WPF中如何在ListBoxItem样式中同时使用Command与Binding?
方法1:通过RelativeSource绑定父级ViewModel的命令
你的ListBox绑定的是字符串集合,每个ListBoxItem的DataContext默认就是集合里的单个字符串,直接修改ListBoxItem的DataContext会覆盖这个值,导致内容无法显示。不用改动DataContext,直接在样式里通过RelativeSource找到父级ListBox的DataContext(即你的ViewModel)来绑定命令:
修改样式里的MouseBinding部分:
<Border.InputBindings> <MouseBinding MouseAction="LeftClick" Command="{Binding DataContext.你的命令名称, RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding}" /> </Border.InputBindings>
这里命令会绑定到ListBox对应的ViewModel,CommandParameter="{Binding}"还能把当前点击的字符串Item传递给命令;TextBlock的{Binding}依然指向当前Item的字符串,完全不影响显示。
方法2:用附加属性封装命令
如果不想依赖RelativeSource的层级关系,可以自定义一个附加属性,把命令挂载到ListBoxItem上:
先编写C#的附加属性代码:
public static class ListBoxItemCommands { public static readonly DependencyProperty ItemClickCommandProperty = DependencyProperty.RegisterAttached( "ItemClickCommand", typeof(ICommand), typeof(ListBoxItemCommands)); public static void SetItemClickCommand(DependencyObject element, ICommand value) { element.SetValue(ItemClickCommandProperty, value); } public static ICommand GetItemClickCommand(DependencyObject element) { return (ICommand)element.GetValue(ItemClickCommandProperty); } }
然后在样式里绑定这个附加属性:
<Border.InputBindings> <MouseBinding MouseAction="LeftClick" Command="{Binding Path=(local:ListBoxItemCommands.ItemClickCommand), RelativeSource={RelativeSource Self}}" CommandParameter="{Binding}" /> </Border.InputBindings>
最后在使用ListBox时,给ItemContainerStyle设置这个附加属性:
<ListBox ItemsSource="{Binding 你的字符串集合}"> <ListBox.ItemContainerStyle> <Style BasedOn="{StaticResource OptionDieStyle}" TargetType="ListBoxItem"> <Setter Property="local:ListBoxItemCommands.ItemClickCommand" Value="{Binding DataContext.你的命令名称, RelativeSource={RelativeSource AncestorType=ListBox}}" /> </Style> </ListBox.ItemContainerStyle> </ListBox>
这种方式更灵活,也不会破坏ListBoxItem原有的DataContext。
方法3:利用ListBox的SelectionChanged转命令
如果只是需要点击Item触发命令,也可以直接在ListBox层面处理,把SelectionChanged事件转成ViewModel里的命令(比如用Prism的InvokeCommandAction,或自行实现类似行为):
<ListBox ItemsSource="{Binding 你的字符串集合}" SelectedItem="{Binding 选中的字符串}"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <prism:InvokeCommandAction Command="{Binding 你的命令名称}" CommandParameter="{Binding 选中的字符串}" /> </i:EventTrigger> </i:Interaction.Triggers> </ListBox>
这种方式无需修改ListBoxItem的样式,直接在ListBox上配置,符合MVVM规范,同时不影响Item的正常显示。
内容的提问来源于stack exchange,提问作者Egor Bobrov

