如何在DataTemplate中处理事件Events

来源:互联网 发布:奇热漫画软件 编辑:程序博客网 时间:2024/05/16 14:17

文章摘自 Naveen Dhaka's blog

http://nerobrain.blogspot.nl/2012/01/wpf-events-to-command.html


Tuesday, January 10, 2012

Wire any WPF Event to Command on ViewModel in MVVM

In the last post I explained how to write a behaviour to hook a commmand to an event. That works well but a new behaviour is needed to written for each event. I tried a generic approach to have a single behaviour that can be used to wire any event to a command. It comes witha little performance penalty as reflection is used to get the event and attached a delegate to that event. Below is the code:

using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Reflection;
using System.Diagnostics;

public class CommandExecuter
{
public static readonly DependencyProperty CommandProperty =DependencyProperty.RegisterAttached("Command"typeof(ICommand),typeof(CommandExecuter), new PropertyMetadata(CommandPropertyChangedCallback));
 
public static readonly DependencyProperty OnEventProperty =DependencyProperty.RegisterAttached("OnEvent"typeof(string),typeof(CommandExecuter));
 
public static readonly DependencyProperty CommandParameterProperty =DependencyProperty.RegisterAttached("CommandParameter"typeof(object),typeof(CommandExecuter));

public static void CommandPropertyChangedCallback(DependencyObject depObj,DependencyPropertyChangedEventArgs args)
{
  string onEvent = (string)depObj.GetValue(OnEventProperty);
  Debug.Assert(onEvent != null"OnEvent must be set.");
  var eventInfo = depObj.GetType().GetEvent(onEvent);
  if (eventInfo != null)
  {
    var mInfo = typeof(CommandExecuter).GetMethod("OnRoutedEvent",BindingFlags.NonPublic | BindingFlags.Static);
    eventInfo.GetAddMethod().Invoke(depObj, new object[] {Delegate.CreateDelegate(eventInfo.EventHandlerType, mInfo) });
  }
  else
  {
    Debug.Fail(string.Format("{0} is not found on object {1}", onEvent, depObj.GetType()));
 
}

}
public static ICommand GetCommand(UIElement element)
{
   return (ICommand)element.GetValue(CommandProperty);
}
public static void SetCommand(UIElement element, ICommand command)
{
   element.SetValue(CommandProperty, command);
}
public static string GetOnEvent(UIElement element)
{
return (string)element.GetValue(OnEventProperty);
}
public static void SetOnEvent(UIElement element, string evnt)
{
   element.SetValue(OnEventProperty, evnt);
}
public static object GetCommandParameter(UIElement element)
{
  return (object)element.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(UIElement element, object commandParam)
{
   element.SetValue(CommandParameterProperty, commandParam);
}
private static void OnRoutedEvent(object sender, RoutedEventArgs e)
{
  UIElement element = (UIElement)sender;
  if (element != null)
  {    ICommand command = element.GetValue(CommandProperty) as ICommand;
    if (command != null &&command.CanExecute(element.GetValue(CommandParameterProperty)))
    {
      command.Execute(element.GetValue(CommandParameterProperty));
    }
  }
}
}

Below code shows how to set the command on the controls for any event:   (local: is namespace prefix)
<ComboBox local:CommandExecuter.Command="{Binding CommandImpl}"local:CommandExecuter.OnEvent="SelectionChanged" ></ComboBox>

<Button local:CommandExecuter.Command="{Binding AnotherCommandImpl}"local:CommandExecuter.OnEvent="MouseEnter"local:CommandExecuter.CommandParameter="{x:Static null}"></Button>
0 0