避免在每个setter中调用RaisePropertyChanged

Ale*_*dro 3 c# proxy-classes mvvm inotifypropertychanged

我想摆脱模型类中占用空间和重复性的RaisePropertyChanged-Properties.我想要我的模特课......

public class ProductWorkItem : NotificationObject
{
    private string name;
    public string Name
    {
        get { return name; }
        set { 
            if (value == name) return; 
            name = value; RaisePropertyChanged(() => Name); 
        }
    }
    private string description;
    public string Description
    {
        get { return description; }
        set { 
            if (value == description) return; 
            description = value; RaisePropertyChanged(() => Description); 
        }
    }
    private string brand;
    public string Brand
    {
        get { return brand; }
        set { 
            if (value == brand) return; 
            brand = value; RaisePropertyChanged(() => Brand); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

...看起来像这样简单:(但是当属性改变时通知视图)

public class ProductWorkItem
{
    public string Name{ get; set; }
    public string Description{ get; set; }
    public string Brand{ get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这可以通过某种代理类来实现吗?

我想避免为每个模型类编写代理.

Hon*_*tan 5

我知道在"vanilla"C#中没有简单且可维护的方法,但你可以用方面实现这一点.我已经使用了PostSharp,它的缺点是作为付费的第三方产品,但有一个免费版本,你也可以这样做.PostSharp利用目标指定,继承等属性的优势,并将它们扩展到方面.

然后LocationInterceptionAspect,您可以定义一个覆盖OnSetValue方法来调用您的RaisePropertyChanged委托.然后,您可以使用使用aspect属性修饰的自动生成的属性.

PostSharp的付费版本允许您在类级别执行此操作,因此您只需要一个属性(或者不需要,如果您修饰基类并将属性定义为可继承).这在PostSharp网站上描述为一个用例InstanceLevelAspect


Ale*_*dro 0

我在命名空间中找到了这个类...它可以让您拦截绑定目标上对绑定源上的System.Dynamic实际DataBinding调用。DependencyObjectProperty

http://i.msdn.microsoft.com/en-us/library/system.windows.data.binding.DataBindingMostBasic(v=vs.110).png?appId=Dev11IDEF1&l=EN-US&k=k(System.Windows .Data.Binding)%3bk(VS.XamlEditor)%3bk(TargetFrameworkMoniker-.NETFramework

因此,现在可以做的是实现一个类(我们称之为DynamicNpcProxyINotifyPropertyChanged,该类实现 、 派生自DynamicObject并重写TryGetMemberTrySetMember方法。

public class DynamicNpcProxy : DynamicObject, INotifyPropertyChanged
{
    public DynamicNpcProxy(object proxiedObject)
    {
        ProxiedObject = proxiedObject;
    }

    //...

    public object ProxiedObject { get; set; }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        SetMember(binder.Name, value);
        return true;
    }

    protected virtual void SetMember(string propertyName, object value)
    {
        GetPropertyInfo(propertyName).SetValue(ProxiedObject, value, null);
        if (PropertyChanged != null) 
            PropertyChanged(ProxiedObject, new PropertyChangedEventArgs(propertyName));
    }

    protected PropertyInfo GetPropertyInfo(string propertyName)
    {
        return ProxiedObject.GetType().GetProperty(propertyName);
    }

    // override bool TryGetMember(...)
}
Run Code Online (Sandbox Code Playgroud)

要使其正常工作,请将代理包装在当前的绑定源周围,替换它们,然后让我们DynamicObject完成剩下的工作。

在 ViewModel.cs 中:

IList<ProductWorkItem> items;
//... assign items
var proxies = items.Select(p => new DynamicNpcProxy(p)).ToList();
ICollectionView Products = CollectionViewSource.GetDefaultView(proxies);
Run Code Online (Sandbox Code Playgroud)

在 View.xaml 中:

<TextBox Text="{Binding Products.CurrentItem.Name}" /> 
<TextBox Text="{Binding Products.CurrentItem.Description}" /> 
Run Code Online (Sandbox Code Playgroud)

你最终得到的是这样的:

另请查看这篇文章,其中code project提供了更多信息......