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

时间:2014-07-21 11:18:02

标签: c# .net reflection properties

我需要添加属性设置器的逻辑。

例如,我有一个名为“CurrentTab”的属性:

private WorkspaceViewModel _currentTab;
public WorkspaceViewModel CurrentTab
{
    get
    {
          return _currentTab;
    }
    set
    {
          _currentTab = value;
          OnPropertyChanged("CurrentTab");
    }
}

这一切都很好并且有效,但我希望能够像这样定义它:

public WorkspaceViewModel CurrentTab { get; set; }

这样,在setter运行后,系统会自动为属性名执行OnPropertyChanged()函数,而不添加任何特定代码。 如何确定哪些属性需要遵循这个逻辑是没有问题的,我只需要找到一种方法来实际执行它。

我想让这更简单,因为我将拥有相当多的这类属性,我想保持它的清洁。

有办法吗? 非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

看看:FodyINotifyPropertyChange有一个加载项: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 :(得分:1)

这可以使用PostSharp来实现,Aspect Oriented Programming方法:

  

在计算中,面向方面编程(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,则此类attirubte也可以在类级别应用。有关示例的更多信息,请参见here