BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Commanding - Creating Custom Commands

The one hundred and sixty-fifth part of the Windows Presentation Foundation Fundamentals tutorial continues the description of commanding. This article explains the process for creating custom commands and binding them to controls.

Commanding

In the previous article we started to look at commanding in WPF. This feature allows you to attach commands to controls so that they execute when the user interacts with menus, buttons and similar items. In the earlier article, we saw how to use standard commands that are provided by the .NET framework, such as cut, copy and paste.

Commanding is much more powerful when you create your own commands. As with standard commands, the ones that you develop can include the command's functionality and code that determines when the command is available. When it is not, any controls and keyboard shortcuts that are linked to the control are automatically disabled.

In this article we will create a simple example program that demonstrates the process for creating and using custom commands. To begin, create a new WPF application in Visual Studio. Name the project, "CustomCommandsDemo". Once prepared, replace the XAML in the main window with the code below:

<Window x:Class="CustomCommandsDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Commanding Demo" Height="250" Width="300">
    <Window.Resources>
        <Style TargetType="Label">
            <Setter Property="Margin" Value="5" />
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="Background" Value="Azure" />
            <Setter Property="Margin" Value="5 5 5 0" />
            <Setter Property="Padding" Value="5" />
        </Style>
        <Style TargetType="Button">
            <Setter Property="HorizontalAlignment" Value="Right" />
            <Setter Property="Margin" Value="5" />
            <Setter Property="Width" Value="90" />
        </Style>
    </Window.Resources>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label>First Name</Label>
        <TextBox Grid.Column="1"
                 Text="{Binding FirstName,UpdateSourceTrigger=PropertyChanged}" />

        <Label Grid.Row="1">Last Name</Label>
        <TextBox Grid.Column="1" Grid.Row="1"
                 Text="{Binding LastName,UpdateSourceTrigger=PropertyChanged}" />

        <StackPanel Grid.ColumnSpan="2" Grid.Row="2" Orientation="Horizontal"
                    HorizontalAlignment="Right">
            <Button>Add</Button>
            <Button>Remove</Button>
        </StackPanel>

        <Label Grid.Row="3">Names</Label>
        <ListBox Grid.Column="1" Grid.Row="3" ItemsSource="{Binding Names}"
                    SelectedItem="{Binding SelectedName}" Margin="5 0" Background="Azure"/>

        <Button Grid.ColumnSpan="2" Grid.Row="4">Info</Button>
    </Grid>
</Window>

The above XAML creates a window with several text boxes and buttons, and a list box. It provides the basis for a standard user interface pattern in Windows, allowing items to be entered into simple controls, then added to or removed from a list. You can see that the input controls include data binding expressions. These will be linked to an object using the window's data context.

Create a new class file for the data context named, "NameList". Replace the standard class with the code below.

public class NameList : INotifyPropertyChanged
{
    string _firstName = "";
    string _lastName = "";
    string _selectedName;

    public NameList()
    {
        Names = new ObservableCollection<string>();
    }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName != value)
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (_lastName != value)
            {
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }
    }

    public string SelectedName
    {
        get { return _selectedName; }
        set
        {
            if (_selectedName != value)
            {
                _selectedName = value;
                OnPropertyChanged("SelectedName");
            }
        }
    }

    public ObservableCollection<string> Names { get; private set; }

    private void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

The NameList class includes all of the properties required for the existing data bindings. They will hold the first and last names of a person before they are added to the list, the collection of names and a string that contains the selected name from the list. The class implements INotifyPropertyChanged so that property changes made in code cause the user interface to update accordingly.

To link the user interface to an instance of the NameList class, modify the constructor of the main window, as shown below:

public MainWindow()
{
    InitializeComponent();
    DataContext = new NameList();
}

The initial version of the demonstration program is now complete. Running the program should generate a window similar to the following image. The buttons perform no actions

WPF Custom Commands Demo Window

14 June 2015