Click here to Skip to main content
15,867,594 members
Articles / Desktop Programming / WPF

DelegateCommand and CompositeCommand in Prism

Rate me:
Please Sign up or sign in to vote.
4.96/5 (19 votes)
29 Dec 2015CPOL7 min read 53.9K   927   16   12
In this article, we will learn about DelegateCommand and CompositeCommand provided by Prism Framework. To grasp the concept, we will create a simple demo with minimum functionality to highlight these concepts.

Introduction

In this article, we will learn about DelegateCommand and CompositeCommand provided by Prism Framework. Particularly CompositeCommand is a very simple concept. But when start learning Prism, we see it included in examples having lot of other functionalities/features too (i.e. standard examples given with Prism), so it is difficult to grasp the concept quickly. In this article we will create a simple demo with minimum functionality to highlight these concepts only so that it would be easy to understand.

Prism framework frequently is used in WPF/Silverlight application with MVVM pattern. Before going into core concepts of this article, first we will have quick introduction to Prism framework. Then we will create demo application and use DelegateCommand and CompositeCommand.

Note: For this article, as prerequisite we must have basic understanding of WPF and ICommand interface. If you are new to ICommand interface, please have a look at this article.

Outlines

  • What is Prism Framework
  • Overview of Demo Application
  • What is DelegateCommand
  • Use of DelegateCommand
  • What is CompositeCommand
  • Use of CompositeCommand

What is Prism Framework

Prism is a framework for building "Composite Applications” using WPF/Silverlight. Prism framework provides a set of libraries which helps us in building modular enterprise applications. By using those libraries, we can categories application into multiple modules, load them as per need and orchestrate them very easily. For more learning about Prism, please have a look at Prism Basic Introduction and Prism Page on MSDN, and few more things about Prism.
 

What is DelegateCommand

DelegateCommand is a class which comes with Prism framework. It is found under “Microsoft.Practices.Prism.Commands” namespace. DelegateCommand class inherits DelegateCommandBase abstract class. DelegateCommandBase class implements ICommand and IActiveAware interface. This way by using DelegateCommand we can achieve the same what we achieved with RelayCommand as we did in previous article. And few additional possibilities are also available with DelegateCommand. So if we are using Prism then it is not necessary to create a generic command class (like RelayCommand) instead we must use DelegateCommand class.  Now let us create a demo application with DelegateCommand.

Overview of Demo Application

Demo application is having simple layout with 3 Buttons, 8 TextBlocks. 2 TextBlocks are used to display numbers and 6 TextBlocks are used to display information as plain text. On button click, the number in respective TextBlock will be increamented upto a certain upper limit.

When we click on “Increment - First” button, it increments numbers in first TextBlock. For first TextBlock, numbers can be incremented till 5 (as max number) then button get disabled.

When we click on “Increment - Second” button, it increments numbers in second TextBlock. For second TextBlock, numbers can be incremented till 10 (as max number) then button get disabled.

When we click on “Increment - All” button, it increments numbers in both TextBlocks.

We will see how DelegateCommand and CompositeCommand are used to achieve the above functionality. Final screen shot of demo application:

Final Screen Shot of Demo App
 

Let us build Demo App

Now open Visual Studio to create demo application, please follow below steps:

Note: When we build any Prism based application, we need take care of matching/compatible versions .NET version for a given Prism version. While creating the demo for this article, we targeted .NET framework 4 and Prism 4. So attached code will work with Visual Studio 2010 and newer versions of Visual Studio without additional setup. The concept of DelegateCommand and CompositeCommand is same in all Prism versions.

Create a WPF application named as "CompositeDemoApp" by targeting .NET 4.0. In this demo application we are going to use DelegateCommand and CompositeCommand which are inbuilt classes given by Prism framework. So to use them we need to download Prism framework 4. This Nuget page describes how to download Prism framework 4.

Let us download prism 4.0 by using “Package Manager Console” as shown in below screen shot.

Navigate Package Mangare Console

