.NET is a great platform to write user interfaces. From Windows Forms to WPF to Xamarin, WinUI or Blazor, you can rely on the same platform and language on a broad range of devices.
As strong as .NET is as a UI platform, it is very useful to harness the functionality of third parties like Syncfusion. Syncfusion’s mission is to build beautiful and well-engineered UI controls that are ready to use in enterprise applications. With more than 1,600 components targeting over a dozen platforms, there’s no doubt Syncfusion excels at this task.
PostSharp’s tool automates the refreshing of projects’ UIs when business objects change and drastically reduces the boilerplate code required to do so. Together, these tools can save developers time and headaches when developing for .NET.
In this blog, I will explain how PostSharp improves the function of the INotifyPropertyChanged interface and show you an example using a UI created with some of Syncfusion’s compatible controls.
The problem with INotifyPropertyChanged Boilerplate
Unfortunately, integrating the UI with the business code in .NET is not an easy task. The most painful point is making the UI automatically refresh itself when your business objects get changed. For this to work, you need to implement the infamous INotifyPropertyChanged in every single class of your model and view-model layers. Typically, it means that instead of having each property on a single line, they will take six, like in the following example.
private string name; public string Name { get => name; set { name = value; RaisePropertyChanged("Name"); } }
As if it were not enough to write six lines of code instead of one, the implementation of INotifyPropertyChanged is also a frequent source of bugs. It’s so easy to forget to raise a property change when you modify a field!
Enter PostSharp
Fortunately, there are tools that allow you to implement the INotifyPropertyChanged interface automatically, without any boilerplate code. One of these tools is PostSharp.
Instead of implementing the feature in every property, you just add a [NotifyPropertyChanged] custom attribute to your base class and you are done.
[NotifyPropertyChanged] public class CustomerModel { public string Name { get; set; } }
The previous example is completely covered by PostSharp Community, a free edition of PostSharp. It means that you can get rid of most of your boilerplate tomorrow if you want, and for free. The new source generators of C# 9.0 may also help reduce that boilerplate.
But there’s more than this case.
Unlike competing tools, PostSharp also supports composite properties like FullName. If you change FirstName or LastName, PostSharp will also say that FullName has changed.
[NotifyPropertyChanged] public class CustomerModel { public string FirstName { get; set; } public string LastName { get; set; } public string FullName => FirstName + " " + LastName; }
PostSharp also supports properties that are dependent on properties of children objects. This is very useful in the view-model layer, which typically exposes the model layer, augmented by a few read-only computed properties. Suppose, for instance, you want the font size to decrease when the customer has a long name. This would be especially annoying to implement in plain C# because you would need to react to changes in the child object. However, with PostSharp, this is a one-liner.
[NotifyPropertyChanged] public class CustomerViewModel { public double BaseFontSize { get; set; } = 12; public CustomerModel Customer { get; set; } public double FullNameFontSize => Customer.FullName.Length > 20 ? this.BaseFontSize : this.BaseFontSize * 1.2; }
How does it work?
Arthur C. Clarke, the co-author of “2001: A Space Odyssey,” famously said: “Any sufficiently advanced technology is indistinguishable from magic.” So, what’s the magic behind PostSharp?
PostSharp is a post-compiler. Once you add its NuGet packages to your projects, it inserts itself in the build process just after the C# compiler, loads the output of the compiler, analyzes it, adds the requested behaviors, and writes it back. PostSharp implements a technology named aspect-oriented programming which allows you, the developer, to teach the compiler how to automatically implement your most boring and repetitive tasks.
Just think about it. Can you teach someone to implement INotifyPropertyChanged? Certainly! How much inventiveness is needed for this task? In most cases, none! If something is boring and repetitive, it’s likely that an algorithm can do it better than a human being. That’s exactly why PostSharp was created.
When PostSharp sees the [NotifyPropertyChanged] attribute on the top of your class, it will first analyze the code of all your property getters to figure out to which fields, properties, or properties of children objects it is dependent. For instance, this algorithm will find that FullName is dependent on both FirstName and LastName, and that FullNameFontSize is dependent on FullName, Customer, and BaseFontSize.
Then, PostSharp will modify all methods (typically property setters, but not only) that modify the fields and will buffer property change notifications for the current thread.
Finally, PostSharp will modify public methods to detect when it is a good time to raise notifications. It is generally not a good idea to raise a notification immediately after a field has been changed because it may happen that the current method will modify another field just after, and you don’t want to raise notifications in the middle of a change. So, we will wait until the end of the execution of the top public methods. It’s a little detail that may seem to split hairs at first sight, but that will save you a lot of headaches.
Compatibility with Syncfusion product suites
As with any well-designed control suite, Syncfusion products support data binding through the INotifyPropertyChanged interface. PostSharp is able to enhance any project targeting .NET Framework, .NET Core, .NET 5, or .NET Standard. Therefore, you can use PostSharp Windows Forms and WPF, but also Xamarin and Blazor, as long as your view-model and model projects target .NET Standard. The following are the projects created with Syncfusion controls and PostSharp,
Summary
Today’s users expect the user interface to reflect the current state of the data without having to press F5—a feature you normally implement thanks to INotifyPropertyChanged. Instead of writing this code manually—which not only takes time but is also error-prone—you can use a tool like PostSharp. You will reduce approximately 80% of the INotifyPropertyChanged boilerplate and avoid subtle bugs.
PostSharp can also reduce the boilerplate that stems from WPF dependency properties, commands, logging, caching, multi-threading, transaction handling, and much more. There is a free PostSharp Community version that’s also available for commercial companies. To get started, watch the PostSharp MVVM introduction video, download the demo source code from GitHub, and start hacking.
Comments (3)
As the IL weaving, that Postsharp and Fody do, might cause problems with hotreload, wouldn’t it be a lot better to implement a source code generator to take care of this?
This is correct, PostSharp and Fody will break Hot Reload and Edit and Continue. Source generators can be a good solution for WPF commands because this is indeed just code generation. But for INotifyPropertyChanged, aspect-oriented programming is a superior solution because it does not require you to rewrite your code in a way that is friendly to code generators. Aspect-oriented programming allows you to keep your code clean and idiomatic, while source generators (in the case of INPC at least) force you to write your code differently (using fields instead of properties). I have developed this argument in great length in this article: https://medium.com/swlh/thinking-beyond-roslyn-source-generators-and-aspect-oriented-programming-3e42d58c37ac
Gael, This is awesome. I checked out the Project and the AutoRetryAttribute is amazing and I am going to be implement it in several of my projects.
I have used PostSharp in the past, but forgot how useful it can be, for example, with simple INotifyPropertyChange notifications.
Comments are closed.