It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

INotifyPropertyChanged auto wiring or how to get rid of redundant code

For the last week most of WPF disciples are discussing how to get rid of hardcoded property name string inside INotifyPropertyChanged implementation and how to keep using automatic properties implementation but keep WPF binding working. The thread was started by Karl Shifflett, who proposed interesting method of using StackFrame for this task. During this thread other methods were proposed including code snippets, R#, Observer Pattern, Cinch framework, Static Reflection, Weak References and others. I also proposed the method we’re using for our classes and promised to blog about it. So the topic today is how to use PostSharp to wire automatic implementation of INotifyPropertyChanged interface based on automatic setters only.

My 5 ¢

So, I want my code to looks like this:

public class AutoWiredSource {
   public double MyProperty { get; set; }
   public double MyOtherProperty { get; set; }
}

while be fully noticeable about any change in any property and makes me able to bind to those properties.

<StackPanel DataContext="{Binding Source={StaticResource source}}">
    <Slider Value="{Binding Path=MyProperty}" />
    <Slider Value="{Binding Path=MyProperty}" />
</StackPanel>

How to achieve it? How to make compiler to replace my code with following?:

private double _MyProperty;
public double MyProperty {
   get { return _MyProperty; }
   set {
      if (value != _MyProperty) {
         _MyProperty = value; OnPropertyChanged("MyProperty");
      }
   }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName) {
   if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");

   var handler = PropertyChanged as PropertyChangedEventHandler;
   if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

Simple: to use aspect oriented programming to inject set of instructions into pre-compiled source.

First of all we have to build some attribute will be used for marking classes requires change tracking. This attribute should be combined (compound) aspect to include all aspects used for change tracking. All we’re doing here is to get all set methods to add composition aspect to

[Serializable, DebuggerNonUserCode, AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = false),
MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false, Inheritance = MulticastInheritance.None, AllowExternalAssemblies = true)]
public sealed class NotifyPropertyChangedAttribute : CompoundAspect {
   public int AspectPriority { get; set; }

   public override void ProvideAspects(object element, LaosReflectionAspectCollection collection) {
      Type targetType = (Type)element;
      collection.AddAspect(targetType, new PropertyChangedAspect { AspectPriority = AspectPriority });
      foreach (var info in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => pi.GetSetMethod() != null)) {
         collection.AddAspect(info.GetSetMethod(), new NotifyPropertyChangedAspect(info.Name) { AspectPriority = AspectPriority });
      }
   }
}

Next aspect is change tracking composition aspect. Which is used for marking only

[Serializable]
internal sealed class PropertyChangedAspect : CompositionAspect {
   public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs) {
      return new PropertyChangedImpl(eventArgs.Instance);
   }

   public override Type GetPublicInterface(Type containerType) {
      return typeof(INotifyPropertyChanged);
   }

   public override CompositionAspectOptions GetOptions() {
      return CompositionAspectOptions.GenerateImplementationAccessor;
   }
}

And the next which is most interesting one, we will put onto method boundary for tracking. There are some highlights here. First we do not want to fire PropertyChanged event if the actual value did not changed, thus we’ll handle the method on it entry and on it exit for check.

[Serializable]
internal sealed class NotifyPropertyChangedAspect : OnMethodBoundaryAspect {
   private readonly string _propertyName;

   public NotifyPropertyChangedAspect(string propertyName) {
      if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
      _propertyName = propertyName;
   }

   public override void OnEntry(MethodExecutionEventArgs eventArgs) {
      var targetType = eventArgs.Instance.GetType();
      var setSetMethod = targetType.GetProperty(_propertyName);
      if (setSetMethod == null) throw new AccessViolationException();
      var oldValue = setSetMethod.GetValue(eventArgs.Instance,null);
      var newValue = eventArgs.GetReadOnlyArgumentArray()[0];
      if (oldValue == newValue) eventArgs.FlowBehavior = FlowBehavior.Return;
   }

   public override void OnSuccess(MethodExecutionEventArgs eventArgs) {
      var instance = eventArgs.Instance as IComposed<INotifyPropertyChanged>;
      var imp = instance.GetImplementation(eventArgs.InstanceCredentials) as PropertyChangedImpl;
      imp.OnPropertyChanged(_propertyName);
   }
}

We almost done, all we have to do is to create class which implements INotifyPropertyChanged with internal method to useful call

[Serializable]
internal sealed class PropertyChangedImpl : INotifyPropertyChanged {
   private readonly object _instance;

   public PropertyChangedImpl(object instance) {
      if (instance == null) throw new ArgumentNullException("instance");
      _instance = instance;
   }

   public event PropertyChangedEventHandler PropertyChanged;

   internal void OnPropertyChanged(string propertyName) {
      if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");

      var handler = PropertyChanged as PropertyChangedEventHandler;
      if (handler != null) handler(_instance, new PropertyChangedEventArgs(propertyName));
   }
}

We done. The last thing is to reference to PostSharp Laos and Public assemblies and mark compiler to use Postsharp targets (inside your project file (*.csproj)

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
  <DontImportPostSharp>True</DontImportPostSharp>
</PropertyGroup>
<Import Project="PostSharp\PostSharp-1.5.targets" />

Now we done. We can use clear syntax like following to make all our properties has public setter to be traceable. The only disadvantage is that you’ll have to drag two Post Sharp files with your project. But after all it much more convenience than manual notify change tracking all over your project.

[NotifyPropertyChanged]
public class AutoWiredSource {
   public double MyProperty { get; set; }
}

Have a nice day and be good people. Also try to thing what other extremely useful things can be done with PostSharp (or any other aspect oriented engine)

Source code for this article (1,225 KB)>>

Be Sociable, Share!

7 Responses to “INotifyPropertyChanged auto wiring or how to get rid of redundant code”

  1. Christopher Bennage Says:

    I didn’t see proxies on your list? Did I miss it? I’ve been experimenting (with some success) using DynamicProxy2. I know that several others have as well.

  2. Tamir Says:

    it is not nessecery to use proxy in this case. All you need is to invoke a method inside the setter of the property

  3. Denis Vuyka Says:

    Great article! However my great concern is performance. I’m 100% sure that you will get a dramatical performance impact when using such approach. Do you have a comparison benchmarks for large objects amount?

  4. Gael Fraiteur Says:

    Thank you for blogging about PostSharp.

    As the author of PostSharp, I’m not proud of this code sample, because it’s not as nice as it could.

    The same aspect will be implemented in a much more elegant manner in PostSharp 2.0, and it’s runtime performance will be much better.

    See http://www.postsharp.org/blog/introducing-postsharp-20-1-notifypropertychanged for the full story.

  5. Tamir Says:

    Thank you for paying attention to such problems. I will fix this article soon

  6. Elk M1 Says:

    There’s certainly nothing to be ashamed of with PostSharp, it’s an excellent code set and quite useful for someone like myself – thank you for your efforts (and this post).

  7. Greatest Product Purchaser Reviews Says:

    Thanks for your special and exciting reviews. I look forward to checking again regularily in the foreseeable future.

Leave a Reply

Recommended

 

Sponsor


Partners

WPF Disciples
Dreamhost
Code Project