This article is contributed. See the original author and article here.
Ever since WPF had been released, we have been written code like below many times to implement INofityPropertyChanged interface:
class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
To labor saving, we have been created base classes such as BindableBase, NotificationObject, etc… like following:
public class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T field, T value, [CallerMangerName]string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Using this class, the Person class is become to simple:
public class Person : BindableBase
{
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
}
That is less code enough. And if using with code snippets, then we can just type the code snippet name to generate the definition of properties. There are many useful C# features such as CallerMemberNameAttribute, expression-bodied members, ref, Null-conditional operators, etc.
Source generator
In a part of C# 9 compiler features, there is source generator feature. The detail is explaining in the following blog post.
Introducing C# Source Generators
I think that it is one of the best solutions to INotifyPropertyChanged interface implementation. In fact, INotifyPropertyChanged implementation is introduced as a use case of Source generator.
The sample source generator to that is here.
The sample source generator is simple and that has minimum features to focus on learning. So, I added a feature to support computed properties to get closer real use cases. The repo is here.
The source generator I created is able to generate codes from below definition:
using MvvmGenerator;
namespace MvvmGeneratorTestApp.VIewModels
{
public partial class MainWindowViewModel
{
[AutoNotify]
private string _firstName;
[AutoNotify]
private string _lastName;
[AutoNotify]
public string FullName => $"{FirstName} {LastName}"; // computed property!
}
}
The generated code is as below(I formatted it for easy to read):
namespace MvvmGeneratorTestApp.VIewModels
{
public partial class MainWindowViewModel : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private static readonly System.ComponentModel.PropertyChangedEventArgs FirstNamePropertyChangedEventArgs =
new System.ComponentModel.PropertyChangedEventArgs(nameof(FirstName));
public string FirstName
{
get => this._firstName;
set
{
if (System.Collections.Generic.EqualityComparer<string>.Default.Equals(this._firstName, value))
{
return;
}
this._firstName = value;
PropertyChanged?.Invoke(this, FirstNamePropertyChangedEventArgs);
PropertyChanged?.Invoke(this, FullNamePropertyChangedEventArgs);
FirstNameChanged();
}
}
partial void FirstNameChanged();
private static readonly System.ComponentModel.PropertyChangedEventArgs LastNamePropertyChangedEventArgs =
new System.ComponentModel.PropertyChangedEventArgs(nameof(LastName));
public string LastName
{
get => this._lastName;
set
{
if (System.Collections.Generic.EqualityComparer<string>.Default.Equals(this._lastName, value))
{
return;
}
this._lastName = value;
PropertyChanged?.Invoke(this, LastNamePropertyChangedEventArgs);
PropertyChanged?.Invoke(this, FullNamePropertyChangedEventArgs);
LastNameChanged();
}
}
partial void LastNameChanged();
private static readonly System.ComponentModel.PropertyChangedEventArgs FullNamePropertyChangedEventArgs =
new System.ComponentModel.PropertyChangedEventArgs(nameof(FullName));
}
}
The generated code is works on WPF, UWP, Xamarin.Forms and other platforms that need INotifyPropertyChanged implementation. The repository has a small WPF app to test the generated code.
If you would like to try it, then please open MvvmGenerator.sln on Visual Studio 2019 preview. And please set MvvmGeneratorTestApp project as a startup project, then start debugging. You will see following window:
Conclusion
C# 9.0 and .NET 5 will be released in November 2020. There are a lot of useful features such as source generator I introduced in this article.
For windows developers too, all features will be available on WPF on .NET 5 and WinForms on .NET 5. After Windows UI Library 3.0 was released, I believe you also get the benefits on Win UI 3.0 on .NET 5 too.
I think that the source generator is the one of great features for all developers. If you make similar codes many times, then please remind this article.
Happy coding!
Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.
Recent Comments