当我的设置也发生变化时,如何更改MVVM属性?

时间:2016-06-09 12:47:07

标签: c# wpf mvvm

我有像这样的ViewModel

Public class AboutPageViewModel
{
  public AboutPageViewModel()
  {
    AppName = Settings.MyAppName;
  }

  private string _appName;
  public string AppName
  {
    get{return _appName;}
    set{_appName = value; RaisePropertyChanged("AppName");}
  }
}

现在是静态类

public static class Settings
{
   public static string MyAppName{get;set;} = "LOL"
}

每次更改MyAppName时如何通知ViewModel,并将其更新为Binded UI?

谢谢!

3 个答案:

答案 0 :(得分:4)

正如您在问题中定义的那样,Settings不是一个静态类(啊,我在评论中看到这是一个错字,并且它在您的代码中是静态的)。它不应该是静态的。关于静态类的PropertyChanged通知在理论上是可行的,但它不值得花时间去处理,并且没有必要打扰。

Settings实施INotifyPropertyChanged,就像您的viewmodel一样。当MyAppName更改时,Settings应该引发PropertyChanged,就像AboutPageViewModel在其自己的AppName属性发生变化时所做的那样。

现在给Settings一个名为Instance的静态属性:

public static Settings Instance { get; private set; }

static Settings()
{
    Instance = new Settings();
}

并在PropertyChanged中处理AboutPageViewModel事件:

public AboutPageViewModel()
{
    AppName = Settings.Instance.MyAppName;
    Settings.Instance.PropertyChanged += (s,e) =>
    {
        //  If you're in C#6:
        //if (e.PropertyName == nameof(Settings.MyAppName))
        if (e.PropertyName == "MyAppName")
        {
            AppName = Settings.Instance.MyAppName;
        }
    }
}

选项编号二

可以说是一个更好的选择;我不止一次这样做过。

在评论中,@ MikeEason非常清楚这也可以通过*Changed这样的自定义MyAppNameChanged事件来完成,这有两个优点:它可以让你回到静态类,它允许您跳过对属性名称的检查,这是额外的代码,也是"magic string"。与INotifyPropertyChanged合作我们对魔法弦的危险有点麻木,但实际上它们很糟糕。如果你在C#6中,你可以并且绝对应该使用nameof()运算符,但我们并不是所有人都在C#6中。我在工作中的主要责任是今年夏天我们希望迁移到C#6的应用程序。

public static event EventHandler<String> MyAppNameChanged;

private static String _myAppName = "";
public static String MyAppName {
    get { return _myAppName; }
    set {
        if (_myAppName != value)
        {
            _myAppName = value;
            //  C#6 again. Note (thanks OP!) you can't pass this for sender 
            //  in a static property. 
            MyAppNameChanged?.Invoke(null, value);
        }
    }
}

这样做的缺点是,这个类称为Settings,而不是Setting。也许它有十几个属性在这里和那里发生变化。这可能是一个真正的不同属性改变事件的丛林(&#34;那么什么?&#34;你可能会问 - 你可能有一点意见)。我倾向于坚持PropertyChanged如果有一大堆它们,并且如果该类只有一个或两个重要属性需要关注,则添加一个事件。在我看来,这两种方式都很烦人;尝试两者,你最终会选择偏好。

答案 1 :(得分:2)

如果你已经在某个地方拥有它,你不需要在ViewModel中存储值(我假设你不会在ViewModel本身改变它):

public class AboutPageViewModel : INotifyPropertyChanged
{
    public string AppName => Settings.MyAppName;
}

至于View以了解此属性何时更改,您需要做两件事:1)应该有一种方法在值更改时通知ViewModel 2)上升PropertyChanged(nameof(AppName))(注意INotifyPropertyChanged)。

有几种可能性:

  1. Settings应该在MyAppName值更改时发生事件,ViewModel订阅并升起PropertyChanged;
  2. 存储初始值,定期检查值是否更改;
  3. 使用另一种实现INotifyPropertyChanged的类型,然后绑定到该类型属性,如果该类型上升PropertyChanged,这将自动更新视图。

答案 2 :(得分:0)

您必须在Settings class上实现INotifyPropertyChanged接口!

然后使用相同的代码:

  private string _myAppName;
  public string MyAppName
  {
    get{return _myAppName;}
    set{_appName = value; RaisePropertyChanged("MyAppName");}
  }