Click enter on Package Manager Console option, Package Manager Console window will be opened. Now write following command in Package Manager Console window and press enter.

Install-Package Prism -Version 4.0.0

Required libraries will be downloaded and message will be displayed like “Successful Installed Prism 4.0.0.0” as shown below:

Command to Download Prism

If you go to References folder, you can see Prism related libraries will be referenced to this project automatically.

Now add ViewModel folder in root of project then add a file called as CalculationViewModel.cs, we will write code in this file in further steps.

Write following xaml code in MainWindow.xaml file which will create UI for us. Code is very simple so we assume it is self-explanatory.

<Grid DataContext="{StaticResource calculationVM}" Background="LightBlue">
        <Grid.RowDefinitions>
            <RowDefinition ></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="80"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.Column="1" Grid.RowSpan="5">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF83FF97" Offset="0" />
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Grid.Column="2" Grid.RowSpan="5">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Yellow"  Offset="0" />
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Row="0" FontSize="18"  Grid.Column="0" Margin="5" Height="30" Text="Values"></TextBlock>
        <TextBlock Grid.Row="0"  Grid.Column="1" FontSize="16"  Background="LightGreen" Margin="5" 
                   HorizontalAlignment="Center" TextAlignment="Center" Width="120" Height="30" 
                   Text="{Binding FirstInput, Mode=TwoWay}">
        </TextBlock>
        <TextBlock Grid.Row="0"  Grid.Column="2" FontSize="16"  Background="BlanchedAlmond"  Margin="5" 
                   HorizontalAlignment="Center" TextAlignment="Center" Width="120" Height="30" 
                   Text="{Binding SecondInput, Mode=TwoWay}">
        </TextBlock>

        <TextBlock Grid.Row="1" FontSize="18"  Grid.Column="0" Margin="5" Height="30" Text="Individual Commands"></TextBlock>
        <Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" Margin="5" Width="120" Height="30" 
                Content="Increment - First" Command="{Binding FirstIncrementCommand}">
        </Button>
        <Button Grid.Row="1" Grid.Column="2"  HorizontalAlignment="Center"  Margin="5" Width="120" Height="30"
                Content="Increment - Second" Command="{Binding SecondIncrementCommand}">
        </Button>

        <TextBlock Grid.Row="2" FontSize="18"  Grid.Column="0" Margin="5" Height="30" Text="Composite Commands"></TextBlock>
        <Button Grid.Row="2" Grid.Column="1" FontSize="16" Grid.ColumnSpan="2" Margin="10,5,10,5" 
                HorizontalAlignment="Center" Width="240"  Height="30" Content="Increment - All" 
                Command="{Binding AllIncrementCommand}">
        </Button>

        <TextBlock Grid.Row="3" FontSize="18"  Grid.Column="0" Margin="5" Height="30" Text="Information"></TextBlock>
        <TextBlock Grid.Row="3" FontSize="16"  Grid.Column="1" Margin="5" Foreground="OrangeRed" 
                   TextWrapping="Wrap" Text="First value can be increamented till 5.">
        </TextBlock>
        <TextBlock Grid.Row="3" FontSize="16"  Grid.Column="2" Margin="5" Foreground="OrangeRed" 
                   TextWrapping="Wrap" Text="Second value can be increamented till 10.">
        </TextBlock>
    </Grid>

Provide namespace of CalculationViewModel in MainWindow.xaml.

xmlns:vm ="clr-namespace:CompositeDemoApp.ViewModel"
<Window.Resources>
   <vm:CalculationViewModel x:Key="calculationVM">
   </vm:CalculationViewModel>
   <Style TargetType="{x:Type Button}">
       <Setter Property="Foreground" Value="Blue"/>
       <Setter Property="IsEnabled" Value="True"/>
       <Style.Triggers>
           <Trigger Property="IsEnabled" Value="false">
               <Setter Property="Foreground" Value="#FFADADAD"/>
           </Trigger>
       </Style.Triggers>
   </Style>
