【问题标题】:What is the advantage of using INotifyPropertyChanged vs WinForms-like event handlers?使用 INotifyPropertyChanged 与类似 WinForms 的事件处理程序有什么优势?
【发布时间】:2019-01-09 14:51:33
【问题描述】:

我正在使用 WPF 重新编码一个 WinForms 应用程序(MySQL/EF6 有许多要更新的字段)。我正在检查支持每个字段的 INotifyPropertyChanged 所需的代码,并想知道这是否比事件处理背后的经典代码更有优势。

我用 C# 开发了一个强大的 WinForms 应用程序,支持相当复杂的数据模型,包括 EF6/MySQL。可以想象,对于许多文本字段、组合框、NumUpDowns 等,所有不同字段都有许多事件处理程序。当我考虑将此代码库移至 WPF 及其本机数据绑定时,我反复阅读过需要重新编码中级数据对象以支持类中每个字段的设置器上的 INotifyPropertyChanged。

我已经编写了屏幕设置方法和 Winforms 事件处理程序,它们在类和控件之间执行双向更新功能。当然,这些需要一些修改以适应 WPF 控件方法和属性。我正在尝试确定是否值得在与屏幕交互的每个单独字段上设置 INotifyPropertyChanged 所需的编码工作和持续维护,或者只是修改事件处理程序背后的更经典的代码。我有 50 到 100 个字段(各种类型),每个字段都需要对双向绑定进行特殊编码。

值得吗,还是我作为 WPF 菜鸟错过了什么?

我在现有的数据维护类中有很多很多字段都采用这种形式:

public class clsLot
{
    // Code omitted for general error codes, enums etc.


    // Here are a long list of fields which are generated by EF6 model, decorated with straightforward {get; set; }
    public long idLot { get; set; }
    public string LotID { get; set; }
    public Nullable<long> idRecipe { get; set; }
    public string PlantOrder { get; set; }
    public Nullable<System.DateTime> CreateDate { get; set; }
    public string Inspector { get; set; }
    public string LotType { get; set; }
    [... Long list omitted.  For ease of maintenance when new fields are added to the database and ef6 model regened, this list is copied from ef6 gened code

            // maintenance methods omitted for mapping between this class and database (save, update etc.
    }

当我看到 WPF 双向绑定的示例时,他们说该类必须支持 INotifyPropertyChanged,并且每个字段都必须转换 从更简单的“公共字符串 LotID {get; set;}”到类似 for each field

public class User : INotifyPropertyChanged
{
    // Begin modification for each field in the class that needs to be bi-directionally mapped
    private string _LotID;
    public string LotID 
    {
        get { return this._LotID; }
        set
        {
            if(this.name != value)
            {
                this._LotID = value;
                this.NotifyPropertyChanged("LotID");
            }
        }
    }
    // End of modification for each field

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propName)
    {
        if(this.PropertyChanged != null)
        this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

将公共事件和 NotifyPropertyChanged 方法添加到现有类没有问题。 我的问题是代码行中的 13 倍扩展以支持每个字段的 INotifyPropertyChanged 其中我有 50-100 个字段(并且不能再从创建的自动生成的类中复制/粘贴 通过 Ef6 模型)。

与仅移动和调整我在 Winforms 应用程序中现有的屏幕设置和控制事件处理程序方法相比,这样做值得吗?

我的问题的核心是我正在使用利用“public string LotID { get; set;}”语法的自动生成代码,这需要分解为每个单独的私有字段和公共属性当前自动生成的字段/属性。

【问题讨论】:

  • 如果在源属性更改时应该更新其目标属性,则应该为要用作 WPF 绑定源的属性实现 INotifyPropertyChanged。
  • 字段和属性之间有一个difference
  • 我很抱歉在使用术语字段和属性时不准确。我指的是自动生成的代码,它将两者结合起来,如“public string LotID { get; set; }”,它将两者结合为一个简写。 EF6 代码生成器广泛使用了这一点,这推动了我关于将这个方案撤消到其适当的字段/属性模型、应用 INotifyPropertyChanged 接口以及每个字段/属性的 getter/setter 的问题的来源。
  • 看看Fody.PropertyChanged。它可以减轻修改所有属性的负担;您需要做的就是在每个实现INotifyPropertyChanged 的类的顶部添加一个属性。这值得么?我认为是。

标签: c# wpf data-binding entity-framework-6


【解决方案1】:

首先,您可以使用 VS 的 Find&Replace 功能和一些巧妙的正则表达式一键完成这项工作。

首先,您忘记了可以删除所有事件处理程序,因此总共有一些行是新的,但有些会被删除。

从维护的角度来看,绑定和 INPC 对人类来说更具可读性,并且更容易解决诸如“为什么这个控件不显示当前值?”之类的问题。

您还可以编辑使用事件处理程序为这些属性进行双向同步所需的所有代码吗?

当使用绑定时,xaml 端只是 Text="{Binding SomeStringProperty}" 并且可以工作。

** 编辑 **

主要优点是您可以使用 MVVM 模式,这是 WPF 的设计初衷。正确的做法使维护应用程序变得更加容易,但在许多情况下更加乏味。

【讨论】:

  • 我确实理解可以创建新的自动化软件来修改现有代码,但是,这仍然是要编写的新软件。我主要担心的是,如果数据库模式发生变化(很有可能),所需的维护量。今天,我使用 EF6 自动生成与数据库直接交互的类,如果有变化,我会直接从生成的字段列表中复制到我的 UI 映射类中。每次架构更改时,我都需要重新修改该列表。
  • 我已经有了从 UI 类更新控件的方法(这可能需要一些 mod,但需要一次性完成),以及 VS 通过单击生成事件处理方法外壳。我确实得到了简单的 XAML 代码,这是我担心的双向映射代码,并且正在尝试在开始之前评估方向。我想选择一种方式。
  • 我展示的绑定适用于 TextBox 和大多数控件 - 这意味着当您在 TextBox 中编写内容时对象的属性会发生变化(如果您不想要,可能需要将触发器更改为 PropertyChange等到失去焦点)在某些情况下,您需要指定Mode=TwoWays。这就是你所说的双向吗?
  • 所有这些代码已经通过带有编码模板的 EF6 生成。也许编写 EF6 转换模板代码(.tt 文件)的人可以修改模板(或提供可选模板)以生成包含 INotifyPropertyChanged 代码的字段定义。
  • 我还没有完全掌握 WPF 语法,但是是的,我的意图是 Mode=TwoWays。为了实现这一点,你的 UI 模型类需要为每个字段支持 INotifyPropertyChanged,这就是我未来代码维护的问题所在。
猜你喜欢
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多