【问题标题】:INotifyPropertyChanged and Auto-PropertiesINotifyPropertyChanged 和自动属性
【发布时间】:2011-03-21 19:28:04
【问题描述】:

有没有办法将INotifyPropertyChanged 与自动属性一起使用?也许是一个属性或其他东西,对我来说并不明显。

public string Demo{
    get;set;
}

对我来说,自动属性将是一件非常实用的事情,但几乎总是,如果属性值已更改并且没有机制来执行此操作,我必须引发PropertyChanged-事件,自动属性是无用的为了我。

【问题讨论】:

  • 绝对没有开箱即用的东西。如果需要设置默认值,自动属性也无用。
  • 对于默认值,我在 .NET 4.6 public string MyPropertyName { get;放; } = "我的默认值。";

标签: c# .net vb.net


【解决方案1】:

在 .NET 4.5 和higher it can be made somewhat shorter

private int unitsInStock;
public int UnitsInStock
{
    get { return unitsInStock; }
    set { SetProperty(ref unitsInStock, value);}
}

【讨论】:

  • 我最近一直在研究这个问题,几乎想出了一个相同的解决方案,尽管我不认为通过引用传递成员变量。非常优雅,这是我使用的要点:gist.github.com/SuperEvenSteven/…
【解决方案2】:

您必须自己编写代码。最接近的可能是代码项目上的this implementation,它使用自定义属性和面向方面的方法来提供这种语法:

[NotifyPropertyChanged] 
public class AutoWiredSource
{ 
   public double MyProperty { get; set; } 
}

有人曾在 Microsoft Connect 上提议对 C# 规范进行更改:

class Person : INotifyPropertyChanged
{
    // "notify" is a context keyword, same as "get" and "set"
    public string Name { get; set; notify; }
}

proposal 现已关闭。

【讨论】:

  • 嗯,我的第一个想法是这是个好主意。但我想知道如果实施的话,它的实际效果如何。
  • @Matt - 我也不确定,但是当我在寻找属性示例时,我偶然发现了它并认为我会分享。
  • 我不确定我会怎么想……虽然方便,但我更愿意将库组件保留在语言之外。 using 块是一个明显的例外,但是如果(何时)我们想出一种不同的通知属性更改的方法会发生什么?
  • @Adam - 我怀疑这就是为什么提议的改变就是这样的原因之一。我觉得我自己更喜欢属性机制。
【解决方案3】:

没有执行此操作的内置机制。 PostSharp 之类的东西可能会为你添加类似的东西(或者 Mark Gravell 的 HyperDescriptor,如果你只是对这种数据绑定感兴趣的话)。

【讨论】:

  • 还有 Fody.PropertyChanged github.com/Fody/PropertyChanged (将引发 PropertyChanged 事件的代码注入到实现 INotifyPropertyChanged 的​​类的属性设置器中)这不需要应用任何属性,但也会带走一些你的控制过程。
【解决方案4】:

我首先尝试了其他方法:

这些方法有效,但是我仍然不得不混淆模型中所有属性的访问器方法,或者使用dynamic 对象,这会在编码时杀死你的自动完成。值得一提的是,不幸的是,WinForms 不支持绑定到动态对象。

解决方案

最后我遇到了ReactiveUI.Fody。这是一个使用 Fody 和 ReactiveUI 的简单易用的解决方案。我在我的 WPF 项目中成功使用了它。

它在编译时编入所需的样板代码RaisePropertyChangesObservableAsPropertyHelper

项目依赖

https://github.com/kswoll/ReactiveUI.Fody

我使用 NuGet 在我的项目中安装了以下软件包:

<packages>
  <package id="Fody" version="2.0.7" targetFramework="net452" developmentDependency="true" />
  <package id="reactiveui" version="7.4.0" targetFramework="net452" />
  <package id="ReactiveUI.Fody" version="2.2.11" targetFramework="net452" />
  <package id="reactiveui-core" version="7.4.0" targetFramework="net452" />
  <package id="Rx-Core" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Interfaces" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Linq" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Main" version="2.2.5" targetFramework="net452" />
  <package id="Rx-PlatformServices" version="2.2.5" targetFramework="net452" />
  <package id="Rx-XAML" version="2.2.5" targetFramework="net452" />
  <package id="Splat" version="1.6.0" targetFramework="net452" />
</packages>

福迪设置

您需要在项目的顶层创建一个 FodyWeavers.xml 文件,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <ReactiveUI/>
</Weavers>

用法

您只需将模型类设置为继承 ReactiveObject 并添加 [Reactive] 属性高于您要通知更改的任何属性。

using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace name.domain.some{
    class SomeClass : ReactiveObject {
        [Reactive]
        public string SomeProperty { get; set; }
    }
}

工作完成!重建您的项目并检查 Visual Studio 中的输出窗口。当 Fody 处理带注释的模型类并注入适当的样板代码时,您应该会看到从 Fody 输出的一些行。它应该看起来像这样:

更多信息

更多有用的信息可以在here找到。

【讨论】:

    【解决方案5】:

    INotifyPropertyChanged 和 DependencyProperties 确实让属性变得不那么有趣了。我找到的最好的解决方案是好的 sn-ps。比如Silverlight contrib项目中的那些

    【讨论】:

      【解决方案6】:

      Useful answer by crea7or,最终在我的最新项目中使用它。改进它的一种方法是通过这种方式重写 SetProperty:

      protected bool SetProperty<T>(ref T storage, T value, string[] dependentPropertyNames = null, [CallerMemberName] string propertyName = null)
      {
          if (Equals(storage, value))
          {
              return false;
          }
      
          storage = value;
          this.OnPropertyChanged(propertyName);
      
          if(dependentPropertyNames != null)
          {
              foreach(var dependentPropertyName in dependentPropertyNames)
              {
                  OnPropertyChanged(dependentPropertyName);
              }
          }
      
          return true;
      }
      

      它现在允许传入依赖属性名称,允许视图知道依赖属性值已更改,即使它不是直接设置,而是由于设置了其他属性。

      用法:

      private string firstName;
      public string FirstName
      {
          get { return firstName; }
          set { SetProperty(ref firstName, value, new[] { "FullName" }); }
      }
      
      private string lastName;
      public string LastName
      {
          get { return lastName; }
          set { SetProperty(ref lastName, value, new[] { "FullName" }); }
      }
      
      public string FullName
      {
          get { return $"{FirstName} {LastName}"; }
      }
      

      【讨论】:

      • 我建议使用nameof(FullName) 来帮助重构/转到定义而不是字符串。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 2011-01-15
      • 2011-12-20
      • 2013-02-11
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      相关资源
      最近更新 更多