代码改变世界

MVVM Light 使用心得之 ListBox.SelectedItem

2012-03-07 15:36  软件猫  阅读(1710)  评论(0编辑  收藏  举报

如图:

假设左边的用户列表代码如下:

            <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 值的改变拖后。仔细想想为什么~。~