I've a data template for ListBoxItem which contains of few buttons, and few custom controls like Grid or Chart. Each button is bound to an appropriate co开发者_JS百科mmand handler, SelectedIndex property of a ListView control is bound to ViewModel's propery as well.
The problem: in command handlers (which are bound to buttons) I can't resolve currently selected item/index because it is not changing whilst clicking on a button or an other control within a ListBox item, but when I clicking on ListBoxItem area itself - SelectedIndex is changing.
Question is how to trigger SelectedIndex to be changed whilst clicking on any control within ListBoxItem?
Add this to your ListBox.Resources
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
EDIT
The previous method only makes the ListBoxItem selected for as long as it has keyboard focus. If you move focus out of the ListBoxItem, it becomes unselected again.
Here's another simple way to select a ListBox item when the keyboard focus moves within the item, and it stays selected when focus is moved out of the ListBoxItem
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
</Style>
And in the Code Behind
protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
{
ListBoxItem item = (ListBoxItem)sender;
item.IsSelected = true;
}
Can you not set the item as the selected item in the bound command? If your list Item viewmodel has access to whatever the ListBoxes viewmodel is, you should be able to set the property that you have bound there.
Private Sub ButtonClickExecute()
ListBoxVM.SelectedItem = Me.MyModelItem
End Sub
I have done this on occasion and it has worked quite well, so long as the SelectedItem bound property is read/write, PropertyChangeNotification is working.
If your ViewModel and Model don't support this, let me know and we can try another way.
Whoops, did not immediately notice the C# tag. That should be:
ListBoxVM.selectedItem = this.myModelItem;
XAML-only solution:
You can adapt the ItemContainerStyle and listen on the trigger is the mousefocus is inside of the Item. It works for all kind of child elements (in this example just mouse focus, which shouldnt be a problem, as the keyboard selects the item automatically too...)
example:
<Grid>
<Grid.Resources>
<x:Array x:Key="strings" Type="sys:String" >
<sys:String>test</sys:String>
<sys:String>test</sys:String>
<sys:String>test</sys:String>
<sys:String>test</sys:String>
</x:Array>
<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource strings}}" ItemContainerStyle="{StaticResource ContainerStyle}" >
<ListBox.Resources>
<DataTemplate DataType="x:Type ListBoxItem">
<ListBoxItem IsSelected="{Binding IsKeyboardFocusWithin}" />
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
If you are only interested in the item 'underneath' the data template you can use a CommandParameter with a the binding as a argument.
CommandParameter={Binding}
This will pass the current item as a parameter to the command, so no need to track the selected item.
精彩评论