简体   繁体   English

将自定义WPF控件中的事件绑定到ViewModel中的命令

[英]Bind event in custom WPF control to command in ViewModel

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. 我希望将事件从自定义控件直接传递到我的视图模型上的ICommand。 I am obviously being dense here as I can't figure out how to do this. 我显然在这里很忙,因为我不知道该怎么做。 Any assistance is most welcome. 欢迎任何帮助。

Thanks 谢谢

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 DependencyProperty 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. 您也许可以使用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. 请注意,您可能希望将实际的事件处理程序类型传递给CommandWrapper并使用反射来构造适当的委托,而不是简单地说“ new EventHandler”。

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. 我不确定XAML解析器是否允许您使用MarkupExtension设置事件,因此最后一种解决方案可能实际上无法简单地工作。 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. 这绝对可以正常工作:CommandWrapper.Add将从标记扩展创建的CommandWrapper接收事件名称,并可以创建适当的映射。

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: 我使用此示例向ComboBox SelectionChanged事件添加命令支持:

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

Cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM