WPF MVVM Light – 在viewmodel中取消属性更改 – 即使值与以前相同,也是RaisePropertyChanged

我有一个绑定到combobox的属性(在viewmodel中)。 当viewmodel属性更改时,它使用Messenger来告诉另一个视图模型。

然后,这个其他视图模型决定是否可以,如果不是,我想取消并将旧值发送回视图。

我想我可以先将值设置为新值,然后再将其设置为此值。 但是有更优雅的疗法吗?

失败的代码

public DeckType SelectedDeckType { get { return _selectedDeckType; } set { DeckTypeMessage deckTypeMessage = new DeckTypeMessage(value); Messenger.Default.Send(deckTypeMessage); if (deckTypeMessage.IsCancel) { //Some background magic finds out the value of this property is still the same? //So the combobox does not revert! //I can hack this but is there some way to force this? RaisePropertyChanged(); return; } _selectedDeckType = value; RaisePropertyChanged(); } } 

我设法使用此解决方法修复它,但我不喜欢它:(乍一看它接缝不正确,但调用堆栈使它成为这种方式

使用对SelectedItem的单向绑定和使用命令的Interaction Trigger

Hacky解决方法

 public DeckType SelectedDeckType { get { return _selectedDeckType; } set { _selectedDeckType = value; RaisePropertyChanged(); } } public ICommand SelectedDeckTypeChangedCommand { get; private set; } private void ExecuteSelectedItemChangedCommand(DeckType aDeckType) { try { if (_previousSelectedDeckType == aDeckType) { return; } _previousSelectedDeckType = aDeckType; DeckTypeMessage deckTypeMessage = new DeckTypeMessage(this, aDeckType); Messenger.Default.Send(deckTypeMessage); if (deckTypeMessage.IsCancel) { SelectedDeckType = _selectedDeckType; _previousSelectedDeckType = _selectedDeckType; return; } SelectedDeckType = aDeckType; } catch (Exception ex) { NotifyMediator.NotifiyException(new NotifyMediator.NotifyInformation(NotifyMediator.NotificationLevel.Error, ex)); } } 

亲切的问候

您需要使用Dispatcher.BeginInvoke来执行用户操作的撤消。

基本上,当用户选择combobox上的项目时,WPF将忽略任何拒绝该值的尝试。 但是,如果您等到与数据绑定相关的所有代码完成,那么您基本上可以启动新的绑定活动。 这就是Dispatcher.BeginInvoke所做的事情。 它允许您重置所选项目,直到绑定引擎完成其工作。

例:

 public class MainViewModel : ViewModelBase { private string _selectedItem; public List Items { get; private set; } public string SelectedItem { get { return _selectedItem; } set { if (value == _selectedItem) return; var previousItem = _selectedItem; _selectedItem = value; var isInvalid = value == "Bus"; // replace w/ your messenger code if (isInvalid) { Application.Current.Dispatcher.BeginInvoke( new Action(() => ResetSelectedItem(previousItem)), DispatcherPriority.ContextIdle, null); return; } RaisePropertyChanged(); } } public MainViewModel() { Items = new[] { "Car", "Bus", "Train", "Airplane" }.ToList(); _selectedItem = "Airplane"; } private void ResetSelectedItem(string previousItem) { _selectedItem = previousItem; RaisePropertyChanged(() => SelectedItem); } }