DevExpress MVVM Framework. MethodToCommandBehavior.

WPF Team Blog
21 April 2015

In a previous blog post, we described how to bind a function to a property without introducing additional properties and writing extra code by using FunctionBindingBehavior. In this post, we’ll consider a different but no less useful option.

All the features described herein are available in both the free and commercial versions of the DevExpress MVVM framework (included in the DevExpress WPF Subscription).

MethodToCommandBehavior

For purposes of this post, let’s consider a common usage scenario - the requirement to assign a method to an ICommand type property (invoke a method of a View or ViewModel by using the Button.Command property). You can accomplish this task by implementing corresponding descendants with required command properties or a custom service that allows access the control’s methods in accordance with MVVVM pattern. This, however, requires writing additional classes, methods and properties.

We introduced the MethodToCommand behavior so you can accomplish these tasks with minimal effort. The general concepts behind MethodToCommandBehavior are similar to those of FunctionBindingBehavior. Both MethodToCommandBehavior and FunctionBindingBehavior operate with two objects: Target and Source. The Source property contains an object whose method will be used for creating a command and as a result will be invoked.

The Target property contains an object whose command property is populated with an ICommand object, which is created by MethodToCommand based on the source-method. The source-method and target-command property should be specified via corresponding MethodToCommand.Method and MethodToCommand.Command properties. By default, MethodToCommandBehavior uses its associated object as Target (target-object) and the data context of its associated object as Source (source-object)

The code snippet below illustrates how to invoke the GridControl’s ClearSorting and SortBy methods by clicking bar button items.

   1: <UserControl 
   2:     ...
   3:     DataContext="{dxmvvm:ViewModelSource Type=vm:MainViewModel}">
   4:     <Grid>
   5:         <dxb:BarManager>
   6:             <dxb:BarManager.Bars>
   7:                 <dxb:Bar Caption="Column Sorting Bar">
   8:                     <dxb:BarButtonItem 
   9:                         Content="Descending" 
  10:                         Glyph="{dx:DXImage Image=MoveDown_16x16.png}">
  11:                         <dxmvvm:Interaction.Behaviors>
  12:                             <dxmvvm:MethodToCommandBehavior 
  13:                                 Source="{Binding ElementName=gridControl}" 
  14:                                 Method="SortBy"
  15:                                 Arg1="{Binding ElementName=gridControl,Path=CurrentColumn}" 
  16:                                 Arg2="Descending">
  17:                             </dxmvvm:MethodToCommandBehavior>
  18:                         </dxmvvm:Interaction.Behaviors>
  19:                     </dxb:BarButtonItem>
  20:                     <dxb:BarButtonItem 
  21:                         Content="Ascending" 
  22:                         Glyph="{dx:DXImage Image=MoveUp_16x16.png}">
  23:                         <dxmvvm:Interaction.Behaviors>
  24:                             <dxmvvm:MethodToCommandBehavior 
  25:                                 Source="{Binding ElementName=gridControl}" 
  26:                                 Method="SortBy"
  27:                                 Arg1="{Binding ElementName=gridControl,Path=CurrentColumn}" 
  28:                                 Arg2="Ascending">
  29:                             </dxmvvm:MethodToCommandBehavior>
  30:                         </dxmvvm:Interaction.Behaviors>
  31:                     </dxb:BarButtonItem>
  32:                     <dxb:BarButtonItem 
  33:                         Content="Clear Sorting" 
  34:                         Glyph="{dx:DXImage Image=Clear_16x16.png}">
  35:                         <dxmvvm:Interaction.Behaviors>
  36:                             <dxmvvm:MethodToCommandBehavior 
  37:                                 Source="{Binding ElementName=gridControl}" 
  38:                                 Method="ClearSorting">                                
  39:                             </dxmvvm:MethodToCommandBehavior>
  40:                         </dxmvvm:Interaction.Behaviors>
  41:                     </dxb:BarButtonItem>
  42:                 </dxb:Bar>
  43:             </dxb:BarManager.Bars>
  44:             <Grid>
  45:                 <dxg:GridControl x:Name="gridControl" ... />
  46:             </Grid>
  47:         </dxb:BarManager>
  48:     </Grid>
  49: </UserControl>

In this code snippet, MethodToCommandBehavior’s Target and Command aren’t set. By default, MethodToCommandBehavior uses its associated object as target-object and the Command property of its associated object as target-command property. Therefore, initialization of these properties may be skipped. The Source property is bound to a source-object (GridControl) and the Method to the required GridControl method: SortBy or ClearSorting.

In fact, the SortBy has tree overloads. Since we use the overload method with two parameters, we must specify two parameters - using the Arg1 and Arg2 properties (maximum number of arguments is 15). Where possible, each specified parameter will be automatically converted to the parameterized type. For example, “Descending” will be converted to the ColumnSortOrder.

MethodToCommandBehavior also provide a CanExecuteFunction property that allows you to specify a Boolean function that considers whether the source-method can be executed in its current state.

To manually re-invoke the CanExecuteFunction you can use the following extension method.

   1: public static class POCOViewModelExtensions {
   2:     public static void UpdateMethodToCommandCanExecute<T>(this T viewModel, Expression<Action<T>> methodExpression) { … }
   3:
   4: }

The code snippet below illustrates use of CanExecuteFunction.

   1: UpdateMethodToCommandCanExecute(x => x.Operation());

Let’s now review how to define the MethodToCommandBehavior at design time.

The first step is to assign the MethodToCommandBehavior to the corresponding BarButtonItem.

1

The next step is to specify the source-object: Bind the Source property to GridControl by using the Binding Editor.

2

Once complete, select the required source-object method from the drop-down list.

3

Once the method is selected, the Smart Tag generates property lines for method arguments. Specify them in order.

4

Note that the Smart Tag generates property lines based on the maximum number of method arguments (you don’t need to specify them simultaneously).

The following is the generated code.

   1: <dxb:BarButtonItem 
   2:
   3:     <dxmvvm:Interaction.Behaviors>
   4:         <dxmvvm:MethodToCommandBehavior 
   5:             Source="{Binding ElementName=gridControl}" 
   6:             Method="SortBy"
   7:             Arg1="{Binding ElementName=gridControl,Path=CurrentColumn}" 
   8:             Arg2="Descending"/>
   9:     </dxmvvm:Interaction.Behaviors>
  10: </dxb:BarButtonItem>

An example that illustrates use of the MethodToCommandBehavior class can be found here.

Should you have any questions or need additional assistance feel free to share your comment with us. We’d love to hear what you think.

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.
Tags
No Comments

Please login or register to post comments.