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

别来无恙 提交于 2019-12-23 03:15:17

问题


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?

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

Hacky workaround

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


回答1:


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

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.

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


来源:https://stackoverflow.com/questions/27449797/wpf-mvvm-light-cancel-property-change-in-viewmodel-raisepropertychanged-even

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!