简体   繁体   English

WPF MVVM Light-取消视图模型中的属性更改-RaisePropertyChanged,即使值与以前相同

[英]WPF MVVM Light - Cancel property change in viewmodel - RaisePropertyChanged even if value is same as before

I have a property(in viewmodel) bound to a combobox. 我有一个绑定到组合框的属性(在viewmodel中)。 When the viewmodel property changes, it uses the Messenger to tell another viewmodel about this. 当viewmodel属性更改时,它使用Messenger将此情况告知另一个viewmodel。

This other viewmodel then decides if this is ok, if not i want to cancel and send the old value back up to the view. 然后,另一个视图模型决定是否可以,否则,我想取消并将旧值发送回视图。

I guess i can do this by setting the value to the new one first, then set it back. 我想我可以通过将值首先设置为新值,然后再将其设置回去来做到这一点。 But is there a more elegant soulution? 但是,有没有更优雅的解决方案?

Failing code 失败的代码

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();
    }
}

I managed to fix it with this workaround, but i dont like it :( At first glance it seams to be incorrect, but the call stack makes it this way 我设法用这种解决方法来解决它,但是我不喜欢它:(乍看之下它似乎是不正确的,但是调用栈就是这样的

Using oneway binding on SelectedItem and Interaction Trigger with command 在SelectedItem上使用单向绑定,并使用命令进行交互触发

Hacky workaround 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));
    }
}

Kind Regards 亲切的问候

You need to use Dispatcher.BeginInvoke to perform the reversal of the user action. 您需要使用Dispatcher.BeginInvoke来执行用户操作的撤消。

Basically, when the user selects the item on the combo box, any attempt to reject that value will be ignored by WPF. 基本上,当用户选择组合框上的项目时,WPF将忽略任何拒绝该值的尝试。 However, if you wait until all the code relating to data binding finishes, then you can basically start a new binding activity. 但是,如果您等到所有与数据绑定有关的代码完成,则可以基本上开始新的绑定活动。 This is what Dispatcher.BeginInvoke does. 这就是Dispatcher.BeginInvoke所做的。 It allows your reset of the selected item to be postponed until the binding engine has finished its work. 它允许您将所选项目的重置推迟到绑定引擎完成其工作之前。

Example: 例:

public class MainViewModel : ViewModelBase
{
    private string _selectedItem;

    public List<string> 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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM