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

时间:2016-11-16 13:13:56

标签: c# wpf data-binding

考虑具有许多输入字段的WPF对话,这些输入字段绑定到视图模型中的属性。 E.g。

...
<TextBox Text="{Binding FirstName}">
...

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

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

4 个答案:

答案 0 :(得分:0)

我可以让您的代码更容易转换为代码段。

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

如果只是写它的时间很痛苦,并且你经常使用WPF,那么片段也可能有用。我知道在Sublime Text,VS Code和Visual Studio中,Snippets非常有用。否则,我认为它只是你能得到的骨头,除非有我没看到的东西

答案 1 :(得分:0)

首先,我猜您已经使用了Microsoft.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 has it's drawbacks(感谢Evk)。

类似的问题已被问到12,现在似乎没有最佳答案,因为这是每个人的痛苦。

答案 2 :(得分:0)

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

https://github.com/Fody/PropertyChanged

答案 3 :(得分:0)

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

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); }
    }
}

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