Handling click event inside LongListSelector - silverlight

I have the following XAML:
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" >
<TextBlock Text="{Binding Path=Name, Mode=TwoWay}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" />
<TextBlock Text="{Binding Path=State.Summary, Mode=TwoWay}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
<toolkit:ToggleSwitch x:Name="stateToggle" x:Uid="{Binding Path=Id, Mode=TwoWay}" IsChecked="{Binding Path=State.Current, Mode=TwoWay}" Click="stateToggle_Click_1" ></toolkit:ToggleSwitch>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
I am trying to achieve the following:
1) Take an action on toggle switch click (handle an event)
2) Take an action when an item from the list is tapped i.e. outside the borders of the toggle switch.
I have tried SelectionChanged and ToggleSwitch Click but that way I still invoke both events when the toggle switch is clicked.
Any ideas?

If SelectionChanged works for use case 2, then you are basically there.
You should set the MouseEventArgs Handled property to true in your ToggleSwitch Click handler. That way the selection should not be changed (because the listitem has not been clicked) and only the click event you want should be raised.

Related

Click on buttons in DataTemplate - WP8

I'm using this datatemplate for my app , which used context menu from WP8 toolkit . So each item in this datatemplate has a button (to open context menu) and context menu also has click events
So when I use this datatemplate for my LongListSelectors in app, how can I call these click events?
<DataTemplate>
<Grid>
<Grid.ColumnDefenitions>.........
......
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Grid.Column="0"/>
<TextBlock Text="{Binding Artist}" TextWrapping="Wrap" Grid.Column="1"/>
<Button Click="openContext" Grid.Column="2"/>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsZoomEnabled="false">
<toolkit:MenuItem Header="Download"
Click="context_download" />
<toolkit:MenuItem Header="Add to later"
Click="context_later" />
.......
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBlock>
</StackPanel>
</DataTemplate>
Context menu should be declared inside the element and not separately. Declare your context menu inside your button like below code and remove the click event in your button.
Whenever you declare context menu in your button, it works automatically (opens context menu) without any click event.
<Button Content="ContextMenu">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsZoomEnabled="False">
<toolkit:MenuItem Header="Download" Click="context_download"/>
<toolkit:MenuItem Header="Add to later" Click="context_later"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</Button>

stop Text block (not Text box) from tabbing sequence

How to exclude TextBlock from tabbing sequence in SILVERLIGHT Grid XAML. I know for TextBox, we use IsTabStop false OR TabIndex -1, but same property is not avaiable for TextBlock
I have 4 controls, 1 and 4 are TextBox (editable) and 2 and 3 are TextBlock (non editable). When I tab, all the 4 are included in the tabbing sequence.
I want to exclude 2,3 (Textblocks) from tabbing. Means, If I tab from TextBox 1, focus should move directly to TextBox 4. please help.
Loaded="UserControl_Loaded">
<DataTemplate x:Key="CellEditClientAllocations" >
<TextBox Text="{Binding ClientAllocations, Mode=TwoWay}"
Style="{StaticResource GridCellTextBoxStyle}"
x:Name="tbxClientAllocations"
Loaded="TextBox_Loaded"
TextChanged="tbxClientAllocations_TextChanged"
KeyDown="tbxClientAllocations_KeyDown"
LostFocus="tbxClientAllocations_LostFocus"
GotFocus="tbxClientAllocations_GotFocus"/>
</DataTemplate>
<DataTemplate x:Key="CellAccountId">
<TextBlock Text="{Binding AccountId, Converter={StaticResource anc}}" Style="{StaticResource GridCellTextBlockStyle}" /> </DataTemplate>
<DataTemplate x:Key="CellEditAccountId">
<TextBox Text="{Binding AccountId, Converter={StaticResource anc}, Mode=TwoWay}" x:Name="tbxAccountId" LostFocus="TbxAccountIdLostFocus" TextChanged="TbxAccountIdTextChanged" GotFocus="tbxAccountId_GotFocus"/>
</DataTemplate><DataTemplate x:Key="CellAccountName"> <StackPanel>
<TextBlock VerticalAlignment="Center" Text="{Binding AccountName, Mode=TwoWay}" Foreground="{Binding IsAccountValid, Converter={StaticResource cc}}" kStyle="{StaticResource GridCellTextBlockStyle}" Name="Account" MouseRightButtonUp="" > </TextBlock> </StackPanel> </DataTemplate>
<DataTemplate x:Key="CellLotInstructions"> <StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LotInstructions}" Style="{StaticResource GridCellTextBlockStyle}"/>
<HyperlinkButton Content="Edit" Style="{StaticResource HyperlinkButtonStyleUnderline}" IsEnabled="{Binding LotInstructionsEnabled}" Name="Lotinstructons" HorizontalContentAlignment="Center" MouseLeftButtonDown="LotinstructonsMouseLeftButtonDown" VerticalContentAlignment="Center" Click="ViewSpecifyLots_Click" Visibility="{Binding LotInstructionsEdit}" /> </StackPanel> </DataTemplate>
Try setting attached property KeyboardNavigation.TabNavigation to None.
<TextBlock KeyboardNavigation.TabNavigation="None"/>
Set Focusable="False" for the textblock
I think you may need to work on the DataGrid Column rather than the Cell content (your TextBlock) it is the Cell that is Focussed not the TextBlock.
You could assign an event handler to the CellEnter Event (accessible from the definition of the original column) and then set the DataGrids selected cell selected property to false. Not the neatest solution but it should work.
Alternatively you could create a behaviour to do this....
Hope this helps!

Getting current Object in Control template

