我创建的自定义控件具有如下事件。
public class Editor : Control
{
...
public event EventHandler<AlarmCollection> AlarmFired = null;
...
}
并且在触发TextChanged事件时,将调用上述事件(如果不为null,则为null。)>
private async void TextArea_TextChanged(object sender, TextChangedEventArgs e) { ... this.AlarmFired?.Invoke(this, this.alarmList); ... }
现在我尝试如下将上述事件从外部绑定到ViewModel。
<DataTemplate DataType="{x:Type documentViewModels:EditorTypeViewModel}"> <editor:Editor FontSize="15" FontFamily="Arial" KeywordForeground="LightBlue"> <i:Interaction.Triggers> <i:EventTrigger EventName="AlarmFired"> <mvvm:EventToCommand Command="{Binding AlarmFiredCommand}" PassEventArgsToCommand="True" EventArgsConverter="{localConverters:RemoveObjectConverter}"/> </i:EventTrigger> </i:Interaction.Triggers> </editor:Editor> </DataTemplate>
EditorTypeViewModel的定义如下所示。
public class EditorTypeViewModel : DocumentViewModel { public event EventHandler<AlarmCollection> AlarmFired = null; public EditorTypeViewModel(string title) : base(title) { } private RelayCommand<AlarmCollection> alarmFiredCommand = null; public RelayCommand<AlarmCollection> AlarmFiredCommand { get { if (this.alarmFiredCommand == null) this.alarmFiredCommand = new RelayCommand<AlarmCollection>(this.OnAlarmFired); return this.alarmFiredCommand; } } private void OnAlarmFired(AlarmCollection alarmInfos) { this.AlarmFired?.Invoke(this, alarmInfos); } }
执行上述程序时,不调用与RelayCommand连接的OnAlarmFired方法。我试图找到原因,并找到了可疑的地方。
可疑点是在调用编辑器的TextChanged方法时,编辑器的AlarmFired事件的值为null。它显示在下面。
我以为AlarmFired不是null,因为它将与Command连接,但不是。
我试图做的是将CustomControl的事件绑定到ViewModel的Command并使用它。
例如,可以将ListView的MouseDoubleClick事件绑定到MouseDoubleClickCommand,如下所示。当触发MouseDoubleClick事件时,MouseDoubleClickCommand将获得控制权。
(我不想在CustomControl中创建Command,因为事件数量很多)<ListView> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseDoubleClick"> <mvvm:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True"/> </i:EventTrigger> </i:Interaction.Triggers> </ListView>
我想创建一个事件以支持转换为类似ListView的MouseDoubleClick的命令
为了实现这个目标我应该怎么做?
感谢您阅读。
我创建的自定义控件具有如下事件。公共类编辑器:控件{...公共事件EventHandler
如果您要将事件参数传递给ViewModel
,则应像这样创建一个新的Behavior
:
public class EventToCommandBehavior : Behavior<FrameworkElement>
{
private Delegate _handler;
private EventInfo _oldEvent;
// Event
public string Event
{
get => (string)GetValue(EventProperty);
set => SetValue(EventProperty, value);
}
public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(string), typeof(EventToCommandBehavior), new PropertyMetadata(null, OnEventChanged));
// Command
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommandBehavior), new PropertyMetadata(null));
// PassArguments (default: false)
public bool PassArguments
{
get => (bool)GetValue(PassArgumentsProperty);
set => SetValue(PassArgumentsProperty, value);
}
public static readonly DependencyProperty PassArgumentsProperty = DependencyProperty.Register("PassArguments", typeof(bool), typeof(EventToCommandBehavior), new PropertyMetadata(false));
private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var beh = (EventToCommandBehavior)d;
if (beh.AssociatedObject != null) // is not yet attached at initial load
beh.AttachHandler((string)e.NewValue);
}
protected override void OnAttached()
{
AttachHandler(Event); // initial set
}
/// <summary>
/// Attaches the handler to the event
/// </summary>
private void AttachHandler(string eventName)
{
// detach old event
if (_oldEvent != null)
_oldEvent.RemoveEventHandler(AssociatedObject, _handler);
// attach new event
if (!string.IsNullOrEmpty(eventName))
{
var ei = AssociatedObject.GetType().GetEvent(eventName);
if (ei != null)
{
var mi = GetType().GetMethod("ExecuteCommand", BindingFlags.Instance | BindingFlags.NonPublic);
if (mi != null) _handler = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);
ei.AddEventHandler(AssociatedObject, _handler);
_oldEvent = ei; // store to detach in case the Event property changes
}
else
throw new ArgumentException($"The event '{eventName}' was not found on type '{AssociatedObject.GetType().Name}'");
}
}
/// <summary>
/// Executes the Command
/// </summary>
// ReSharper disable once UnusedParameter.Local
private void ExecuteCommand(object sender, EventArgs e)
{
object parameter = PassArguments ? e : null;
if (Command == null) return;
if (Command.CanExecute(parameter))
Command.Execute(parameter);
}
}