How do I trap the button clicked event in my ViewModel for an ItemsSource Canvas collection? - binding

I have a XAML view shown below where I bind to an ObservableCollection of Buttons in my ViewModel using an ItemsSource on a Canvas. What I need to do now is when one of the buttons is clicked, set a property in my ViewModel to store which button was clicked please.
A Sample of my Canvas Output
<Grid.DataContext>
<local:MyViewModel />
</Grid.DataContext>
<Grid.Resources>
<Style TargetType="tgr:AnimatedButton" >
<Setter Property="ButtonBrush" Value="Red" />
<Setter Property="Canvas.Left" Value="{Binding Position.X,RelativeSource={RelativeSource Self}}"/>
<Setter Property="Canvas.Top" Value="{Binding Position.Y,RelativeSource={RelativeSource Self}}"/>
</Style>
</Grid.Resources>
<ItemsControl
ItemsSource="{Binding FilteredLocations
,NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas ClipToBounds="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>

I've worked it out, I just add a handler in my ViewModel and that solves it.

Related

Xamarin.Forms (iOS Project): ListView Separator shows in all screen

I have a ListView with the default SeparatorVisibility. My Android project shows the Separator if there are elements in the ItemsSource and stops showing it below the last element. It's the result I want for my iOS project.
However, in my iOS project the screen is full of Separators no matter how many elements I have, even if I have no elements or only one, the Separators still being there.
Could someone give me a reason and how to fix it please? Thanks.
I think you can take a look to this post
these are some tips
First disable the default separator, this is done by adding following property to the ListView XAML
SeparatorColor="Transparent"
After this, wrap the complete ViewCell content inside a double StackLayout! I know this sounds like overkill but this way you’ll not run into any BoxView issues regarding margins inside the ViewCell… or other stuff.
The first StackLayout should have a BackgroundColor set to the colour you want your separator to be, the second StackLayout should have the same BackgroundColor as the rest of the container it is in… in our example the page and that is set to white. Be sure to also add a Margin to the bottom of this second StackLayout because that will represent the thickness of our separator!
I think you can play with this "Margin"... when your data is empty, remove the margin so you should not have the separator
<ListView x:Name="SeparatorListView"
SeparatorColor="Transparent"
ItemsSource="{Binding Persons}"
Margin="0,20,0,0"
RowHeight="60"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
BackgroundColor="White"
Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell IsEnabled="false">
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
BackgroundColor="Black">
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
BackgroundColor="White"
Margin="0,0,0,0.4">
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand" Spacing="0">
<Label Text="{Binding FullName}" TextColor="Maroon" VerticalOptions="CenterAndExpand" Margin="20,0,20,0" />
<Label Text="{Binding Profession}" TextColor="Maroon" VerticalOptions="CenterAndExpand" Margin="20,0,20,0" />
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
With that in place, you’ll get the same visual result as the preview image at the top right of this blog post.
As a bonus, you could omit one of the StackLayouts IF your page has a background color other than white. Because if this is the case, you can use that color as the separator color by playing with transparency inside the ListView.
Example of this, note will only work if the page itself also has a BackgroundColor set to Olive!
<ListView x:Name="SeparatorListView"
SeparatorColor="Transparent"
ItemsSource="{Binding Persons}"
Margin="0,20,0,0"
RowHeight="60"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
BackgroundColor="Olive"
Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell IsEnabled="false">
<StackLayout BackgroundColor="#f4eac3"
Padding="0,5,0,5"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand"
Spacing="0"
Margin="20,0,20,0">
<Label Text="{Binding FullName}" TextColor="Maroon" VerticalOptions="CenterAndExpand" />
<Label Text="{Binding Profession}" TextColor="Maroon" VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer (typeof(ListView), typeof(CustomListViewRenderer))]
namespace yourNamespace
{
public class CustomListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var listView = Control as UITableView;
listView.SeparatorInset = UIEdgeInsets.Zero;
}
}
}
}
That is due to the implementation of the ListView on the iOS side. It renders as a UITableView which (in the case of the ListView) always takes the entire height and shows empty items. To change this type of behavior you could set the ListView height dynamically in the code-behind for your page. Another option is taking a look at Xamarin's Evolve sample app which has a few pages where it uses a CardView combined with a ListView to make it appear as it does on Android.

WPF: Customized control focus management

