wpf-17350-mvvm-framework-viewmodels-bindablebase.md
The BindableBase class implements the INotifyPropertyChanged interface and provides the API to declare bindable property with minimum coding.
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.
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
public string FirstName {
get { return GetValue<string>(nameof(FirstName)); }
set { SetValue(value, nameof(FirstName)); }
}
}
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:
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
public string FirstName {
get { return GetValue<string>(); }
set { SetValue(value); }
}
}
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 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.
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!");
}
}
}
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.
The SetValue method has overloads that take a callback method as a parameter. This callback is invoked after a property value has been changed.
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
public string FirstName {
get { return GetValue<string>(); }
set { SetValue(value, changedCallback: OnFirstNameChanged); }
}
void OnFirstNameChanged() {
//...
}
}
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
If you need to raise the INotifyPropertyChanged.PropertyChanged event for a specific property, use the RaisePropertyChanged/RaisePropertiesChanged method.
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));
}
}
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
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.
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
string _FirstName;
public string FirstName {
get { return _FirstName; }
set { SetValue(ref _FirstName, value, changedCallback: NotifyFullNameChanged); }
}
}
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
The BindableBase class is marked with the DataContract attribute. As a result, the JSON serializer looks only for members marked with the DataMember attribute:
using DevExpress.Mvvm;
using System.Runtime.Serialization;
// ...
public class ViewModel : BindableBase {
[DataMember]
public string FirstName {
get { return GetValue<string>(); }
set { SetValue(value); }
}
}
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
Use the GetProperty and SetProperty methods to implement bindable properties.
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
public string FirstName {
get { return GetProperty(() => FirstName); }
set { SetProperty(() => FirstName, value); }
}
}
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.
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.
using DevExpress.Mvvm;
public class ViewModel : BindableBase {
public string FirstName {
get { return GetProperty(() => FirstName); }
set { SetProperty(() => FirstName, value, OnFirstNameChanged); }
}
void OnFirstNameChanged() {
//...
}
}
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
If you need to raise the INotifyPropertyChanged.PropertyChanged event for a specific property, use the RaisePropertyChanged/RaisePropertiesChanged method.
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);
}
}
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
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.
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); }
}
}
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