Use the MVVM Framework to Avoid Code-Behind
- 5 minutes to read
This topic describes the most common scenarios where the DevExpress MVVM Framework can help you avoid code-behind and maintain a clean MVVM pattern in your application.
Process UI Element Events in the View Model
You can specify a View Model command that is executed when a UI element raises an event. To do this, create a command in your View Model and implement one of the techniques below.
Use the EventToCommand Behavior
Assign an EventToCommand behavior to the UI element. In this behavior, specify the EventName / Event property and bind the created command to the Command property:
<UserControl>
<!-- ... -->
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded" Command="{Binding InitializeCommand}"/>
</dxmvvm:Interaction.Behaviors>
</UserControl>
public class ViewModel : ViewModelBase {
[Command]
public void Initialize() {
// ...
}
}
Use the CommandParameter property to pass a parameter to the command. The PassEventArgsToCommand and EventArgsConverter properties allow you to pass event arguments to the command.
Use Built-in Command Properties
The DevExpress Data Grid contains command properties that correspond to events. This is one of the ways how we extend MVVM support. If the UI element contains a command property (for example, the TableView.RowDoubleClickCommand for the TableView.RowDoubleClick event), bind this property to your View Model command:
<dxg:GridControl.View>
<dxg:TableView RowDoubleClickCommand="{Binding RowDoubleClickCommand}"/>
</dxg:GridControl.View>
public class ViewModel : ViewModelBase {
// ...
[Command]
public void RowDoubleClick(RowClickArgs args) {
DXMessageBox.Show("Row double click: " + ((DataItem)args.Item).Name);
}
}
Refer to the following help topic for the complete command list: Data Grid Command API.
Handle Events Outside of the View Model
You can maintain an MVVM pattern even if you cannot process UI element events in the View Model. For example, you may need to access properties of event arguments (e.Handled
, e.Cancel
, and so on).
Create a Behavior
class and attach it to the UI element. Override the OnAttached
method and subscribe to the event. Unsubscribe from the event in the overloaded OnDetaching
method:
<TextBox Text="Text">
<dxmvvm:Interaction.Behaviors>
<behaviors:ValidationBehavior ValidForeground="{Binding ValidBrush}"
InvalidForeground="{Binding InvalidBrush}"
InvalidValue="{Binding InvalidValue}"/>
</dxmvvm:Interaction.Behaviors>
</TextBox>
public class ValidationBehavior : Behavior<TextBox> {
// ...
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.TextChanged += OnAssociatedObjectTextChanged;
}
void OnAssociatedObjectTextChanged(object sender, TextChangedEventArgs e) {
// ...
}
protected override void OnDetaching() {
AssociatedObject.TextChanged -= OnAssociatedObjectTextChanged;
base.OnDetaching();
}
}
Refer to the following help topic for more information: Behaviors.
Handle Events in the View
The DXEvent extension allows you to create a simple event handler in the View:
<dxg:TableView ...
CompleteRecordDragDrop="{DXEvent Handler='@args.Handled = true'}"/>
Refer to the following help topic for more information on the DXEvent
syntax: Language Specification.
Call UI Element Methods from the View Model
Implement a Service that calls the UI element’s methods:
public interface IGridUpdateService { void BeginUpdate(); void EndUpdate(); } public class GridUpdateService : ServiceBase, IGridUpdateService { GridControl GridControl => AssociatedObject as GridControl; public void BeginUpdate() { Dispatcher.Invoke(new Action(() => { if (GridControl != null) { GridControl.BeginDataUpdate(); } })); } public void EndUpdate() { Dispatcher.Invoke(new Action(() => { if (GridControl != null) { GridControl.EndDataUpdate(); } })); } }
Attach this service to the UI element:
<dxg:GridControl> <!-- ... --> <dxmvvm:Interaction.Behaviors> <local:GridUpdateService /> </dxmvvm:Interaction.Behaviors> </dxg:GridControl>
In the View Model, obtain the service and call the service’s methods:
public class ViewModel : ViewModelBase { //... public IGridUpdateService GridUpdateService { get { return GetService<IGridUpdateService>(); } } void TimerCallback(object state) { lock(SyncRoot) { if(GridUpdateService != null) { GridUpdateService.BeginUpdate(); foreach(DataItem item in Source) { item.Value = random.Next(100); } GridUpdateService.EndUpdate(); } } } }
Refer to the following help topic for more information: Create a Custom Service.