windowsforms-401698-cross-platform-app-development-winforms-mvvm-concepts-data-bindings-and-notifications-advanced-binding-features.md
Converters allow you to dynamically convert bindable property values.
The DevExpress MVVM Framework automatically converts simple types. For instance, in the Binding via Default Converters demo, a string TextEdit.Text property is bound to the integer ViewModel Progress property. Here, the Framework converts property values from Int32 to String and back.
//View code
var fluent = mvvmContext.OfType<ViewModel>();
fluent.SetBinding(editor, e => e.Text, x => x.Progress);
//ViewModel code
public class ViewModel {
public virtual int Progress { get; set; }
}
'View code
Dim fluent = mvvmContext.OfType(Of ViewModel)()
fluent.SetBinding(editor, Function(e) e.Text, Function(x) x.Progress)
'ViewModel code
Public Class ViewModel
Public Overridable Property Progress() As Integer
End Class
The MvvmContext component fires the BindingConvert event when the Framework converts values. You can handle this event to adjust the conversion logic. The Binding with Custom Conversion Handling demo illustrates a TextEdit editor. The editor’s EditValue property is bound to the integer ViewModel Value property. If a user leaves the TextEdit blank, the editor’s EditValue is null because automatic conversion cannot convert null to Int32. In this case, use the BindingConvert event handler to change null to 0.
//View code
var fluent = mvvmContext.OfType<ViewModel>();
mvvmContext.BindingConvert += (s, e) => {
string strValue = e.Value as string;
if(strValue != null) {
int intValue;
if(int.TryParse(strValue, out intValue))
e.Value = intValue;
else
e.Value = null;
}
if(e.Value == null)
e.Value = 0;
};
fluent.SetBinding(editor, e => e.EditValue, x => x.Value);
'View code
Dim fluent = mvvmContext.OfType(Of ViewModel)()
AddHandler mvvmContext.BindingConvert, Sub(s, e)
Dim strValue As String = TryCast(e.Value, String)
If strValue IsNot Nothing Then
Dim intValue As Integer = Nothing
If Integer.TryParse(strValue, intValue) Then
e.Value = intValue
Else
e.Value = Nothing
End If
End If
If e.Value Is Nothing Then
e.Value = 0
End If
End Sub
fluent.SetBinding(editor, Function(e) e.EditValue, Function(x) x.Value)
When you use complex property types that cannot be converted automatically, pass two converters as the last SetBinding method parameters. The first converter converts bindable property values to an acceptable type and the second converter does the opposite.
The Binding via Custom Converters demo illustrates a ViewModel with the ModelState property that accepts custom State enumeration values. This property is bound to the CheckBox.CheckState property of the System.Windows.Forms.CheckState type. Lambda expressions in the SetBinding methods are converters that transform property values.
//View code
var fluent = mvvmContext.OfType<ViewModel>();
fluent.SetBinding(check, e => e.CheckState, x => x.ModelState,
modelState => {
// Convert the ViewModel.State to CheckState
switch(modelState) {
case ViewModel.State.Active:
return CheckState.Checked;
case ViewModel.State.Inactive:
return CheckState.Unchecked;
default:
return CheckState.Indeterminate;
}
},
checkState => {
// Convert back from CheckState to the ViewModel.State
switch(checkState) {
case CheckState.Checked:
return ViewModel.State.Active;
case CheckState.Unchecked:
return ViewModel.State.Inactive;
default:
return ViewModel.State.Suspended;
}
});
//ViewModel code
public class ViewModel {
public virtual State ModelState {
get;
set;
}
public enum State {
Suspended = 0,
Inactive = 1,
Active = 2
}
}
Dim fluent = mvvmContext.OfType(Of ViewModel)()
fluent.SetBinding(check, Function(e) e.CheckState, Function(x) x.ModelState, Function(modelState)
Select Case modelState
Case ViewModel.State.Active
Return CheckState.Checked
Case ViewModel.State.Inactive
Return CheckState.Unchecked
Case Else
Return CheckState.Indeterminate
End Select
End Function,
Function(checkState)
Select Case checkState
Case CheckState.Checked
Return ViewModel.State.Active
Case CheckState.Unchecked
Return ViewModel.State.Inactive
Case Else
Return ViewModel.State.Suspended
End Select
End Function)
'ViewModel code
Public Class ViewModel
Public Overridable Property ModelState() As State
Public Enum State
Suspended = 0
Inactive = 1
Active = 2
End Enum
End Class
If users are not allowed to edit the View element’s property value, you can skip the reversed conversion.
To format bound property values, pass a string format expression to the SetBinding method. The {0} character sequence is a placeholder for the property value.
var fluent = mvvmContext.OfType<ViewModel>();
fluent.SetBinding(labelControl, l => l.Text, x => x.Value, "Bound property value is ({0})");
Dim fluent = mvvmContext.OfType(Of ViewModel)()
fluent.SetBinding(labelControl, Function(l) l.Text, Function(x) x.Value, "Bound property value is ({0})")
You can add Format Specifiers to apply additional numeric, date-time, and time span formats. The MVVM Best Practices demo illustrates how to display integer values as currency.
var fluent = mvvmContext.OfType<ViewModel>();
fluent.SetBinding(label, l => l.Text, x => x.Price, "Price: {0:C2}");
Dim fluent = mvvmContext.OfType(Of ViewModel)()
fluent.SetBinding(label, Function(l) l.Text, Function(x) x.Price, "Price: {0:C2}")
To combine values of multiple properties within the same control, use the MvvmContext.SetMultiBinding method. This method accepts the following parameters:
The DevExpress Demo Center provides two modules that combine values of the FirstName and LastName properties into one TextEdit editor. The module that uses a format string binds properties to a disabled (non-editable) editor. In the module that uses converters, you can change the TextEdit value and pass updated strings back to ViewModel properties.
var fluent = mvvmContext.OfType<ViewModel>();
mvvmContext.SetMultiBinding(
editForFullName,
e => e.Text,
new string[] { "FirstName", "LastName" },
"{1}, {0}"
);
Dim fluent = mvvmContext.OfType(Of ViewModel)()
mvvmContext.SetMultiBinding(editForFullName, Function(e) e.Text, New String() { "FirstName", "LastName" }, "{1}, {0}")
var fluent = mvvmContext.OfType<ViewModel>();
mvvmContext.SetMultiBinding(
editForFullName,
e => e.EditValue,
new string[] { "FirstName", "LastName" },
values => string.Join(",", values),
value => ((string)value).Split(',')
);
Dim fluent = mvvmContext.OfType(Of ViewModel)()
mvvmContext.SetMultiBinding(
editForFullName,
Function(e) e.EditValue,
New String() { "FirstName", "LastName" },
Function(values) String.Join(",", values),
Function(value) CStr(value).Split(","c))