It is always useful to have some common stereotype/boilerplate so that you can copy and paste and start something every quickly.
This is for RoutedCommand stenciles/templates.
there are three major steps involves with the RoutedCommand;
they are
- Declare/Define/Create the routed Command
- Set the Command property a Control can raise/trigger, e.g. <Button Command=...>
- Add/Remove the handler to the RoutedCommand, through the use CommandBinding
In the following example, we are going to create Custom RoutedCommand, and we are going to give it name "OKCommand";
The RoutedComand Static Field Approach
Since in Xaml the CommandBinding's Command Property is a static field, you could not use a Binding Element on the Command attribute of CommandBindings;
So it is recommended to use Static Field for the RoutedCommands;
private static RoutedCommand m_okCommand;
public static RoutedCommand OKCommand
{
get
{
return m_okCommand != null ? m_okCommand : (m_okCommand = new RoutedCommand("OKCommand", typeof(MainWindow)));
}
}
and you use the x:Static Xaml directive to pick up the ICommand
<Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{x:Static local:MainWindow.OKCommand}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
<Button.CommandBindings>
<CommandBinding
Command="{x:Static local:MainWindow.OKCommand}"
CanExecute="OKCommandCanExecute"
Executed="OKCommandExecuted"
>
</CommandBinding>
</Button.CommandBindings>
<Button.InputBindings>
<KeyBinding Gesture="Alt+O"
Command="{x:Static local:MainWindow.OKCommand}">
</KeyBinding>
</Button.InputBindings>
</Button>
Except setting the command bindings through the use of Xaml, you can also do it via code inside the CLR code. Below is one example.
public MainWindow()
{
InitializeComponent();
this.CommandBindings.Add(new CommandBinding(
OKCommand,
OKCommandExecuted,
OKCommandCanExecute)
);
}
As you can see, this is the most common way of using the RoutedCommand.
A slightly better way is to move the RoutedCommand out of the MainWindow and put into a separate class which can be shared by many classes.
Following the discussion, we will move the commands to another class called Commands;
namespace AcceptOrCancelButton
{
public class Commands : DependencyObject
{
private static RoutedCommand m_okCommand;
public static RoutedCommand OKCommand
{
get
{
return m_okCommand != null ? m_okCommand : (m_okCommand = new RoutedCommand("OKCommand", typeof(MainWindow)));
}
}
}
}
The Dependency Property approach
DependencyProperty the key is a public static readonly field, the metadata is associated with the owner class as well, but the CLR accessor is associated with the class intance, and this is creating a issue for us iin Xaml.
Suppose now the Commands class is like this:
namespace AcceptOrCancelButton
{
public class Commands : DependencyObject
{
public RoutedCommand OKCommand
{
get { return (RoutedCommand)GetValue(OKCommandProperty); }
set { SetValue(OKCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for OKCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OKCommandProperty =
DependencyProperty.Register("OKCommand", typeof(RoutedCommand), typeof(Commands), new UIPropertyMetadata(new RoutedCommand("OKCommand", typeof(Commands))));
}
}
In xaml , the following won't work.
<Window x:Class="AcceptOrCancelButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AcceptOrCancelButton"
x:Name="Self"
>
<Window.CommandBindings>
<CommandBinding
Command="{Binding Path=OKCommand, ElementName=Self}"
CanExecute="OKCommandCanExecute"
Executed="OKCommandExecuted"
>
</CommandBinding>
</Window.CommandBindings>
</Window>
You will see the following error at runtime.
A 'Binding' cannot be set on the 'Command' property of type 'CommandBinding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
however, you can still use the code to do the bindings;
namespace AcceptOrCancelButton
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.CommandBindings.Add(new CommandBinding(
Commands.OKCommand,
OKCommandExecuted,
OKCommandCanExecute)
);
}
private Commands m_commands = new Commands();
public Commands Commands { get { return m_commands; } }
}
}
the UIElement do has the Command as DependencyProperty, so that you can do the following.
<Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{Binding Path=Commands.OKCommand, ElementName=Self}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
<Button.InputBindings>
<KeyBinding Gesture="Alt+O"
Command="{Binding Path=Commands.OKCommand, ElementName=Self}">
</KeyBinding>
</Button.InputBindings>
</Button>
However, if you do want to achieve this in Xaml (if you are paranoid for no reason).
the key is the StaticResource
<Window x:Class="AcceptOrCancelButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AcceptOrCancelButton"
Title="MainWindow" Height="350" Width="525"
x:Name="Self"
>
<Window.Resources>
<RoutedCommand x:Key="MyCommand" />
<local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
<!--<local:Commands.OKCommand>
<StaticResource ResourceKey="MyCommand"></StaticResource>
</local:Commands.OKCommand>-->
</local:Commands>
</Window.Resources>
<StackPanel>
<!-- With the help of Click Event, prove cancel and default button works -->
<!--<Button x:Name="OKButton" IsDefault="True" Content="OK" Click="OkClick"/>
<Button x:Name="CancelButton" IsCancel="True" Content="Cancel" Click="CancelClick"/>-->
<!-- With the help of Static Routed Comand, prove cancel and default button works -->
<Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{StaticResource MyCommand}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
<Button.CommandBindings>
<CommandBinding
Command="{StaticResource MyCommand}"
CanExecute="OKCommandCanExecute"
Executed="OKCommandExecuted"
>
</CommandBinding>
</Button.CommandBindings>
<Button.InputBindings>
<KeyBinding Gesture="Alt+O"
Command="{StaticResource MyCommand}">
</KeyBinding>
</Button.InputBindings>
</Button>
</StackPanel>
</Window>
You can only use StaticResource, you cannot use DynamicResource, because DynamicResource requires that the target property is a DependencyProperty;
Tricks to use AttachedDependencyProperty
You can create a Attached Dependency Property,which indicate if the element that the attached property is applied will be bound to a known RoutedCommand (in this example), the known RoutedCommand is the defined in the Resources.
here is the code.
public static bool GetIsOKCommandSource(DependencyObject obj)
{
return (bool)obj.GetValue(IsOKCommandSourceProperty);
}
public static void SetIsOKCommandSource(DependencyObject obj, bool value)
{
obj.SetValue(IsOKCommandSourceProperty, value);
}
// Using a DependencyProperty as the backing store for IsOKCommandSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsOKCommandSourceProperty =
DependencyProperty.RegisterAttached("IsOKCommandSource", typeof(bool), typeof(MainWindow), new UIPropertyMetadata(false, OnIsOkCommandSourceChanged));
public static void OnIsOkCommandSourceChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
//Button button = dep as Button;
Button button = dep as Button;
if (button != null)
{
var command = ((Commands)button.TryFindResource("Commands")).OKCommand;
button.Command = command;
button.CommandTarget = button;
}
}
}
and you have the following xaml which basically create the resource, create the Command handlers, and use the attach dependency property.
<Window x:Class="AcceptOrCancelButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AcceptOrCancelButton"
Title="MainWindow" Height="350" Width="525"
x:Name="Self"
>
<Window.Resources>
<RoutedCommand x:Key="MyCommand" />
<local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
</local:Commands>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="{StaticResource MyCommand}"
CanExecute="OKCommandCanExecute"
Executed="OKCommandExecuted"
>
</CommandBinding>
</Window.CommandBindings>
<StackPanel>
<Button x:Name="OKButton" local:MainWindow.IsOKCommandSource="True" IsDefault="True" Content="OK">
</Button>
</StackPanel>
</Window>
Another way to use the Attached Dependency Property is as follow. -- this is not IDEAL, tend to remove
public static RoutedCommand GetOkCommand(DependencyObject obj)
{
return (RoutedCommand)obj.GetValue(OkCommandProperty);
}
public static void SetOkCommand(DependencyObject obj, RoutedCommand value)
{
obj.SetValue(OkCommandProperty, value);
}
// Using a DependencyProperty as the backing store for OkCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OkCommandProperty =
DependencyProperty.RegisterAttached("OkCommand", typeof(RoutedCommand), typeof(MainWindow), new UIPropertyMetadata(null, OnOKCommandChanged));
public static void OnOKCommandChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
if (dep is ICommandSource)
{
var parent = GetParent(dep, typeof(MainWindow)) as MainWindow;
if (dep.GetType() == typeof(Button))
{
Button button = (Button)dep;
button.Command = (RoutedCommand)e.NewValue;
button.CommandTarget = button;
button.CommandBindings.Add(new CommandBinding(button.Command, parent.OKCommandExecuted, parent.OKCommandCanExecute));
}
}
}
} public static DependencyObject GetParent(DependencyObject obj, Type parentType)
{
DependencyObject parent = obj ;
if (obj == null) return null;
Type type = obj.GetType();
while (type != parentType)
{
parent = LogicalTreeHelper.GetParent(parent);
if (parent != null) type = parent.GetType();
else return null;
}
return parent;
}
and the xaml
<Window x:Class="AcceptOrCancelButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AcceptOrCancelButton"
Title="MainWindow" Height="350" Width="525"
x:Name="Self"
>
<Window.Resources>
<RoutedCommand x:Key="MyCommand" />
<local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
</local:Commands>
</Window.Resources>
<StackPanel>
<Button x:Name="OKButton" local:MainWindow.OkCommand="{Binding Source={StaticResource MyCommand}}" IsDefault="True" Content="OK" />
</StackPanel>
</Window>
The last attached event I am thinking of is of type CommandBinding; Please see below.
public static CommandBinding GetOKCommandBinding(DependencyObject obj)
{
return (CommandBinding)obj.GetValue(OKCommandBindingProperty);
}
public static void SetOKCommandBinding(DependencyObject obj, CommandBinding value)
{
obj.SetValue(OKCommandBindingProperty, value);
}
// Using a DependencyProperty as the backing store for OKCommandBinding. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OKCommandBindingProperty =
DependencyProperty.RegisterAttached("OKCommandBinding", typeof(CommandBinding), typeof(MainWindow), new UIPropertyMetadata(null, OnOKCommandBindingChanged));
public static void OnOKCommandBindingChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
if (dep.GetType() == typeof(Button))
{
var button = (Button)dep;
button.CommandBindings.Clear();
button.CommandBindings.Add((CommandBinding)e.NewValue);
}
}
}
and the Xaml
<Window x:Class="AcceptOrCancelButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AcceptOrCancelButton"
Title="MainWindow" Height="350" Width="525"
x:Name="Self"
>
<Window.Resources>
<RoutedCommand x:Key="MyCommand" />
<local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
</local:Commands>
<CommandBinding x:Key="OKCommandBinding"
Command="{StaticResource MyCommand}"
Executed="OKCommandExecuted"
CanExecute="OKCommandCanExecute"
>
</CommandBinding>
</Window.Resources>
<StackPanel>
<Button x:Name="OKButton" local:MainWindow.OKCommandBinding="{StaticResource OKCommandBinding}" Command="{StaticResource MyCommand}" IsDefault="True" Content="OK" />
</StackPanel>
</Window>
路由命令
6895

被折叠的 条评论
为什么被折叠?



