假设左边的用户列表代码如下:
<ListBox Grid.Row="1" Grid.Column="0" Grid.RowSpan="10" Margin="5,2"
ItemsSource="{Binding Path=Staffs}"
SelectedItem="{Binding Path=SelectedStaff, Mode=TwoWay}"
IsEnabled="{Binding Path=IsEnabled}">
......
看起来很不错,但是实际上,如果选择了其中一个用户,修改用户名,然后直接选择另一个用户,此时被修改的用户名其实并没有修改成功。
因为其中牵涉到了代码执行顺序的问题。那么怎么办呢?很简单,不要直接绑定 SelectedItem,而使用 Trigger 绑定 SelectionChanged 事件。
<UserControl
......
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL5"
......
>
......
<ListBox Grid.Row="1" Grid.Column="0" Grid.RowSpan="10" Margin="5,2"
ItemsSource="{Binding Path=Staffs}"
SelectedItem="{Binding Path=SelectedStaff}"
IsEnabled="{Binding Path=IsEnabled}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectedStaffChangeCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
然后 VM 那边这样写
#region SelectedStaffChangeCommand
private RelayCommand<SelectionChangedEventArgs> _selectedStaffCmd = null;
/// <summary>
/// 获取 SelectedStaffChange 命令。
/// </summary>
public ICommand SelectedStaffChangeCommand
{
get
{
if (_selectedStaffCmd == null)
{
_selectedStaffCmd = new RelayCommand<SelectionChangedEventArgs>(OnInvokeSelectedStaffChangeCommand);
}
return _selectedStaffCmd;
}
}
private void OnInvokeSelectedStaffChangeCommand(SelectionChangedEventArgs e)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.RunWorkerCompleted += (s, a) =>
{
this.SelectedStaff = e.AddedItems.Cast<Staff>().FirstOrDefault();
};
bgw.RunWorkerAsync();
}
#endregion
我们使用 BackgroundWorker 把修改 SelectedStaff 的时间拖后,这样就好了。
并且当我们在 VM 中对 SelectedStaff 进行改变时,前端会随即响应。
不建议直接在 SelectedStaff 属性中使用 BackgroundWorker 来将 SelectedStaff 值的改变拖后。仔细想想为什么~。~