最小化绑定属性上的WPF样板代码

本文关键字:代码 WPF 绑定 属性 最小化 | 更新日期: 2023-09-27 18:18:07

考虑一个具有许多输入字段的WPF对话框,这些字段绑定到视图模型中的属性。例如

...
<TextBox Text="{Binding FirstName}">
...
public string FirstName {
  get { return mFirstName; }
  set {
    if (mFirstName == value) return;
    mFirstName = value;
    OnPropertyChanged("FirstName");
  }
}

由于有数十个这样的字段,我想尽量减少要编写的样板c#代码。我有什么选择?

最小化绑定属性上的WPF样板代码

如果您可以选择使用基类,请考虑从以下内容继承视图模型对象:

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }
        storage = value;
        // ReSharper disable once ExplicitCallerInfoArgument
        OnPropertyChanged(propertyName);
        return true;
    }
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    protected void OnPropertiesChanged(params string[] propertyNames)
    {
        foreach (string propertyName in propertyNames)
        {
            // ReSharper disable once ExplicitCallerInfoArgument
            OnPropertyChanged(propertyName);
        }
    }
}

示例用法,显示样板文件大大减少了:

public sealed class ViewModel : BindableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        private set { SetProperty(ref name, value); }
    }
}

(如果你不能使用基类(例如,你已经有一个或正在使用框架元素的属性),你仍然可以选择直接在相关类中添加类似的支持)

我可以让你的代码更容易转换成代码段。

if (mFirstName != value) {
    mFirstName = value;
    OnPropertyChanged("FirstName");
}

如果仅仅是编写代码所花费的时间就很痛苦,并且您经常使用WPF,那么代码片段也可能有用。我知道在Sublime Text, VS Code和Visual Studio中,snippet是无价的。除此之外,我认为它就是你能看到的最基本的内容了,除非有什么我没看到的

我使用Fody在编译时注入属性更改的代码。你的类获得一个[ImplementPropertyChanged]属性,然后你的{get;设置;}属性成为编译后代码中的通知属性。

https://github.com/Fody/PropertyChanged

首先,我猜你已经在用微软了。Prism,您可以在后台删除字符串并从CallerMemberNameAttribute中获利,因此您的代码看起来像这样:

public string FirstName {
  get { return mFirstName; }
  set {
    if (mFirstName == value) return;
    mFirstName = value;
    OnPropertyChanged();
  }
}

这也等价于c# 6.0的nameof(FirstName)运算符。

第二,您可以深入研究AOP并将样板抽象为一个属性。处理这个问题的AOP框架之一是PostSharp,使用它你的代码可以像这样:

[NotifyPropertyChanged]
public class Customer
{
    public string FirstName { get; set; }

虽然它不是免费的,而且AOP有它的缺点(感谢Evk)。

类似的问题已经被问到1,2,遗憾的是,目前似乎没有最佳答案,因为这是每个人的痛苦。