After your opinion I’ve become a DelegateCommand disciple J but I also didn’t like the idea of loosing DisplayText and InputBindings so after some thinking I implemented this…
I’ve created a IBindableCommand interface that inherits from ICommand and added the properties I need:
interface IBindableCommand:ICommand
{
string DisplayText { get; set; }
InputBindingCollection InputBindings { get; set; }
}
Then created a custom markup extension that does all the funky stuff for me:
[MarkupExtensionReturnType(typeof(IBindableCommand))]
public class BindCommand : MarkupExtension
{
private string commandName;
public BindCommand(string commandName)
{
this.commandName = commandName;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget pvt = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (pvt != null)
{
FrameworkElement fe = pvt.TargetObject as FrameworkElement;
fe.Loaded += new RoutedEventHandler(HandleLoaded);
}
return null;
}
private void HandleLoaded(object sender, RoutedEventArgs e)
{
FrameworkElement fe = (sender as FrameworkElement);
//Use reflection to retrieve provided Command
PropertyInfo property = fe.DataContext.GetType().GetProperty(this.commandName);
IBindableCommand command = (IBindableCommand)property.GetValue(fe.DataContext, null);
ICommandSource source = sender as ICommandSource;
if (source != null)
{
//Button
Button button = fe as Button;
if (button != null)
{
button.Content = command.DisplayText;
button.Command = command;
foreach (InputBinding ib in command.InputBindings)
{
button.InputBindings.Add(ib);
}
}
else if (fe as MenuItem != null)
{
//MenuItem
MenuItem menuItem = fe as MenuItem;
menuItem.Command = command;
menuItem.Header = command.DisplayText;
//Handle MenuItem Inputbindings
if (command.InputBindings != null)
{
KeyGesture keyGesture = command.InputBindings[0].Gesture as KeyGesture;
menuItem.InputGestureText = keyGesture.DisplayString;
foreach (InputBinding ib in command.InputBindings)
{
menuItem.InputBindings.Add(ib);
}
}
}
}
//De-register loaded event
fe.Loaded -= HandleLoaded;
}
}
It’s basically a mix of a markup extension and attached behavior, but using this I’ve a more friendly approach of applying a Command, like this:
<Button
Command="{local:BindCommand MoveNextCommand}"
Margin="0,0,10,0"
HorizontalAlignment="Right" />
Where “MoveNextCommand” is the property of my ViewModel that exposes the DelegateCommand implementing IBindableCommand:
public class DelegateCommand: IBindableCommand
{
}
Of course there is the obvious limitation that it applies only to MenuItems and Buttons, but maybe you have a smart ideas about how can make it more generic.
What do you think?
Corrado
I did it, but I have no InputBindings and other stuff…
Corrado