tags:

views:

233

answers:

2

Hi,

I have a custom control that has an event. I have a window using that custom control. The window is bound to a viewmodel. I would like to have the event from the custom control direct to an ICommand on my viewmodel. I am obviously being dense here as I can't figure out how to do this. Any assistance is most welcome.

Thanks

+1  A: 

Hi,

If you want to route an event to a command you can use an attached property. I used this example to add command support to a ComboBox SelectionChanged event:

http://blog.fossmo.net/post/How-to-create-an-attached-property-in-WPF-using-a-ComboBox.aspx

Cheers.

chibacity
A: 

If it's a one-off, you can use a simple event handler:

<some:CustomControl SuperDuper="OnSuperDuper" />

with code behind

private void OnSuperDuper(object sender, EventArgs e)
{
  _theCommand.Execute(null, (IInputElement)sender);
}

If you want to do this multiple times for a specific event I would use an attached property.

<some:CustomControl my:AttachedEvents.SuperDuperCommand="{Binding TheCommand}" />

where the attached property is simply:

// use propa snippet to build this quickly
public static ICommand GetSuperDuperCommand(DependencyObject obj) { return (ICommand)obj.GetValue(SuperDuperCommandProperty); }
public static void SetSuperDuperCommand(DependencyObject obj, ICommand value) { obj.SetValue(SuperDuperCommandProperty, value); }
public static readonly SuperDuperCommandProperty = DependencyProperty.RegisterAttached("SuperDuperCommand", typeof(ICommand), typeof(AttachedEvents), new PropertyMetadata
{
  PropertyChangedCallback = (obj, e) =>
  {
    if(oldCommand==null) ((CustomControl)obj).SuperDuper += OnSuperDuper;
    if(newCommand==null) ((CustomControl)obj).SuperDuper -= OnSuperDuper;
  }
});

private void OnSuperDuper(object sender, EventArgs e)
{
  var control = (CustomControl)sender;
  GetSuperDuperCommand(sender).Execute(null, sender));
}

You may be able to further generalize this to map any event to any command using a MarkupExtension. Here's the idea:

<some:CustomControl SuperDuper="{lib:CommandWrapper {Binding TheCommand}}" />

The code is like this:

public class CommandWrapper : MarkupExtension
{
  public BindingBase CommandBinding { get; set; }

  public CommandWrapper() {}
  public CommandWrapper(BindingBase commandBinding) { CommandBinding = commandBinding; }

  public object ProvideValue(IServiceProvider serviceProvider)
  {
    return new EventHandler((obj, e) =>
    {
      // Evaluate CommandBinding against obj, fire command
    });
  }
}

You can flesh out the details. Note that instead of simply saying "new EventHandler" you may want to pass the actual event handler type into CommandWrapper and use reflection to construct the appropriate delegate.

I'm not completely sure the XAML parser will let you set an event using a MarkupExtension, so this last solution may not actually work this simply. But if not, it can be combined with an attached property like so:

<some:CustomControl lib:CommandWrapper.Add="{lib:CommandWrapper SuperDuper,{Binding TheCommand}}" />

This will definitely work: CommandWrapper.Add will receive the event name from the CommandWrapper created by the markup extension and can create the appropriate mapping.

Ray Burns