DevExpress MVVM Framework. Behaviors.

WPF Team Blog
18 July 2014

OTHER RELATED ARTICLES:

  1. Getting Started with DevExpress MVVM Framework. Commands and View Models.
  2. DevExpress MVVM Framework. Introduction to Services, DXMessageBoxService and DialogService.
  3. DevExpress MVVM Framework. Interaction of ViewModels. IDocumentManagerService.
  4. DevExpress MVVM Framework. Introduction to POCO ViewModels.
  5. DevExpress MVVM Framework. Interaction of ViewModels. Messenger.
  6. DevExpress MVVM Framework. Using Scaffolding Wizards for building Views.
  7. DevExpress MVVM Framework. Data validation. Implementing IDataErrorInfo.
  8. DevExpress MVVM Framework. Using DataAnnotation attributes and DevExpress Fluent API.
  9. THIS POST: DevExpress MVVM Framework. Behaviors.
  10. DevExpress MVVM Framework. TaskbarButtonService, ApplicationJumpListService and NotificationService.
  11. DevExpress MVVM Framework. Asynchronous Commands.
  12. DevExpress MVVM Framework. Converters.

All the features described in this post are available in both the free and non-free versions of the DevExpress MVVM framework (included in the DevExpress WPF component suite).

The Behavior mechanism extends the capabilities of visual controls. You can implement missing functionality with a custom Behavior and begin using it with ease.

Example. You have a WPF or Silverlight form containing some components. You wish to focus a specific control on startup. This isn’t particularly easy, because we need to handle the Loaded event of the form and call the Focus method for the necessary control.

<Window x:Class="WpfApplication1.MainWindow" ...>
    <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
            <TextBox Text="Enter your name: "/>
            <TextBox Name="name" Width="200"/>
        </StackPanel>
    </Grid>
</Window>
public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();
        Loaded += OnLoaded;
    }
    void OnLoaded(object sender, RoutedEventArgs e) {
        name.Focus();
    }
}

To adhere to the MVVM pattern and keep the code clear, you can implement a custom Behavior to perform the same.

public class FocusBehavior : Behavior<FrameworkElement> {
    protected override void OnAttached() {
        base.OnAttached();
        AssociatedObject.Focus();
    }
}

There is no longer a need to handle the Loaded event - everything will now work fine without it. The code is simple and can used in any place in your application.

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <TextBox Text="Enter your name: "/>
    <TextBox Name="name" Width="200">
        <dxmvvm:Interaction.Behaviors>
            <local:FocusBehavior/>
        </dxmvvm:Interaction.Behaviors>
    </TextBox>
</StackPanel>

You can further extend the Behavior by adding dependency properties, events, and other customization options.

 

How do Behaviors work?

The DevExpress.Mvvm.UI.Interactivity.Interaction class implements a Behaviors attached property. This property is read-only and contains a collection of Behaviors. The elements in this collection descend from the AttachableObjectBase class. This class has an AssociatedObject property, set internally once a Behavior is added to the Behaviors collection. After the AssociatedObject property is set, the OnAttached virtual method is invoked. You can override this method to subscribe to AssociatedObject events. When the Behavior is destroyed, an OnDetaching virtual method is called where you can unsubscribe from events.

protected override void OnAttached() {
    base.OnAttached();
    AssociatedObject.Loaded += OnAssociatedObjectLoaded;
}
protected override void OnDetaching() {
    AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
    base.OnDetaching();
}

 

Predefined set of Behaviors in DevExpress MVVM Framework

  • Probably, the most useful Behavior is EventToCommand. Here is a simple example of how to use it.
<UserControl x:Class="EventToCommandSample.MainView"
             xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" ...>
    <dxmvvm:Interaction.Behaviors>
        <dxmvvm:EventToCommand EventName="Loaded" Command="{Binding InitCommand}"/>
    </dxmvvm:Interaction.Behaviors>
</UserControl>
 
  • FocusBehavior allows specify a control to be focused on start up.
<StackPanel Orientation="Horizontal" Margin="10">
    <TextBlock Text="This control is focused on startup: " VerticalAlignment="Center"/>
    <TextBox Text="Focus is here">
        <dxmvvm:Interaction.Behaviors>
            <dxmvvm:FocusBehavior/>
        </dxmvvm:Interaction.Behaviors>
    </TextBox>
</StackPanel>

FocusBehavior can also be triggered when a specific property is changed or an event occurs.

<StackPanel Orientation="Horizontal" Margin="10">
    <TextBlock Text="This control is focused on button click: " VerticalAlignment="Center"/>
    <TextBox Text="Click the bottom button">
        <dxmvvm:Interaction.Behaviors>
            <dxmvvm:FocusBehavior SourceName="button" EventName="Click"/>
        </dxmvvm:Interaction.Behaviors>
    </TextBox>
    <Button x:Name="button" Content="Click to focus the TextBox"/>