</Window.Resources>

Instead of writing ViewModelBase class as we did in previous article., we will use "NotificationObject". This class is provided by Prism Framework under "Microsoft.Practices.Prism.ViewModel" namespace. It implements INotifyPropertyChanged interface. This is standard interface which we must implement whenever we will need to notify objects (UI or ViewModels) about update in properties values. Now inherit CalculationViewModel from NotificationObject class.

In MainWindow.xaml file, we have bound UI properties with CalculationViewModel properties. CalculationViewModel’s property “FirstInput” is bound with "Text" property of first TextBlock, CalculationViewModel’s property “SecondInput” is bounded with "Text" property of second TextBlock. Now we need to create implement those properties in CalculationViewModel.

private int firstInput;
private int secondInput;
public int FirstInput
{
    get
    {
        return firstInput;
    }
    set
    {
        firstInput = value;
        RaisePropertyChanged("FirstInput");
    }
}
public int SecondInput
{
    get
    {
        return secondInput;
    }
    set
    {
        secondInput = value;
        RaisePropertyChanged("SecondInput");
    }
 }

Now on “Increment - First” or “Increment - Second” button click, we want increment number bound with “FirstInput” or “SecondInput” TextBlock. For that we need to use command while button click that we will do with DelegateCommand in next section.

Use of DelegateCommand

For using DelegateCommand, we first need to create private fields correspondent to each command with type of DelegateCommand. In our case we need two DelegateCommand for two buttons called “Increment – First” and “Increment – Second” as shown below.

private DelegateCommand firstIncrementCommand;
private DelegateCommand secondIncrementCommand;
public DelegateCommand FirstIncrementCommand
{
    get { return firstIncrementCommand; }
}
public DelegateCommand SecondIncrementCommand
{
    get { return secondIncrementCommand; }
}

Inside the constructor of CalculationViewModel we need to instantiate the commands, so write below lines of code

firstIncrementCommand = new DelegateCommand(incrementFirstInput, canIncrementFirstInput);
secondIncrementCommand = new DelegateCommand(incrementSecondInput, canIncrementSecondInput);

Here we are creating an instance of DelegateCommand class. As arguments it takes two methods name as a delegate. For firstIncrementCommand we are passing name of method called incrementFirstInput as first argument, which is having actual logic what we want to perform on “Increment – First” button click. And as second argument we are passing name of method called canIncrementFirstInput name, which will decide whether Cammand should be enabled or disabled. Those which will be fired while Exceute and CanExecute will be invoked of respective commands. Now implement these two methods.

 private void incrementFirstInput()
 {
     FirstInput += 1;
     FirstIncrementCommand.RaiseCanExecuteChanged();
 }
 // Enable Increment - First button only if first value is less than 5
private bool canIncrementFirstInput()
 {
     bool ifFirstInputLessThan5 = firstInput < 5;
     return ifFirstInputLessThan5;
 }

Same way, we need to implement two methods to be executed on “Increment – Second” button command - SecondIncrementCommand.

private void incrementSecondInput()
{
     SecondInput += 1;
     SecondIncrementCommand.RaiseCanExecuteChanged();
}
// Enable Increment - Second button only if second value is less than 10
private bool canIncrementSecondInput()
{
     bool ifSecondInputLessThan10 = secondInput < 10;
     return ifSecondInputLessThan10;
}

Now run the application. Click on “Increment – First” or “Increment – Second” button, we will see numbers are incrementing till 5 in first TextBlock and numbers are incrementing till 10 in second TextBlock respectively.

So far, in this demo application when we click on “Increment – First” button click, number is increasing in first TextBlock and “Increment – Second” button click, number is increasing in second TextBlock.

Now we want to increment number in both TextBlocks on a single button click by reusing code for functionalities which we have implemented for “Increment – First” and “Increment – Second” button click. Such kind of reusability can be achieved by using CompositeCommand. Let us understand CompositeCommand.

What is CompositeCommand

