WPF MVVM Light-取消视图模型中的属性更改-RaisePropertyChanged,即使值与以前相同 [英] WPF MVVM Light - Cancel property change in viewmodel - RaisePropertyChanged even if value is same as before

查看:528
本文介绍了WPF MVVM Light-取消视图模型中的属性更改-RaisePropertyChanged,即使值与以前相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个绑定到组合框的属性(在viewmodel中). 当viewmodel属性更改时,它使用Messenger将此情况告知另一个viewmodel.

I have a property(in viewmodel) bound to a combobox. When the viewmodel property changes, it uses the Messenger to tell another viewmodel about this.

然后,另一个视图模型确定是否可以,如果不可以,我想取消并将旧值发送回视图.

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?

错误代码

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

在SelectedItem上使用单向绑定,并通过命令使用交互触发器

Using oneway binding on SelectedItem and Interaction Trigger with command

麻烦的解决方法

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来执行用户操作的撤消.

You need to use Dispatcher.BeginInvoke to perform the reversal of the user action.

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

Basically, when the user selects the item on the combo box, any attempt to reject that value will be ignored by 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. It allows your reset of the selected item to be postponed until the binding engine has finished its work.

示例:

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

这篇关于WPF MVVM Light-取消视图模型中的属性更改-RaisePropertyChanged,即使值与以前相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