<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel>
<StackPanel Margin="0,0,28,0" Orientation="Horizontal" Visibility="{Binding IsEditable,Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Foreground="Gray" Text="{Binding DateCreated,Converter={StaticResource DateTimeConverter}}" FontFamily="/Assets/Fonts/Berthold Akzidenz Grotesk BE Regular.ttf" FontSize="16"/>
<TextBlock Text=":" Foreground="Gray"/>
<TextBlock Width="20"/>
<TextBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0" Name="TrainerNoteText" Text="{Binding TrainerNote}" FontFamily="/Assets/Fonts/Berthold Akzidenz Grotesk BE Regular.ttf" Foreground="Black" FontSize="16" TextWrapping="Wrap" KeyUp="EditTrainerNote" Width="400"/>
</StackPanel>
</StackPanel>
</ControlTemplate>
The above control template is in a listview. The textbox inside is editable. So when user presses the enter key, I need to get the current object associated with that. How to do this?
You can listen to KeyDown RoutedEvent at ListView level.
http://msdn.microsoft.com/en-us/library/system.windows.input.keyboard.keydown.aspx
Its an attached event and its handler can be placed anywhere in VisualTree.
Here is an example:
<StackPanel TextBox.KeyDown="OnKeyDownHandler">
<TextBox Width="300" Height="20"/>
</StackPanel>
And this is the handler:
public void OnKeyDownHandler(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)
{
TextBox tbx = (TextBox)sender;
tbx.....
}
}
You know, you really should define what your items look like in a DataTemplate defined in the ListBox.ItemTemplate property and not the ListBoxItem.Template property. Based on the example from the linked page:
<ListBox Width="400" Margin="10" ItemsSource="{Binding YourCollectionProperty}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When Binding a collection property to the ListBox.Items property, all of the UI elements inside the DataTemplate will have access to the properties of the type that is in the collection. In this example, the type that populates the YourCollectionProperty collection has TaskName, Description and Priority properties in it. You can replace these properties with those from the type that is in your collection property.
If you set up your properties to implement the INotifyPropertyChanged interface (or use DependencyProperties then any updates in the UI elements will automatically be updated in the data objects in the view model/code behind. Therefore, there is no need to add KeyDown or KeyUp handlers. For more information, please read the Data Binding Overview page on MSDN.

Strange behavior with CheckBox in DataGridTemplateColumn

I have a SL4 DataGrid with a column containing a checkbox:
<data:DataGridTemplateColumn Header="Check" CanUserSort="False" >
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="CheckRead" Click="CheckRead_Click" IsChecked="{Binding Acknowledged, Mode=TwoWay}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Everything works fine as long as the user clicks directly on the checkbox. If they click anywhere else in the cell, the cell gets selected. But on subsequent clicks on the checkbox - the checkbox changes state but that change is not reflected in the bound object.
If the user clicks on any other cell and then goes back to click the checkbox, it works again.
Why does having the cell selected disable the binding of the checkbox????
I tried the solution proposed of setting horizontal/vertical alignment to stretch but that does not change anything.
Okay, the answer is...
<data:DataGridTemplateColumn Header="Check" CanUserSort="False" >
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Center">
<CheckBox x:Name="CheckRead" Click="CheckRead_Click" IsChecked="{Binding Acknowledged, Mode=TwoWay}" />
</ContentControl>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Wrapping the checkbox in a contentcontrol like this causes the problem to go away!

WPF ListBoxItem selection problem

I have a listbox where the items contain checkboxes:
<ListBox Style="{StaticResource CheckBoxListStyle}" Name="EditListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="Checkbox_Click" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Content="{Binding Path=DisplayText}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem I'm having is that when I click on the checkbox or its content, the parent ListBoxItem does not get selected. If I click on the white space next to the checkbox, the ListBoxItem does get selected.
The behavior that I'm trying to get is to be able to select one or many items in the list and use the spacebar to toggle the checkboxes on and off.
Some more info:
private void Checkbox_Click(object sender, RoutedEventArgs e)
{
CheckBox chkBox = e.OriginalSource as CheckBox;
}
In the code above when I click on a checkbox, e.Handled is false and chkBox.Parent is null.
Kent's answer put me down the right path, here's what I ended up with:
<ListBox Style="{StaticResource CheckBoxListStyle}" Name="EditListBox" PreviewKeyDown="ListBox_PreviewKeyDown">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" />
<TextBlock Text="{Binding DisplayText}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I had to use PreviewKeyDown because by default when you hit the spacebar in a list box, it deselects everything except for the most recently selected item.
To begin with, put the content outside the CheckBox:
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding DisplayText}"/>
</StackPanel>
After that, you will need to ensure that pressing space on a ListBoxItem results in the CheckBox being checked. There are a number of ways of doing this, including a simple event handler on the ListBoxItem. Or you could specify a handler for UIElement.KeyUp or whatever in your DataTemplate:
<CheckBox IsChecked="{Binding IsChecked}" UIElement.KeyUp="..."/>
You can also bind the IsChecked property of the CheckBox and IsSelected property of the ListBoxItem:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding DisplayText}" IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In your use case it would be way simpler to use a ItemsControl instead of a list box. A ItemsControl is similar to a Listbox except that it doesn't contain the automatic selection behaviour. Which means that using it to host a list of what are essentially checkboxes is very simple and you don't have to workaround the ListBox's selection behaviour.
Simply switching to ItemsControl will give you exactly what you need:
<ItemsControl Style="{StaticResource CheckBoxListStyle}" Name="EditListBox">
<ItemsControl .ItemTemplate>
<DataTemplate>
<CheckBox Click="Checkbox_Click" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Content="{Binding Path=DisplayText}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can click on text to check checkboxes (default behavior) and you can use the keyboard too without having to wire up any event handlers.

Resources