With a UI app based upon data-binding, you often need to create classes that can notify the UI when a property value changes. This is typically done by implementing the INotifyPropertyChanged interface, which requires you to raise the PropertyChanged event whenever a property value is modified. Observable entities using the CommunityToolkit.Mvvm library can simplify this process significantly.

The ObservableObject is a base class for objects that are observable by implementing the INotifyPropertyChanged and INotifyPropertyChanging interfaces. It can be used as a starting point for all kinds of objects that need to support property change notifications.
Ms Learn Reference: ObservableObject

The ObservableObject class is part of the CommunityToolkit.Mvvm library, which is a popular MVVM (Model-View-ViewModel) framework for .NET applications. It provides a simple and efficient way to implement property change notifications, which are essential for data binding in MVVM architectures.

The ObservableProperty type is an attribute that allows generating observable properties from annotated fields. Its purpose is to greatly reduce the amount of boilerplate that is needed to define observable properties.
MS Learn Reference: ObservableProperty attribute

The ObservableProperty attribute is used in conjunction with source generators to automatically create properties that raise property change notifications. By annotating a field with this attribute, the source generator will create the corresponding property and implement the necessary logic to notify when the property value changes.

So by annotating a class as ObservableObject and its fields as ObservableProperty, you can create a class that automatically notifies the UI of changes to its properties, making it easier to implement data binding in your applications. You only need to add fields as private and with an underscore or lowercase first character as the field name. When the class is “generated” by the source generator, the properties will be created with the same name as the field but with the first character capitalized.

  • Note that you need to make the class Partial for the source generator to work correctly.
  • Also you need to add the NuGet package CommunityToolkit.Mvvm to your project for the source generation to function.

An Example

using CommunityToolkit.Mvvm.ComponentModel;

....

public partial class LaneResult : ObservableObject
{
    public LaneResult()
    {
    }

    [ObservableProperty]
    private int? lane;
}

This private field “effectively” becomes:

private int? lane;

public int? Lane
{
    get => lane;
    set => {lane=value; OnPropertyChanged(nameof(Lane));}
}

When you set the Lane property, the OnPropertyChanged method is called automatically, which raises the PropertyChanged event. This notifies any UI elements that are bound to the Lane property that its value has changed, allowing them to update accordingly.

Note that when coding, if you use the implicit property name, Lane in this case, before compilation, you will see errors. Once one subsequent compilation is done, the source generator will have created the property and the errors will disappear. A bit like XAML where bindings may not recognized until after a build.

You can also directly add more properties to the class in the normal way but you have the explicitly add the OnPropertyChanged call.

Sometimes it is desirable include presentation code with a class such as formatting or display strings. These do not need to be observable so can be added as read-only properties, (but need to be excluded from serialization if the class is being serialized.) The observable property upon which they depend needs to trigger a NotifyPropertyChanged event for that read-only property when it changes. For example

    [ObservableProperty,NotifyPropertyChangedFor(nameof(LaneStr))]
    private int? lane;

    [JsonIgnore]
    [NotMapped]
    public string LaneStr
    {
        get => $"Lane {Lane}";
    }

So whenever the Lane property changes, the LaneStr property will also notify any bound UI elements to update.

Also by overriding the ToString() method you can provide a useful string representation of the object for display purposes.

    public partial class Meet :ObservableObject
    {
        ...
        ...

        public override string ToString()
        {
            string result = $"Meet Round:{Round}. Series:{Description} {DateStr} at {Location}";
            return result ;
        }

Then in xaml:

<MenuItem x:Name="MeetInfo" Header="{Binding CurrentMeet}"

Requiring in the ViewModel:

  // Object reference for the selected Meet
  private AthStitcher.Data.Meet? _CurrentMeet;
  public AthStitcher.Data.Meet? CurrentMeet
  {
      get => _CurrentMeet;
      set
      {
          _CurrentMeet = value;;
          OnPropertyChanged(nameof(CurrentMeet));
      }
  }

Nb: Could have done this as an ObservableObject as well

Footnote

There are two events that can be hooked into with an ObservableProperty:

  • On[PropertyName]Changing - called just before the property value changes
  • On[PropertyName]Changed - called just after the property value has changed

For example:

[ObservableProperty]
private string? meetName;

partial void OnMeetNameChanging(string? value)
{
    Console.WriteLine($"Meet Name is about to change to {value}");
}

partial void OnMeetNameChanged(string? value)
{
    Console.WriteLine($"Meet Meet Name has changed to {value}");
}

These can be of use for validation with On[PropertyName]Changing or logging with On[PropertyName]Changed, purposes.

Summary

Observable entities using the CommunityToolkit.Mvvm library provide a streamlined way to implement property change notifications in .NET applications. By leveraging the ObservableObject base class and the ObservableProperty attribute, developers can significantly reduce boilerplate code and simplify the process of creating data-bound classes. This approach enhances maintainability and readability while ensuring that UI elements remain synchronized with underlying data changes.

Other Observable Types

Not discussed here: ObservableCollection<T> - a collection that provides notifications when items get added, removed, or when the whole list is refreshed. Useful for collections bound to UI elements like ListView or DataGrid. _ObservableCollection is not part of CommunityToolkit.Mvvm though. It’s actually part of the .NET Base Class Library, specifically in the System.Collections.ObjectModel namespace._

Wish List

It would be nice if when annotating a class as an ObservableObject, that all private fields were automatically treated as ObservableProperty without needing to annotate each one. This would further reduce boilerplate code and make it even easier to create observable entities. This would require a convention such as, that all private fields that have, say, a leading underscore are treated as observable properties and those with a leading lowercase character are not; or vice versa!


 TopicSubtopic
   
 This Category Links 
Category:Application Dev Index:Application Dev
<  Prev:   AthStitcher