以编程方式更改属性设置逻辑

3
我需要添加一个属性设置器的逻辑。
例如,我有一个名为“CurrentTab”的属性:
private WorkspaceViewModel _currentTab;
public WorkspaceViewModel CurrentTab
{
    get
    {
          return _currentTab;
    }
    set
    {
          _currentTab = value;
          OnPropertyChanged("CurrentTab");
    }
}

这很好并且有效,但我想只需像这样定义它:
public WorkspaceViewModel CurrentTab { get; set; }

在setter运行后,系统自动为属性名称执行OnPropertyChanged()函数,而无需我添加任何特定代码。

如何确定哪些属性需要遵循这种逻辑并不是问题,我只需要找到一种实际操作的方法。

我想让这个过程更简单,因为我将有相当多这样的属性,我希望保持整洁。

有什么方法吗? 非常感谢您的任何帮助!

2个回答

2
看看这个: Fody。它有一个用于INotifyPropertyChange的插件:github 它在生成解决方案时操纵IL代码。
您只需向视图模型添加属性即可。
[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

当代码被编译时:
public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

1
这可以通过使用PostSharp实现,它是一种面向方面编程的方法:

在计算机中,面向方面的编程(AOP)是一种编程范式,旨在通过允许分离横切关注点来增加模块性。 AOP为面向方面的软件开发奠定了基础。

您可以使用称为InstanceLevelAspect的方面来实现此操作:
/// <summary> 
/// Aspect that, when apply on a class, fully implements the interface  
/// <see cref="INotifyPropertyChanged"/> into that class, and overrides all properties to 
/// that they raise the event <see cref="INotifyPropertyChanged.PropertyChanged"/>. 
/// </summary> 
[Serializable] 
[IntroduceInterface(typeof(INotifyPropertyChanged),  
                     OverrideAction = InterfaceOverrideAction.Ignore)] 
[MulticastAttributeUsage(MulticastTargets.Class | MulticastTargets.Property,  
                          Inheritance = MulticastInheritance.Strict)] 
public sealed class NotifyPropertyChangedAttribute : InstanceLevelAspect,  
                                                     INotifyPropertyChanged 
{ 
    /// <summary> 
    /// Field bound at runtime to a delegate of the method OnPropertyChanged
    /// </summary> 
    [ImportMember("OnPropertyChanged", IsRequired = false)]
    public Action<string> OnPropertyChangedMethod; 

    /// <summary> 
    /// Method introduced in the target type (unless it is already present); 
    /// raises the <see cref="PropertyChanged"/> event. 
    /// </summary> 
    /// <param name="propertyName">Name of the property.</param> 
    [IntroduceMember(Visibility = Visibility.Family, IsVirtual = true,  
                      OverrideAction = MemberOverrideAction.Ignore)] 
    public void OnPropertyChanged(string propertyName) 
    { 
        if (this.PropertyChanged != null) 
        { 
            this.PropertyChanged(this.Instance,  
                                  new PropertyChangedEventArgs(propertyName)); 
        } 
    } 

    /// <summary> 
    /// Event introduced in the target type (unless it is already present); 
    /// raised whenever a property has changed. 
    /// </summary> 
    [IntroduceMember(OverrideAction = MemberOverrideAction.Ignore)] 
    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Method intercepting any call to a property setter. 
    /// </summary> 
    /// <param name="args">Aspect arguments.</param> 
    [OnLocationSetValueAdvice,  
     MulticastPointcut( Targets = MulticastTargets.Property,  
         Attributes = MulticastAttributes.Instance)] 
    public void OnPropertySet(LocationInterceptionArgs args) 
    { 
        // Don't go further if the new value is equal to the old one. 
        // (Possibly use object.Equals here). 
        if (args.Value == args.GetCurrentValue()) 
        {
           return; 
        }

        // Actually sets the value. 
        args.ProceedSetValue(); 

        // Invoke method OnPropertyChanged (our, the base one, or the overridden one). 
        this.OnPropertyChangedMethod.Invoke(args.Location.Name); 
    } 
} 

然后,像这样在您的属性上使用它:

[NotifyPropertyChanged]
public WorkspaceViewModel CurrentTab { get; set; }

如果您希望所有属性都实现NotifyPropertyChanged,则此属性也可以应用于类级别。有关示例的更多信息,请单击此处


3
PostSharp看起来很有前途,但最终我使用了pwas提供的Fody答案。主要是因为PostSharp不是免费的。感谢您的建议! - Rik De Peuter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接