在MVVM中一次更新2个属性

时间:2014-12-17 09:03:18

标签: c# wpf mvvm inotifypropertychanged

查看Windows Power Options,turn off the display中有两个组合框,一个是Battery,另一个是Plugged in

现在要求是Battery中的值应始终小于Plugged in中的值。

因此,如果Battery最初设置为25分钟,然后Plugged in设置为10分钟,则Battery的值应自动更改为5分钟。 更改一个值可能会影响另一个。

代码是实现INotifyPropertyChanged的简单ViewModel。

public class MyViewModel : INotifyPropertyChanged 
{
    private uint pluggedIn;
    public uint PluggedIn 
    {
        get { return pluggedIn;}
        set 
        {
            if (pluggedIn != value)
            {
                pluggedIn = value;
                OnPropertyChanged("PluggedIn");
            } 
        }
    } 
    public uint Battery{...} //the same implementation
}

我修改了setter以应用规则。

        set 
        {
            if (pluggedIn != value)
            {
                pluggedIn = value;
                OnPropertyChanged("PluggedIn");

                if (Battery >= PluggedIn)
                {
                    Battery = FindTheValueLessThanPluggedIn(); //this can potentially modify the value of PluggedIn from the setter of Battery.
                }
            } 
        }

问题。

你可以看到调用Bettery的setter也可能会影响PluggedIn的价值,如果我有其他要求,我将不得不写一些难以阅读/维护的代码来实现这个看似简单的任务。

问题

我可以先计算两个属性的最终值,我需要一个可以同时更新两个属性的“原子”操作(不会相互影响),并且在完成“原子”操作后,触发{{ 1}}两个属性更新UI的事件。

第二个想法

在发布后阅读我的问题之后,我想我已经回答了我自己的问题 - 设置支持字段而不是调用setter,但是其他更好的方式?

PropertyChanged

enter image description here

2 个答案:

答案 0 :(得分:3)

这有什么问题:

   set 
    {
        if (pluggedIn != value)
        {
            pluggedIn = value;

            if (Battery >= PluggedIn)
            {
                _battery = FindTheValueLessThanPluggedIn();
                OnPropertyChanged("Battery");
            }

            OnPropertyChanged("PluggedIn");
        } 

请注意,永远不会调用电池的设定器。

对单个属性的两个OnPropertyChanged调用就是我如何处理与您类似的所有案例,并且它们运行良好。

或者,我也使用过这种技术:

YourViewModel(){
  PropertyChanged += PropertyChangedHandler;
}

void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "Battery":
            PluggedIn = CalculateNewValueForPluggedIn();
            break;

        case "PluggedIn":
            Battery = CalculateNewValueForBattery();
            break;
    }
}

答案 1 :(得分:0)

我的建议是将OnChange事件绑定到您在ViewModel中实现的“原子”方法。这些方法应计算两个下拉菜单的最终值,然后设置Properties PluggedIn和Battery。因此,您根本不需要修改属性的setter,理论上甚至不需要延迟触发PropertyChanged事件(让Property setter为您执行此操作)。

通过将所有逻辑外包给它自己的方法并保持setter简单,属性不会相互干扰。但请注意,虽然使用掩码时将满足所有限制,但这可以通过在代码中手动设置属性来覆盖您的限制。