如果你严肃地遵循MVVM并且不想使用任何代码后台,也不喜欢使用
Dispatcher
,那么以下解决方案适合我,并且比这里提供的大多数解决方案更加优雅。它基于这样一个概念,在代码后台中,您可以使用
SelectionChanged
事件停止选择。既然如此,为什么不为其创建一种行为,并将命令与
SelectionChanged
事件相关联呢?在视图模型中,您可以轻松记住先前选择的索引和当前选择的索引。诀窍在于在
SelectedIndex
上绑定到您的视图模型,并且每当选择更改时,只需让它发生变化即可。但是,在选择实际更改之后立即触发
SelectionChanged
事件,该事件现在通过命令通知到您的视图模型。因为您记得先前选择的索引,所以您可以验证它,如果不正确,则将选定的索引移回原始值。行为的代码如下:
public class ListBoxSelectionChangedBehavior : Behavior<ListBox>
{
public static readonly DependencyProperty CommandProperty
= DependencyProperty.Register("Command",
typeof(ICommand),
typeof(ListBoxSelectionChangedBehavior),
new PropertyMetadata());
public static DependencyProperty CommandParameterProperty
= DependencyProperty.Register("CommandParameter",
typeof(object),
typeof(ListBoxSelectionChangedBehavior),
new PropertyMetadata(null));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
protected override void OnAttached()
{
AssociatedObject.SelectionChanged += ListBoxOnSelectionChanged;
}
protected override void OnDetaching()
{
AssociatedObject.SelectionChanged -= ListBoxOnSelectionChanged;
}
private void ListBoxOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
Command.Execute(CommandParameter);
}
}
在XAML中使用它:
<ListBox x:Name="ListBox"
Margin="2,0,2,2"
ItemsSource="{Binding Taken}"
ItemContainerStyle="{StaticResource ContainerStyle}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"
SelectedIndex="{Binding SelectedTaskIndex, Mode=TwoWay}">
<i:Interaction.Behaviors>
<b:ListBoxSelectionChangedBehavior Command="{Binding SelectionChangedCommand}"/>
</i:Interaction.Behaviors>
</ListBox>
适用于视图模型的代码如下所示:
public int SelectedTaskIndex
{
get { return _SelectedTaskIndex; }
set { SetProperty(ref _SelectedTaskIndex, value); }
}
private void SelectionChanged()
{
if (_OldSelectedTaskIndex >= 0 && _SelectedTaskIndex != _OldSelectedTaskIndex)
{
if (Taken[_OldSelectedTaskIndex].IsDirty)
{
SelectedTaskIndex = _OldSelectedTaskIndex;
}
}
else
{
_OldSelectedTaskIndex = _SelectedTaskIndex;
}
}
public RelayCommand SelectionChangedCommand { get; private set; }
在视图模型的构造函数中:
SelectionChangedCommand = new RelayCommand(SelectionChanged)
RelayCommand
是MVVM Light的一部分。如果你不知道它,请搜索一下谷歌。
你需要参考。
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
因此,您需要引用 System.Windows.Interactivity
。