【问题标题】:MVVM binding many propertiesMVVM 绑定很多属性
【发布时间】:2017-11-10 17:32:22
【问题描述】:

有没有更简单的方法来绑定许多属性?

如果你有一个 Person 类,它的属性有:姓氏、名字、生日、性别、头衔……

现在我对 ViewModel 上的每个属性都执行此操作:

 public string _LastName;
 public string LastName
 {
    get { return _LastName; }
    set { _LastName = value;
          RaisePropertyChanged("LastName"); }
 } 

在 XAML 页面上这个绑定:

 <TextBlock Text="{Binding FirstName}" />

如果 Person 对象有 20 个属性,现在图像.. 所以我的问题是我能以更简单的方式做到这一点吗?

【问题讨论】:

标签: c# wpf xaml mvvm binding


【解决方案1】:

如果您确实打算在运行时动态更新属性,则只需从数据绑定属性的设置器中引发 PropertyChanged 事件。否则,您可以使用自动实现的属性而无需任何自定义逻辑:

public FirstName { get; set; }

还有一个名为 Fody 的 NuGet 包,它可以自动为您将简单的公共属性转换为完整的 INotifyPropertyChanged 实现:https://github.com/Fody/PropertyChanged

【讨论】:

  • 谢谢我明天去看看!
【解决方案2】:

如果您使用第三方 MVVM 框架,它也可能有一个代码 sn-p 来使用 INotifyPropertyChanged 创建属性。

如果你使用 Catel,你可以在这里下载模板和 sn-ps: http://catelproject.com/downloads/general-files/

以下是 Caliburn.Micro 的实现: https://github.com/winterdouglas/propc

【讨论】:

    【解决方案3】:

    最简单的解决方案是使用免费的DevExpress MVVM Framework 提供的POCO mechanism。 POCO 将自动实现 INotifyPropertyChanged 并为您的视图模型中的所有 public virtual 属性引发 PropertyChanged 事件。

    当您使用 ViewModelSource 类来创建您的视图模型时,所有的魔法都会发生。您可以在 XAML 中创建视图模型:

    <UserControl ...
        DataContext="{dxmvvm:ViewModelSource Type=local:MyViewModel}"> 
    

    或者在代码隐藏中:

    this.DataContext = ViewModelSource.Create(() => new MyViewModel());
    

    【讨论】:

      【解决方案4】:

      前提

      在默认的 MVVM 场景中,您的 ViewModel没有每个属性上发出通知

      典型情况:您从数据库中获取一些Person,将它们显示在视图上,通过TextBoxes 和其他控件对其进行修改,然后单击“保存”将它们重新发送到数据库。您可以通过在每次调用数据库时在视图上设置DataContext 来做到这一点。此操作会引发控件和每个子控件的绑定属性的第一次更新,因此 ViewModel 绑定属性的所有 getter 都会被调用一次,并且 View 会使用 ViewModel 的值填充。当您在 View 上修改某些内容时,该绑定会将修改带到相应的 ViewModel 的属性(甚至是简单的普通 get-set 属性)。

      在这种情况下,您可以使用以下内容:

      public class Person
      {
          public string Name { get; set; }
          public string Surname { get; set; }
          //and so on...
      }
      

      仅当 View 必须侦听某些属性的更改时,您才需要为 ViewModel 的属性发出通知。例如,此功能:当且仅当Person 上的Name 不为空时,才会启用Button“保存”。在这里,显然Button 必须能够看到Name 属性何时发生变化,因此属性设置器必须引发PropertyChanged 事件。


      一种可能的实现方式:

      使用它作为 ViewModel 的基类:

      protected abstract BaseViewModel : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler PropertyChanged;
      
          public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
          {
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
          }
      
          protected void SetAndNotifyIfChanged<T>(
              ref T field, T value, [CallerMemberName] string propertyName = null)
          {
              if (!EqualityComparer<T>.Default.Equals(field, value))
              {
                  field = value;
                  NotifyPropertyChanged(propertyName);
              }
          }
      }
      

      在派生类中,您可以像这样编写每个 get-set 属性:

      class MyViewModel : BaseViewModel
      {
          public string MyProp
          {
              get { return _MyProp; }
              set { SetAndNotifyIfChanged(ref _MyProp, value); }
          }
          private string _MyProp;
      }
      

      类型T和参数propertyName是自动推断出来的。

      这是您可以编写的最短的代码,与普通的完整属性没有太大区别:

          public string NormalProp
          {
              get { return _ NormalProp; }
              set { _NormalProp = value; }
          }
          private string _MyProp;
      

      如果您不想每次都编写所有这些代码,请使用code snippet

      【讨论】:

        猜你喜欢
        • 2013-06-13
        • 2011-08-23
        • 2020-04-19
        • 2014-05-14
        • 2016-03-28
        • 1970-01-01
        • 1970-01-01
        • 2014-04-10
        • 2011-05-20
        相关资源
        最近更新 更多