Back to Devexpress

BindableBase

wpf-17350-mvvm-framework-viewmodels-bindablebase.md

latest14.3 KB
Original Source

BindableBase

  • Jan 30, 2024
  • 8 minutes to read

The BindableBase class implements the INotifyPropertyChanged interface and provides the API to declare bindable property with minimum coding.

Bindable Properties

To declare bindable properties, do the following:

  • inherit your ViewModel from the BindableBase class;

  • use the GetValue and SetValue methods in property getters and setters.

  • C#

  • VB.NET

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
    public string FirstName {
        get { return GetValue<string>(nameof(FirstName)); } 
        set { SetValue(value, nameof(FirstName)); }
    }
}
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName() As String
        Get
            Return GetValue(Of String)(NameOf(FirstName))
        End Get
        Set(ByVal value As String)
            SetValue(value, NameOf(FirstName))
        End Set
    End Property
End Class

The BindableBase class exposes the GetValue and SetValue overloads that use the CallerMemberNameAttribute. You do not have to pass property name to these methods’ parameter. This simplifies the bindable property declaration:

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
    public string FirstName {
        get { return GetValue<string>(); } 
        set { SetValue(value); }
    }
}
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName() As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            SetValue(value)
        End Set
    End Property
End Class

Note

The CallerMemberNameAttribute is available in .NET Framework 4.5 and above.

The BindableBase in .NET Framework 4.0 section describes how to use the BindableBase View Model in .NET 4.0.

Property values are stored in an internal dictionary:

  • the GetValue method uses this dictionary to get a property value;
  • the SetValue method uses the property name as a key to store a property value in the dictionary.

The SetValue method returns True or False values that indicate whether a property has been changed. If you set the same value to the property, the SetValue method returns False and change notifications are not sent.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
    public string FirstName {
        get { return GetValue<string>(); }
        set {
            if (SetValue(value))
                NotifyFullNameChanged();
            else MessageBox.Show("Could not change value!");
        }
    }
}
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName() As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            If Not SetValue(value) Then
                NotifyFullNameChanged()
            Else MessageBox.Show("Could not change value!")
            End If
        End Set
    End Property
End Class

Note

The simplified property declaration uses a dictionary to store property values. As a result, application performance can decrease when properties are frequently accessed or updated. To avoid this, you can use properties with backing fields.

Run Custom Code When Property Value Changed

The SetValue method has overloads that take a callback method as a parameter. This callback is invoked after a property value has been changed.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
        public string FirstName {
            get { return GetValue<string>(); }
            set { SetValue(value, changedCallback: OnFirstNameChanged); }
        }
        void OnFirstNameChanged() {
            //...
        }
    }
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName() As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            SetValue(value, changedCallback:= AddressOf OnFirstNameChanged)
        End Set
    End Property
    Sub OnFirstNameChanged()
        '...
    End Sub
End Class

Manually Raise INotifyPropertyChanged.PropertyChanged

If you need to raise the INotifyPropertyChanged.PropertyChanged event for a specific property, use the RaisePropertyChanged/RaisePropertiesChanged method.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
    public string FirstName {
        get { return GetValue<string>(); }
        set { SetValue(value, changedCallback: NotifyFullNameChanged); }
    }

    public string LastName {
        get { return GetValue<string>(); }
        set { SetValue(value, changedCallback: NotifyFullNameChanged); }
    }

    public string FullName { get { return FirstName + " " + LastName; } }

    void NotifyFullNameChanged() {
        RaisePropertyChanged(nameof(FullName));
    }
}
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName() As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            SetValue(value, changedCallback:= AddressOf NotifyFullNameChanged)
        End Set
    End Property

    Public Property LastName() As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            SetValue(value, changedCallback:= AddressOf NotifyFullNameChanged)
        End Set
    End Property

    Public ReadOnly Property FullName() As String
        Get
            Return FirstName & " " & LastName
        End Get
    End Property

    Private Sub NotifyFullNameChanged()
        RaisePropertyChanged(Function() FullName)
    End Sub
End Class

Using Properties With Backing Fields

An application’s performance can decrease when a property is frequently accessed or updated because property values are stored in the Dictionary. To improve the application’s performance, store property values in backing fields.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
    string _FirstName;
    public string FirstName {
        get { return _FirstName; }
        set { SetValue(ref _FirstName, value, changedCallback: NotifyFullNameChanged); }
    }
}
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Private _FirstName As String
    Public Property FirstName() As String
        Get
            Return _FirstName
        End Get
        Set(ByVal value As String)
            SetValue(_FirstName, value, changedCallback:= AddressOf NotifyFullNameChanged)
        End Set
    End Property
End Class

Serialize Bindable Properties