</StackPanel>
 
  • ValidationErrorsHostBehavior tracks validation errors with ease. For instance:
[POCOViewModel(ImplementIDataErrorInfo=true)]
public class MainViewModel {
    [Required]
    public virtual string FirstName { get; set; }
    [Required]
    public virtual string LastName { get; set; }
}
<UserControl.Resources>
    <dxmvvm:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
</UserControl.Resources>
<dxmvvm:Interaction.Behaviors>
    <dxmvvm:ValidationErrorsHostBehavior x:Name="validationErrorsHostBehavior"/>
</dxmvvm:Interaction.Behaviors>
<Grid>
    <StackPanel Orientation="Vertical" ...>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="First Name: " .../>
            <TextBox Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, 
                            NotifyOnValidationError=True, ValidatesOnDataErrors=True}" .../>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Last Name: " .../>
            <TextBox Text="{Binding LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, 
                            NotifyOnValidationError=True, ValidatesOnDataErrors=True}" .../>
        </StackPanel>
        <Button Content="Save" ... IsEnabled="{Binding ElementName=validationErrorsHostBehavior, 
                                               Path=HasErrors, Converter={StaticResource BooleanNegationConverter}}"/>
    </StackPanel>
</Grid>

The Save button will be disabled until the end-user fills the required fields.

  • ConfirmationBehavior. It’s often required to show a confirmation box before performing an action. For instance, an end-user changes something in a document and closes it. While closing, we need to show the message: “Are you sure to close the document?” For this purposes, there is ConfirmationBehavior.
<Button Content="Save" HorizontalAlignment="Center" VerticalAlignment="Center">
    <dxmvvm:Interaction.Behaviors>
        <dxmvvm:ConfirmationBehavior Command="{Binding SaveCommand}" 
                                     MessageText="Do you want to save?" MessageButton="YesNo"/>
    </dxmvvm:Interaction.Behaviors>
</Button>

To accomplish the same task without ConfirmationBehavior, it’s necessary to use IMessageBoxService from the SaveCommand (I described this approach in a previous post).

  • DependencyPropertyBehavior. Sometimes, the properties that a control provides aren’t dependency properties. For instance, the TextBox.SelectedText property. This means the WPF binding system can’t target this property. In such cases, can use a DependencyPropertyBehavior.
<TextBox Width="200" Text="Select some text in this box">
    <dxmvvm:Interaction.Behaviors>
        <dxmvvm:DependencyPropertyBehavior PropertyName="SelectedText" 
                          EventName="SelectionChanged" Binding="{Binding SelectedText, Mode=TwoWay}"/>
    </dxmvvm:Interaction.Behaviors>
</TextBox>

The above code binds the TextBox.SelectedText property to the SelectedText property of the underlying ViewModel. Notice that the DependencyPropertyBehavior.EventName property is set. When performing updates on the bound properties the behavior will processes the specified event.

6 comment(s)
Marcin Sulecki
Marcin Sulecki

I have a proposition to add to EventToCommand paragraph description PassEventArgsToCommand nad EventArgsConverter properties.

  <dxmvvm:Interaction.Triggers>

               <dxmvvm:EventToCommand

Command="{Binding YourCommand}"

                          EventName="YourEvent"

                          EventArgsConverter="{StaticResource MyConverter}"

                          PassEventArgsToCommand="true" />

           </dxmvvm:Interaction.Triggers>

1 September, 2014
Alexander (DevExpress Support)
Alexander (DevExpress Support)

Hi Marcin,

I am currently working on a blog about the EventToCommand trigger. Hope that I will manage to publish it in a few days.

Also, I am working on our documentation. With the next minor, the documentation will be updated, and so it will contain more information about our MVVM framework.

Thank you for your interest in our products!

1 September, 2014
Apurva Sharma
Apurva Sharma

Is there a way to implement the behavior on a GridControl's row/cell?

20 October, 2014
Alexander (DevExpress Support)
Alexander (DevExpress Support)

Hi,

Yes, it is possible, but everything is related to your particular scenario. Please contact our support team and provide more details about the behavior you wish to implement. We will be happy to assist you.

21 October, 2014
Meha Jain
Meha Jain

Hi,

I want to know, which dll we need to add as reference for dev express in order to use the Event To Command functionality

xmlns:dxmvvm="schemas.devexpress.com/.../mvvm" ...>

10 August, 2015
Alexander (DevExpress Support)
Alexander (DevExpress Support)

Hi Meha,

EventToCommand is used in the UI layer and its implementation depends on a particular platform. So, it is located in the DevExpress.Xpf.Core library.

17 August, 2015

Please login or register to post comments.