I was tying to set focus on a TextBox used to build a customized "Numeric Up Down" control.
This is the custom "Numeric Up Down"
<Style x:Key="SpinButton" TargetType="Slider" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Border Grid.RowSpan="3" BorderThickness="1,1,1,1" BorderBrush="WhiteSmoke">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=".5*"/>
<RowDefinition Height=".5*"/>
</Grid.RowDefinitions>
<TextBox Name="textBoxNumericUpDown" Grid.RowSpan="3" Margin="2,0,0,0" Text="{Binding Value,Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" FontSize="20" VerticalAlignment="Center" Background=" {x:Null}" Foreground="White" BorderThickness="0" CaretBrush="White" IsTabStop="True"/>
<RepeatButton Grid.Column="1" Grid.Row="0" Margin="0,0,-5,0" Command="Slider.IncreaseLarge" Style="{StaticResource TimeRepeatButtonStyle}" Content="+" Background="{x:Null}" BorderBrush="White" Foreground="White" FontSize="18" Cursor="Hand" Width="44" Height="44" IsTabStop="False"/>
<RepeatButton Grid.Column="1" Grid.Row="1" Command="Slider.DecreaseLarge" Margin="0,1,-5,0" Style="{StaticResource TimeRepeatButtonStyle}" Content="-" Background="{x:Null}" BorderBrush="White" Foreground="White" FontSize="18" Cursor="Hand" Width="44" Height="44" IsTabStop="False"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage
<Slider PreviewTextInput="textBoxTimeMinute_PreviewTextInput" Name="textBoxTimeMinute" Width="100" Style="{StaticResource SpinButton}" Maximum="999" Margin="8" HorizontalAlignment="Left" Minimum="0" IsTabStop="True" TabIndex="0"/>
<Label Grid.Column="1" Content=":" VerticalAlignment="Center" IsTabStop="False"/>
<Slider PreviewTextInput="textBoxTimeSecond_PreviewTextInput" Grid.Column="2" Name="textBoxTimeSecond" Width="100" Style="{StaticResource SpinButton}" Maximum="60" Margin="8" HorizontalAlignment="Left" Minimum="-1" IsTabStop="True" TabIndex="1"/>
Wanted result (Automatic focus on the first textbox if no number inside)
Wanted result (Automatic focus on the first textbox if number inside, number is selected)
I tried different ways to make it select the correct Control, but it always selects the outer layer. In my case The Grid/Border.
Only after I press TAB I can have it select the correct TextBox Control.
Is there any way in WPF I can achieve the focus on textbox without pressing TAB?
Solved:
If you want to focus a TextBox inside a ControlTemplate you have to set up a trigger on the "IsFocused" property.
When it becomes true then you have to set the FocusManager.FocusedElement field to the name of the TextBox (or other control) you want to focus.
Below is the code I used to achieve this:
<ControlTemplate TargetType="Slider">
<TextBox x:Name="TextBoxToFocus"/> //The textbox(or any other element) I want to set focus to. It is very important to have it named, otherwise I won't know which control to focus.
<ControlTemplate.Triggers> //The trigger
<Trigger Property = "IsFocused" Value = "True" /> //The property the trigger is watching
<Setter TargetName="TextBoxToFocus" Property="FocusManager.FocusedElement" Value="{Binding ElementName=NumericUpDown}"/> //Setter when the trigger executes
</Trigger>
</ControlTelmplate.Triggers>

WP8 WrapPanel ItemsControl not showing all items

I'm trying to create a scrollable area to display controls using the XAML code below. My problem is that I only see one item displayed when the items are rendered. I'm using an ObservableCollection for the data.
I've attached to the CollectionChanged event on the collection and definitely see multiple items being added but the view always displays only one item.
If I manually place HubTiles inside the WrapPanel (not databound) the tiles show up correctly. Also I tried replacing the hub tile with a button control and I do see multiple buttons, so I'm wondering if perhaps there is some issue with the HubTile control.
Here's my XAML:
<Grid x:Name="dataGrid" Grid.Row="1">
<ScrollViewer x:Name="myPanel" HorizontalAlignment="Stretch" Width="Auto" Margin="0" >
<toolkit:WrapPanel MaxWidth="{Binding ActualWidth, ElementName=myPanel, Mode=OneWay}" Margin="0" HorizontalAlignment="Center" ItemHeight="230" ItemWidth="230">
<ItemsControl x:Name="images">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<toolkit:HubTile
Style="{Binding Source={StaticResource media}}"
Message="{Binding Data.Caption}"
Source="{Binding Data.Source}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</toolkit:WrapPanel>
</ScrollViewer>
</Grid>
Difficult to say without more information,
but the first thing I noticed is that you have a WrapPanel in a ScrollViewer,
and that WrapPanel contains an ItemsControl, with a WrapPanel as ItemsPanel.
The "inner" WrapPanel doesn't have an ItemWidth or ItemHeight. Is there any reason you have two WrapPanel's?

Listbox of buttons and relative source

I have a listbox bound to a view model property called Choices. Each choice has a label and an index. I need to bind the buttons in the list to a command on the same view model. So far Ive figured out this much:
<ListBox Grid.Row="1" ItemsSource="{Binding Choices}" SelectedIndex="{Binding SelectedChoice, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Margin="1">
<Button Content="{Binding Caption}" Height="24" HorizontalAlignment="Stretch"
Command="{Binding RelativeSource={RelativeSource ???},
Path=SelectChoice}" CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I cant figure out what RelativeSource to use for the command and I'm not sure the CommandParameter is correct.
This seems a really simple thing to do but it's obviously too simple for my poor old brain. Can anyone help please?
Thanks
Sorted:
<ItemsControl Grid.Row="1" ItemsSource="{Binding Choices}" >
<ItemsControl.ItemsPanel >
<ItemsPanelTemplate >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Caption}" Height="24" HorizontalAlignment="Stretch" Margin="0,0,4,0"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.SelectChoice}"
CommandParameter="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

How do I make a Silverlight popup with a TextBox fill its parent?

I have a popup within a user control. The popup uses a TextBox to show a textual preview of data produced by the control.
How do I make the popup size itself to the user control it's inside of? With code as shown below, I find that the text box is sized according to its content, and the popup is sized according to the textbox.
It works fine if I use fixed sizes in my row and column definitions, but I would like to popup to resize itself to match the user control (which in turn matches the browser).
<UserControl
<!-- usual stuff here -->
>
<Grid>
<!-- layout for the user control here -->
<!-- and after that my popup: -->
<Popup Name="MyPopup">
<Border BorderBrush="Black" BorderThickness="2" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="22"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="Preview:" Margin="5" ></TextBlock>
<TextBox
Grid.Row="1"
Name="MyTextBox"
IsReadOnly="True"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
TextWrapping="Wrap"
Margin="5"
>
</TextBox>
</Grid>
</Border>
</Popup>
</Grid></UserControl>
The C# code to do this would be something like:
textBox1.Width = UserControl.Width;
textBox1.Height = UserControl.Height;
textBox1.Margin = UserControl.Margin;
The key here is resetting the margin. I know this works in WPF to, say, fill a Window with a TextBox. Give it a try, see if it works.

Resources