Fully automated MVVM library without code rewriting. There is no magic behind it: a background thread monitors object properties (explicitly annotated as [Observable]
), checks their values by comparing with their previous values, and raises change notifications "in the name" of the object.
The library utilizes the three-phase approach in each cycle.
The UI thread is used to retrieve property values for currently observed objects. The single context switch is used to read property values. If the object is known to be thread-safe its property values are read directly, i.e. without first switching to the UI thread.
The reflection is not used to retrieve property values. During the object type registration a static method is emitted to read the property value.
The library compares the current property values with their previous value and creates the list if changed properties. The analysis is made in the monitoring thread.
If the list of changed properties is not empty, a single context switch is made to the UI thread to raise all change notifications. The change notifications are always raised in the UI thread even for objects that are known to be thread-safe.
The object type registration is triggered automatically when the PropertyChanged
event is attached for the first time. The object type is scanned for public properties that are annotated with the [Observable]
attribute. For each discovered property a static method is emitted. The scanning result is cached for that object type.
When the first PropertyChanged
event is attached, the object is treated as observed. The library uses weak references to observed objects. When the last PropertyChanged
event is detached, the library stops the object observation.
The object should derive the base ObservableObject
and annotate the properties with the [Observable]
attribute:
public class Person : ObservableObject
{
[Observable]
public string Name { get; set; }
[Observable]
public int Age { get; set; }
}
Such an object should pass true
to the base constructor. Note that the library does not verify whether the object is truly thread-safe. It uses the information only to avoid context switches to the UI thread to read values of the observable properties.
public class ThreadSafePerson : ObservableObject
{
internal ThreadSafePerson() : base(true) { }
[Observable]
public string Name { get; set; }
[Observable]
public int Age { get; set; }
}
The program bootstrap should establish a monitoring scope around the application Run
method. The typical Main
method looks like this:
[STAThread]
static void Main()
{
var app = new App();
app.InitializeComponent();
var applicationMonitorScope = new ApplicationMonitorScope(new WpfNotificationContext(app.Dispatcher));
try
{
app.Run();
}
finally
{
applicationMonitorScope.DisposeAsync().AsTask().GetAwaiter().GetResult(); // when running with .NET Core
applicationMonitorScope.DisposeAsync().GetAwaiter().GetResult(); // when running with .NET Framework
}
}
- No need to call
NotifyPropertyChange
in property setters, just annotate the property with[Observable]
attribute. The library tracks property values, compares them with their previous value and issues property change notification (if needed) in the name of the object. - No need to track internal dependencies between observable properties, i.e. "if the property
X
changes the propertyY
must be notified as well". This ensures less error-prone code. - No need to notify
Command
properties that theCanExecute
method can return another value.
- do not observe properties with never changing values
- do not observe commands with never changing "can execute" results
- avoid observable properties with heavy-weight getters
- do not observe properties/commands when the UI must react instantly, call
NotifyPropertyChange
instead - use fewer observable properties/commands (prefer converters over properties)
- use virtualization where possible
- consider suspending when the app is minimized
- do not annotate indexers with
[Observable]
attribute
See In-depth look into the guidelines
The Shuriken library makes extensive use of the Event Tracing for Windows (ETW) for logging as well as for reporting performance.
Note: when observed properties throw exceptions the monitoring is not interrupted, the exceptions are just logged. The same approach is also applied when command CanExecute
or Execute
methods fail. So it is strongly recommended to turn on event capturing and writing to the Output window (at least for debug sessions).
See In-depth look into logging and performance monitoring
Use the NuGet package manager to install the package.
The library currently supports the WPF only.
Please feel free to report them.