The BindableBase class is marked with the DataContract attribute. As a result, the JSON serializer looks only for members marked with the DataMember attribute:

csharp
using DevExpress.Mvvm;
using System.Runtime.Serialization;
// ...
public class ViewModel : BindableBase {
    [DataMember]
    public string FirstName {
        get { return GetValue<string>(); } 
        set { SetValue(value); }
    }
}
vb
Imports DevExpress.Mvvm
Imports System.Runtime.Serialization

Public Class ViewModel
    Inherits BindableBase

    <DataMember>
    Public Property FirstName As String
        Get
            Return GetValue(Of String)()
        End Get
        Set(ByVal value As String)
            SetValue(value)
        End Set
    End Property
End Class

BindableBase in .NET Framework 4.0

Bindable Properties

Use the GetProperty and SetProperty methods to implement bindable properties.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
        public string FirstName {
            get { return GetProperty(() => FirstName); }
            set { SetProperty(() => FirstName, value); }
        }
    }
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName As String
        Get
            Return GetProperty(Function() FirstName)
        End Get
        Set(value As String)
            SetProperty(Function() FirstName, value)
        End Set
    End Property
End Class

The first parameter of the GetProperty and SetProperty methods is a lambda expression that returns the property used to identify the target property name. The property names are internally obtained with the static BindableBase.GetPropertyName<T> method.

Run Custom Code When Property Value Changed

The SetProperty method returns True or False values that indicate whether a property was changed. If you set the property to the same value, the SetProperty method returns False and changing notifications are not sent. The SetProperty method has overloads that take a callback method as a parameter. This callback is invoked after the field has been changed.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
        public string FirstName {
            get { return GetProperty(() => FirstName); }
            set { SetProperty(() => FirstName, value, OnFirstNameChanged); }
        }
        void OnFirstNameChanged() {
            //...
        }
    }
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public Property FirstName As String
        Get
            Return GetProperty(Function() FirstName)
        End Get
        Set(value As String)
            SetProperty(Function() FirstName, value, AddressOf OnFirstNameChanged)
        End Set
    End Property
    Sub OnFirstNameChanged()
        '...
    End Sub
End Class

Manually Raise INotifyPropertyChanged.PropertyChanged

If you need to raise the INotifyPropertyChanged.PropertyChanged event for a specific property, use the RaisePropertyChanged/RaisePropertiesChanged method.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
        public string FullName {
            get { return string.Format("{0} {1}", FirstName, LastName); }
        }
        public string FirstName {
            get { return GetProperty(() => FirstName); }
            set { SetProperty(() => FirstName, value, OnFirstNameChanged); }
        }
        public string LastName {
            get { return GetProperty(() => LastName); }
            set {
                if(SetProperty(() => LastName, value))
                    RaisePropertyChanged(() => FullName);
            }
        }
        void OnFirstNameChanged() {
            RaisePropertyChanged(() => FullName);
        }
    }
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Public ReadOnly Property FullName As String
        Get
            Return String.Format("{0} {1}", FirstName, LastName)
        End Get
    End Property
    Public Property FirstName As String
        Get
            Return GetProperty(Function() FirstName)
        End Get
        Set(value As String)
            SetProperty(Function() FirstName, value, AddressOf OnFirstNameChanged)
        End Set
    End Property
    Public Property LastName As String
        Get
            Return GetProperty(Function() LastName)
        End Get
        Set(value As String)
            If SetProperty(Function() LastName, value) Then
                RaisePropertyChanged(Function() FullName)
            End If
        End Set
    End Property
    Sub OnFirstNameChanged()
        RaisePropertyChanged(Function() FullName)
    End Sub
End Class

Using Properties With Backing Fields

An application performance can decrease when a property is frequently updated (due to the calculation of property names from lambda expressions and storing property values in the Dictionary). To accommodate these scenarios, use storage variables for properties and calculate property names once from the static constructor using the BindableBase.GetPropertyName<T> method.

csharp
using DevExpress.Mvvm;

public class ViewModel : BindableBase {
        static string Property1Name;
        static ViewModel() {
            Property1Name = BindableBase.GetPropertyName(() => new ViewModel().Property1);
        }

        string property1;
        public string Property1 {
            get { return property1; }
            set { SetProperty(ref property1, value, Property1Name); }
        }
    }
vb
Imports DevExpress.Mvvm

Public Class ViewModel
    Inherits BindableBase
    Shared Property1Name As String
    Shared Sub New()
        Property1Name = BindableBase.GetPropertyName(Function() New ViewModel().Property1)
    End Sub

    Dim _Property1 As String
    Public Property Property1 As String
        Get
            Return _Property1
        End Get
        Set(value As String)
            SetProperty(_Property1, value, Property1Name)
        End Set
    End Property
End Class