我正在尝试将事件转换为devexpress wpf网格上下文菜单项上的命令,该菜单项派生自FrameworkContentElement而不是FrameworkElement。这会导致运行时错误:
{“无法附加type \”EventToCommand \“来键入\”BarButtonItem \“。类型为”“EventToCommand \”的实例只能附加到类型为“FrameworkElement \”的对象。“}
有解决方法吗?
<dxg:TableView.RowCellMenuCustomizations>
<dxb:BarButtonItem Name="deleteRowItem" Content="Delete" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="ItemClick">
<cmd:EventToCommand Command="{Binding FooChangeCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</dxb:BarButtonItem>
<!--ItemClick="deleteRowItem_ItemClick"/>-->
</dxg:TableView.RowCellMenuCustomizations>
不幸的是,devexpress在将基类更改为有意进行更改的FrameworkElement时遇到了问题......
答案 0 :(得分:1)
FrameworkConentElement
是一个仅在WPF中可用而不在Silverlight中的类。由于MVVM Light旨在为所有 WPF方言(WPF 3.5,WPF 4,Silverlight 3,Silverlight 4,Sivlverlight 5,WP 7,WP 7.1)提供通用功能它不能包含仅在其中一个框架中工作的实现。
有关FrameworkElement
和FrameworkContentElement
see here之间差异的讨论。
但是,您可以轻松实现自己的EventToCommand
类支持ContentElement
(FrameworkContentElement
继承)。该类是从MVVM Light源代码的BL0015复制并修改的:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace GalaSoft.MvvmLight.Command
{
/// <summary>
/// This <see cref="System.Windows.Interactivity.TriggerAction" /> can be
/// used to bind any event on any FrameworkElement to an <see cref="ICommand" />.
/// Typically, this element is used in XAML to connect the attached element
/// to a command located in a ViewModel. This trigger can only be attached
/// to a FrameworkElement or a class deriving from FrameworkElement.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
////[ClassInfo(typeof(EventToCommand),
//// VersionString = "3.0.0.0",
//// DateString = "201003041420",
//// Description = "A Trigger used to bind any event to an ICommand.",
//// UrlContacts = "http://stackoverflow.com/q/6955785/266919",
//// Email = "")]
public partial class EventToCommandWpf : TriggerAction<DependencyObject>
{
/// <summary>
/// Gets or sets a value indicating whether the EventArgs passed to the
/// event handler will be forwarded to the ICommand's Execute method
/// when the event is fired (if the bound ICommand accepts an argument
/// of type EventArgs).
/// <para>For example, use a RelayCommand<MouseEventArgs> to get
/// the arguments of a MouseMove event.</para>
/// </summary>
public bool PassEventArgsToCommand
{
get;
set;
}
/// <summary>
/// Provides a simple way to invoke this trigger programatically
/// without any EventArgs.
/// </summary>
public void Invoke()
{
Invoke(null);
}
/// <summary>
/// Executes the trigger.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
/// <param name="parameter">The EventArgs of the fired event.</param>
protected override void Invoke(object parameter)
{
if (AssociatedElementIsDisabled())
{
return;
}
var command = GetCommand();
var commandParameter = CommandParameterValue;
if (commandParameter == null
&& PassEventArgsToCommand)
{
commandParameter = parameter;
}
if (command != null
&& command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}
}
private static void OnCommandChanged(
EventToCommandWpf element,
DependencyPropertyChangedEventArgs e)
{
if (element == null)
{
return;
}
if (e.OldValue != null)
{
((ICommand)e.OldValue).CanExecuteChanged -= element.OnCommandCanExecuteChanged;
}
var command = (ICommand)e.NewValue;
if (command != null)
{
command.CanExecuteChanged += element.OnCommandCanExecuteChanged;
}
element.EnableDisableElement();
}
private bool AssociatedElementIsDisabled()
{
var element = GetAssociatedObject();
return AssociatedObject == null
|| (element != null
&& !element.IsEnabled);
}
private void EnableDisableElement()
{
var element = GetAssociatedObject();
if (element == null)
{
return;
}
var command = this.GetCommand();
if (this.MustToggleIsEnabledValue
&& command != null)
{
SetIsEnabled(element, command.CanExecute(this.CommandParameterValue));
}
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
{
EnableDisableElement();
}
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(EventToCommandWpf),
new PropertyMetadata(
null,
(s, e) => {
var sender = s as EventToCommandWpf;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(EventToCommandWpf),
new PropertyMetadata(
null,
(s, e) => OnCommandChanged(s as EventToCommandWpf, e)));
/// <summary>
/// Identifies the <see cref="MustToggleIsEnabled" /> dependency property
/// </summary>
public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register(
"MustToggleIsEnabled",
typeof(bool),
typeof(EventToCommandWpf),
new PropertyMetadata(
false,
(s, e) => {
var sender = s as EventToCommandWpf;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
private object _commandParameterValue;
private bool? _mustToggleValue;
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This property is here for compatibility
/// with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="CommandParameter" /> property.
/// </summary>
public object CommandParameterValue
{
get
{
return this._commandParameterValue ?? this.CommandParameter;
}
set
{
_commandParameterValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. If this property
/// is false, the element will not be disabled when the command's
/// CanExecute method changes. This is a DependencyProperty.
/// </summary>
public bool MustToggleIsEnabled
{
get
{
return (bool)this.GetValue(MustToggleIsEnabledProperty);
}
set
{
SetValue(MustToggleIsEnabledProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. This property is here for
/// compatibility with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="MustToggleIsEnabled" /> property.
/// </summary>
public bool MustToggleIsEnabledValue
{
get
{
return this._mustToggleValue == null
? this.MustToggleIsEnabled
: this._mustToggleValue.Value;
}
set
{
_mustToggleValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Called when this trigger is attached to a DependencyObject.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
EnableDisableElement();
}
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The object to which this trigger
/// is attached casted as a FrameworkElement.</returns>
private IInputElement GetAssociatedObject()
{
return AssociatedObject as IInputElement;
}
private void SetIsEnabled(IInputElement element, bool value)
{
if (element is UIElement)
{
((UIElement)element).IsEnabled = value;
}
else if (element is ContentElement)
{
((ContentElement)element).IsEnabled = value;
}
else
{
throw new InvalidOperationException("Cannot set IsEnabled. Element is neither ContentElemen, nor UIElement.");
}
}
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The command that must be executed when
/// this trigger is invoked.</returns>
private ICommand GetCommand()
{
return Command;
}
}
}
要将它包含到您的代码中,您必须定义指向正确dll的xml命名空间,然后像普通EventToCommand
类一样使用它。
注意:此类在Silverlight中不起作用!
答案 1 :(得分:1)
对于那些尝试使用dev express来解决这个特定问题的人来说,这样就可以了!
<dxg:TableView.RowCellMenuCustomizations>
<dxb:BarButtonItem Name="deleteRowItem" Content="Delete" Command="{Binding View.DataContext.DeleteSelectionCommand}" />
</dxg:TableView.RowCellMenuCustomizations>
我跟着他们的例子,按钮上有一个事件,很少意识到我还可以使用一个命令。然后挑战是解决绑定,因为菜单项不在主视觉树上。但是上面解决了这个问题。
答案 2 :(得分:0)
我发现这与DEV express一起使用
<dxb:BarButtonItem Content="123" Name="item1">
<dxmvvm:Interaction.Triggers>
<dxmvvm:EventToCommand EventName="ItemClick" Command="{Binding SomeCommand}" CommandParameter="{Binding ElementName=item1, Path=Content}"/>
</dxmvvm:Interaction.Triggers>
</dxb:BarButtonItem>