Reputation: 466
Let's say I'm not allowed to use default wpf classes RoutedCommand, CommandBinding and ICommand interface. Instead I must provide my own implementation. So I specify simple ICommand interface:
public interface ICommand
{
void Execute();
}
Make a class for specific command:
public class NewCommand : ICommand
{
private readonly IReceiver _receiver;
// receiver is any class that provides implementation of a New() method
public NewCommand(IReceiver receiver)
{
_receiver = receiver;
}
public void Execute()
{
_receiver.New();
}
}
There must be an Invoker as well:
public class Invoker
{
private ICommand _command;
public void SetCommand(ICommand c)
{
_command = c;
}
public void Run()
{
_command.Execute();
}
}
How do I wire this all to XAML considering that with default implementation my code looks like this:
public class DesignerCanvas : Canvas
{
private readonly IDesignerCommandsReceiver _receiver;
public DesignerCanvas()
{
_receiver = new DesignerCommandsReceiver(this);
CommandBindings.Add(new CommandBinding(ApplicationCommands.New, New_Executed));
}
private void New_Executed(object sender, ExecutedRoutedEventArgs e)
{
_receiver.New();
}
}
And the button that invokes New command is binded like:
<Button Margin="3" Width="55" Style="{StaticResource ToolBarButtonBaseStyle}"
Command="{x:Static ApplicationCommands.New}"
CommandTarget="{Binding ElementName=MyDesigner}">
<Button.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Image Source="Images/GenericDocument.png" Width="45"/>
<TextBlock Grid.Row="1" Text="New" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</Grid>
</Button.Content>
</Button>
How do I bind my NewCommand class if Command attribute expects class that implements System.Windows.Input.ICommand? Where do I create instance of Invoker, set NewCommand and Run it? Generally speaking, I'm a little confused about how to replace default implementation of the pattern with my own. Any advices are welcome.
Upvotes: 0
Views: 982
Reputation: 128136
Although I doubt that it really makes sense to have a custom command interface and implementation, you could probably create a custom attached Command
property, which attaches a Click
handler in its PropertyChangedCallback. The Click handler would then execute the custom command.
The following code sample declares a custom ICustomCommand
interface, and declares an attached Command
property in a static CustomCommandEx
class.
public interface ICustomCommand
{
void Execute();
}
public static class CustomCommandEx
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICustomCommand),
typeof(CustomCommandEx),
new PropertyMetadata(CommandPropertyChanged));
public static ICustomCommand GetCommand(DependencyObject obj)
{
return (ICustomCommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICustomCommand value)
{
obj.SetValue(CommandProperty, value);
}
private static void CommandPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
{
var button = obj as ButtonBase;
var command = eventArgs.NewValue as ICustomCommand;
if (button != null)
{
button.Click += (s, e) => command.Execute();
}
}
}
You would assign the attached property like this:
<Button local:CustomCommandEx.Command="{Binding SomeCommand}"/>
where SomeCommand
is a property in your view model that implements ICustomCommand
.
Upvotes: 1