CompositeCommand is a class which can have multiple child commands in itself. It provides facility to execute all associated methods (Execute and CanExecute) of child commands. If any CanExecute method of child command returns false, then no child command will be executed.

For example, CompositeCommand is having 5 child commands, if any one of associated CanExecute method of child command returns false, CompositeCommand will not be enabled/executed.

Use of CompositeCommand

To use CompositeCommand, first create private field of CompositeCommand:

private CompositeCommand allIncrementCommand;

Inside the constructor of CalculationViewModel create instance of CompositeCommand class. Thenregister firstIncrementCommand and secondIncrementCommand to CompositeCommand. Here firstIncrementCommand and secondIncrementCommand are child commands.

allIncrementCommand = new CompositeCommand();
allIncrementCommand.RegisterCommand(firstIncrementCommand);
allIncrementCommand.RegisterCommand(secondIncrementCommand);

Now create one more public command in CalculationViewModel so that we can bind it in UI code, as shown below.

public CompositeCommand AllIncrementCommand
{
    get { return allIncrementCommand; }
}

Since AllIncrementCommand command is bound to “Increment – All” button in Ul, those two child commands automatically will be executed with their associated methods whenever AllIncrementCommand will be fired.
Now run the application. Click on “Increment – All” button, we will see numbers are incrementing in both TextBlocks till 5. After it “Increment – First” and “Increment – All” button get disabled but “Increment – Second” button is still enable.

This is happening because canIncrementFirstInput method of first child command (called firstIncrementCommand) returns false after FirstInput is 5. As we explained before, CompositeCommand will not work if CanExcecute method of any child command returns false.

Conclusion

In this article, we learned about DelegateCommand and CompositeCommand in Prism based applications and how to use those along with MVVM pattern. Your comments/suggestions and queries are most welcome. Thanks.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
I am a Software Developer working on Microsoft technologies. My interest is exploring and sharing the awesomeness of emerging technologies.

Comments and Discussions

 
QuestionMessage Closed Pin
18-Nov-20 6:19
Member 1499644918-Nov-20 6:19 
QuestionMerci beaucoup Pin
said0114-Apr-20 15:22
said0114-Apr-20 15:22 
PraiseVery Nice explanation Pin
Member 1297557021-Jun-17 3:12
Member 1297557021-Jun-17 3:12 
AnswerRe: Very Nice explanation Pin
Snesh Prajapati21-Jun-17 4:25
professionalSnesh Prajapati21-Jun-17 4:25 
PraiseFantastic Pin
Rabbles24-Jan-17 2:34
Rabbles24-Jan-17 2:34 
AnswerRe: Fantastic Pin
Snesh Prajapati24-Jan-17 15:50
professionalSnesh Prajapati24-Jan-17 15:50 
QuestionNice article Pin
Amit K Thakur4-Oct-16 16:05
Amit K Thakur4-Oct-16 16:05 
AnswerRe: Nice article Pin
Snesh Prajapati4-Oct-16 16:12
professionalSnesh Prajapati4-Oct-16 16:12 
GeneralMy vote of 5 Pin
Santhakumar M13-Nov-15 4:21
professionalSanthakumar M13-Nov-15 4:21 
AnswerRe: My vote of 5 Pin
Snesh Prajapati13-Nov-15 12:48
professionalSnesh Prajapati13-Nov-15 12:48 
GeneralRe: My vote of 5 Pin
Santhakumar M13-Nov-15 21:39
professionalSanthakumar M13-Nov-15 21:39 
PraiseVery nice Pin
viler8412-Nov-15 14:38
viler8412-Nov-15 14:38 
AnswerRe: Very nice Pin
Snesh Prajapati12-Nov-15 14:54
professionalSnesh Prajapati12-Nov-15 14:54 
Thanks a lot for kind words.

Yes, you got it right....while I started learning PRISM, I faced this issue that in a given example there, lot of things are mixed so first we need to look for basic understanding of other things too. Anyway, PRISM is great library with loads of concepts.

Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.