Click or drag to resize
Binding to Model Data

Without library support, binding the value of a C# source property to the value of a C# target property is rather tedious and error-prone. This is due to the fact that implementations of INotifyPropertyChanged signal a property change by calling the subscribed handler with the property name as a string. The handler then needs to compare the passed string to find out exactly which property has been changed. The Lawo.ComponentModel and Lawo.Reflection namespaces offer a few tools to make this process much easier.

Bindings are typically created in the ViewModel constructor.

Note Note

All the binding methods discussed below return an object that represents the newly created binding. The binding can be broken by calling Dispose. In many cases however, it is sensible to never explicitly remove a binding.

This topic contains the following sections:

Two-Way Binding
C#
TwoWayBinding.Create(
    this.settings.GetProperty(o => o.ListeningPort), this.GetProperty(o => o.ListeningPort));
TwoWayBinding.Create(
    this.settings.GetProperty(o => o.ProviderHostName), this.GetProperty(o => o.ProviderHostName));
TwoWayBinding.Create(
    this.settings.GetProperty(o => o.ProviderPort), this.GetProperty(o => o.ProviderPort));
TwoWayBinding.Create(
    this.settings.GetProperty(o => o.LogFolder), this.GetProperty(o => o.LogFolder));
TwoWayBinding.Create(
    this.settings.GetProperty(o => o.AutoScrollToMostRecentEvent),
    a => a,
    this.GetProperty(o => o.AutoScrollToMostRecentEvent),
    a => a.GetValueOrDefault());

TwoWayBinding can be used to simply "forward" a property from the Model to the ViewModel and vice versa. Overloads that accept conversion functions can be used to convert between properties of differing types.

One-Way Binding

OneWayBinding can be used if changes only need to be propagated from the Model to the ViewModel but not the other way round. ViewModel properties bound in such a way are typically read-only for the View.

Multi-Binding

MultiBinding can be used if the value of a ViewModel property depends on multiple other properties.

Calculated Property

CalculatedProperty offers a slightly easier way than MultiBinding to implement a ViewModel property that depends on multiple other properties. The differences are:

To implement a calculated property in MainWindowViewModel, firstly we need a field:

C#
private readonly CalculatedProperty<bool> canStart;

Secondly, the field needs to be assigned an appropriately initialized instance:

C#
this.canStart = CalculatedProperty.Create(
    this.GetProperty(o => o.IsStarted),
    this.GetProperty(o => o.IsStopped),
    this.GetProperty(o => o.ListeningPort),
    this.GetProperty(o => o.ProviderPort),
    this.GetProperty(o => o.LogFolder),
    (isStarted, isStopped, lp, pp, lf) => !isStarted && isStopped && string.IsNullOrEmpty(ValidatePort(lp) + ValidatePort(pp) + ValidateFolder(lf)),
    this.GetProperty(o => o.CanStart));

The first 5 arguments represent the source properties that the calculated property is derived from. The next argument calculates the value of the target property from the values of the source properties. The last argument represents the target property.

The implementation of the actual property looks as follows:

C#
public bool CanStart => this.canStart.Value;
Caution note Caution

By design, the NotifyPropertyChangedPropertyChanged event occurs before the CalculatedPropertyT instance can be assigned to the field.

Therefore, if an event handler is already subscribed to PropertyChanged while a CalculatedPropertyT instance is created, the event handler will provoke a NullReferenceException if it attempts to call the getter of the calculated property.

This problem can easily be avoided by only ever calling CalculatedPropertyCreate inside a constructor and immediately assigning the resulting instance to a private readonly field. In scenarios where this is not possible, MultiBinding should be used instead.