Introduction
The main idea of tip is to make work with command more convinient in following:
- Command should be selfdescriptive and have description, tooltips, icons in itselt.
- It could be simply used with MWWM pattern.
- XAML should be as simple as possible.
Background
This article is a continuation of article previously posted http://www.codeproject.com/Tips/989373/INotifyPropertyChanged-convinient-implementation, because it uses code from it.
Using the code
To make work with commands simpler we should do following:
- Create class with will encapsulate all command properties and will implement
ICommand
interface.
- Create styles for different UI elements: buttons, menu buttons
- Combine all of that on the view.
Here is the implementation of Command (if you downloaded source code you already have it):
Download Command.zip
And example of command instance definition:
CommandA = new CommandT(
o =>
{
Status = "Command A Executing";
for (int i = 0; i < 10; i++)
{
Status = "Left to be disabled: {0}s".F(10 - i);
Thread.Sleep(1000);
}
},
o=>true,
err =>
{
this.ShowMessageBox(err.Message, err.StackTrace, MessageBoxButton.OK, MessageBoxImage.Error);
},
"Command A",
"Command A My long description",
R.TryGetImageSource("A"),
true);
Now we should create some styles, wich will use Command
properties:
<!---->
<Style TargetType="Button" x:Key="Buttons_CommandButtonBase" BasedOn="{StaticResource Common_ToolTipedElement}">
<Setter Property="we:ImageButtonExtension.ImageSource" Value="{Binding RelativeSource={RelativeSource Self}, Path=Command.Image}" />
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Command.ToolTip}" />
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}}" />
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource Converters_ObjectBooleanToVisibility}">
<Binding RelativeSource="{RelativeSource Self}" Path="Command" />
<Binding RelativeSource="{RelativeSource Self}" Path="Command.IsVisible" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
As you can see, Command - is view model to wich we make bindings, so UI will reflect to command properties changing.
Behind the scene there are many additional code (you can see it in test project), but our final view will be simple:
<StackPanel DataContext="{StaticResource VM}">
<GroupBox Header="Menu">
<Menu>
<MenuItem Command="{Binding CommandA}" Style="{StaticResource MenuButtons_BaseWithCommand}" />
<MenuItem Command="{Binding CommandB}" Style="{StaticResource MenuButtons_BaseWithCommand}" />
<MenuItem Header="Commands">
<MenuItem Command="{Binding CommandA}" Style="{StaticResource MenuButtons_BaseWithCommand}" />
<MenuItem Command="{Binding CommandB}" Style="{StaticResource MenuButtons_BaseWithCommand}" />
</MenuItem>
</Menu>
</GroupBox>
<GroupBox Header="Buttons" command:Command.DisableTarget="True">
<StackPanel>
<Button Command="{Binding CommandA}" Style="{StaticResource Buttons_BaseTextButtonWithCommand}"/>
<Button Command="{Binding CommandA}" Style="{StaticResource Buttons_BaseImageButtonWithCommand}"/>
<Button Command="{Binding CommandB}" Style="{StaticResource Buttons_BaseTextButtonWithCommand}"/>
<Button Command="{Binding CommandB}" Style="{StaticResource Buttons_BaseImageButtonWithCommand}"/>
</StackPanel>
</GroupBox>
<TextBlock Text="{Binding Status}" />
</StackPanel>
And final picture will look like this:
As you can see, everithing works on bindings (Icons, ToolTips, Headers)...
In the ViewModel we have just two commands, but we simply bind them to eight UI elements (buttons and menu buttons).
Test project contains several useful extensions and styles examples, they are simple so I will not type text too much, just try it...