你好,Overflowers同事:
我有一个中继命令类,它在几个不同的上下文中使用。当我绑定到矩形(Shape)时,不会调用CanExecute()方法。但是,当我将同一个类绑定到MenuItem时,会调用CanExecute()。当我开始查看菜单时,它似乎被调用了。当CanExecute返回false时,我的菜单项将变灰。非常好!然而,我的应用程序有很多带有CanExecute实现的形状。到目前为止,我必须从Shapes的Exclude()方法调用CanExecute。顺便说一句,我正在用鼠标行为绑定结构中的形状。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Sweeper.ViewModels
{
public class
RelayCommand : ICommand
{
#region Fields
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
private readonly Action<object> _unexecute;
private string _displayText;
private string _category;
private static EventHandler newLogItemEvent;
public static event EventHandler NewLogItemEvent
{
add { newLogItemEvent += value; }
remove { newLogItemEvent -= value; }
}
protected virtual void OnNewLogItemEvent(LogItem li)
{
if (newLogItemEvent != null)
{
newLogItemEvent(null,li);
}
}
private void RaiseNewLogItemEvent(LogItem li)
{
OnNewLogItemEvent(li);
}
//
public string Category
{
get { return _category; }
set { _category = value; }
}
#endregion // Fields
#region Constructors
//<summary>
//Creates a new command that can always execute.
//</summary>
//<param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
//<summary>
//Creates a new command.
//</summary>
//<param name="execute">The execution logic.</param>
//<param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
: this(execute, canExecute, "")
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute, string displayText)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
_displayText = displayText;
}
public string DisplayText
{
get { return _displayText; }
set { _displayText = value;
}
}
#endregion // Constructors
#region ICommand Members
// [DebuggerStepThrough]
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
else
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
bool sendLogItem = false;
if (_canExecute != null)
{
if (_canExecute(parameter))
{
_execute(parameter);
sendLogItem = true;
}
}
else
{
_execute(parameter);
sendLogItem = true;
}
if (sendLogItem)
{
string str;
str = "Cmd:(" + _displayText + ")tParm:(" + parameter + ")";
RaiseNewLogItemEvent(new LogItem(this, str, parameter, _category));
}
else
{ //Rejected
}
}
#endregion // ICommand Members
}
请仔细阅读,我将在下一个代码块中发布用于附加矩形对象的信标
namespace Sweeper.Views
{
public class MouseBehavior
{
#region MouseUp
public static readonly DependencyProperty MouseUpCommandProperty =
DependencyProperty.RegisterAttached("MouseUpCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseUpCommandChanged)));
private static void MouseUpCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseUp += element_MouseUp;
}
static void element_MouseUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseUpCommand(element);
command.Execute(e);
}
public static void SetMouseUpCommand(UIElement element, ICommand value)
{
element.SetValue(MouseUpCommandProperty, value);
}
public static ICommand GetMouseUpCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseUpCommandProperty);
}
#endregion
#region MouseDown
public static readonly DependencyProperty MouseDownCommandProperty =
DependencyProperty.RegisterAttached("MouseDownCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseDownCommandChanged)));
private static void MouseDownCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseDown += element_MouseDown;
}
static void element_MouseDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseDownCommand(element);
command.Execute(e);
}
public static void SetMouseDownCommand(UIElement element, ICommand value)
{
element.SetValue(MouseDownCommandProperty, value);
}
public static ICommand GetMouseDownCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseDownCommandProperty);
}
#endregion
#region MouseEnter
public static readonly DependencyProperty MouseEnterCommandProperty =
DependencyProperty.RegisterAttached("MouseEnterCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseEnterCommandChanged)));
private static void MouseEnterCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseEnter += new MouseEventHandler(element_MouseEnter);
}
static void element_MouseEnter(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseEnterCommand(element);
command.Execute(e);
}
public static void SetMouseEnterCommand(UIElement element, ICommand value)
{
element.SetValue(MouseEnterCommandProperty, value);
}
public static ICommand GetMouseEnterCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseEnterCommandProperty);
}
#endregion
#region MouseLeave
public static readonly DependencyProperty MouseLeaveCommandProperty =
DependencyProperty.RegisterAttached("MouseLeaveCommand",
typeof(ICommand),
typeof(MouseBehavior),
new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseLeaveCommandChanged)));
private static void MouseLeaveCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseLeave += new MouseEventHandler(element_MouseLeave);
}
static void element_MouseLeave(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseLeaveCommand(element);
command.Execute(e);
}
public static void SetMouseLeaveCommand(UIElement element, ICommand value)
{
element.SetValue(MouseLeaveCommandProperty, value);
}
public static ICommand GetMouseLeaveCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseLeaveCommandProperty);
}
#endregion
#region MouseLeftButtonDown
public static readonly DependencyProperty MouseLeftButtonDownCommandProperty =
DependencyProperty.RegisterAttached("MouseLeftButtonDownCommand",
typeof(ICommand),
typeof(MouseBehavior),
new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseLeftButtonDownCommandChanged)));
private static void MouseLeftButtonDownCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseLeftButtonDown += element_MouseLeftButtonDown;
}
static void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseLeftButtonDownCommand(element);
command.Execute(e);
}
public static void SetMouseLeftButtonDownCommand(UIElement element, ICommand value)
{
element.SetValue(MouseLeftButtonDownCommandProperty, value);
}
public static ICommand GetMouseLeftButtonDownCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseLeftButtonDownCommandProperty);
}
#endregion
#region MouseLeftButtonUp
public static readonly DependencyProperty MouseLeftButtonUpCommandProperty =
DependencyProperty.RegisterAttached("MouseLeftButtonUpCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseLeftButtonUpCommandChanged)));
private static void MouseLeftButtonUpCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseLeftButtonUp += element_MouseLeftButtonUp;
}
static void element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseLeftButtonUpCommand(element);
command.Execute(e);
}
public static void SetMouseLeftButtonUpCommand(UIElement element, ICommand value)
{
element.SetValue(MouseLeftButtonUpCommandProperty, value);
}
public static ICommand GetMouseLeftButtonUpCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseLeftButtonUpCommandProperty);
}
#endregion
#region MouseMove
public static readonly DependencyProperty MouseMoveCommandProperty =
DependencyProperty.RegisterAttached("MouseMoveCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseMoveCommandChanged)));
private static void MouseMoveCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseMove += new MouseEventHandler(element_MouseMove);
}
static void element_MouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseMoveCommand(element);
command.Execute(e);
}
public static void SetMouseMoveCommand(UIElement element, ICommand value)
{
element.SetValue(MouseMoveCommandProperty, value);
}
public static ICommand GetMouseMoveCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseMoveCommandProperty);
}
#endregion
#region MouseRightButtonDown
public static readonly DependencyProperty MouseRightButtonDownCommandProperty =
DependencyProperty.RegisterAttached("MouseRightButtonDownCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseRightButtonDownCommandChanged)));
private static void MouseRightButtonDownCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseRightButtonDown += element_MouseRightButtonDown;
}
static void element_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseRightButtonDownCommand(element);
command.Execute(e);
}
public static void SetMouseRightButtonDownCommand(UIElement element, ICommand value)
{
element.SetValue(MouseRightButtonDownCommandProperty, value);
}
public static ICommand GetMouseRightButtonDownCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseRightButtonDownCommandProperty);
}
#endregion
#region MouseRightButtonUp
public static readonly DependencyProperty MouseRightButtonUpCommandProperty =
DependencyProperty.RegisterAttached("MouseRightButtonUpCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseRightButtonUpCommandChanged)));
private static void MouseRightButtonUpCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseRightButtonUp += element_MouseRightButtonUp;
}
static void element_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseRightButtonUpCommand(element);
command.Execute(e);
}
public static void SetMouseRightButtonUpCommand(UIElement element, ICommand value)
{
element.SetValue(MouseRightButtonUpCommandProperty, value);
}
public static ICommand GetMouseRightButtonUpCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseRightButtonUpCommandProperty);
}
#endregion
#region MouseWheel
public static readonly DependencyProperty MouseWheelCommandProperty =
DependencyProperty.RegisterAttached("MouseWheelCommand", typeof(ICommand), typeof(MouseBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseWheelCommandChanged)));
private static void MouseWheelCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseWheel += new MouseWheelEventHandler(element_MouseWheel);
}
static void element_MouseWheel(object sender, MouseWheelEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseWheelCommand(element);
command.Execute(e);
}
public static void SetMouseWheelCommand(UIElement element, ICommand value)
{
element.SetValue(MouseWheelCommandProperty, value);
}
public static ICommand GetMouseWheelCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseWheelCommandProperty);
}
#endregion
}
}
以及绑定行为的数据模板
<DataTemplate x:Key="GamePieceTemplate">
<Border MinWidth="10" MinHeight="10" Padding="0" BorderBrush="{StaticResource GridBorderBrush}" >
<Rectangle Style="{StaticResource GamePieceTrigger}"
StrokeThickness="1"
vw:MouseBehavior.MouseLeftButtonDownCommand="{Binding MouseLeftButtonDownCommand}"
vw:MouseBehavior.MouseLeftButtonUpCommand="{Binding MouseLeftButtonUpCommand}"
vw:MouseBehavior.MouseEnterCommand="{Binding MouseEnterCommand}"
vw:MouseBehavior.MouseLeaveCommand="{Binding MouseLeaveCommand}"
vw:MouseBehavior.MouseRightButtonUpCommand="{Binding MouseRightButtonUpCommand}"
/>
</Border>
</DataTemplate>
然后这里有一个违规的(不调用CanExecute)命令
#region MOUSE_LEFT_BUTTON_DOWN
private RelayCommand _mouseLeftButtonDownCommand;
public RelayCommand MouseLeftButtonDownCommand
{
get
{
if (_mouseLeftButtonDownCommand == null)
{
_mouseLeftButtonDownCommand = new RelayCommand(param => ExecuteMouseLeftButtonDown((MouseEventArgs)param),
param => CanExecuteMouseLeftButtonDown(null))
{
DisplayText = "MouseLeftButtonDownCommand",
Category = CATEGORY
};
}
return _mouseLeftButtonDownCommand;
}
set { _mouseLeftButtonDownCommand = value; }
}
private bool CanExecuteMouseLeftButtonDown(object o)
{
return ((!this.IsPlayed) && !(this.value == GameConstants.PieceValues.FLAGGED));
}
private void ExecuteMouseLeftButtonDown(MouseEventArgs e)
{
Debug.WriteLine("Mouse Down : " + e.GetPosition((IInputElement)e.Source));
if (e.LeftButton == MouseButtonState.Pressed)
{
if (this.Value == GameConstants.PieceValues.BUTTON)
{
this.Value = GameConstants.PieceValues.PRESSED;
gameBoard.GameState = GameConstants.GameStates.IN_DECISION;
}
else
if (gameBoard.GameState != GameConstants.GameStates.WON &&
gameBoard.GameState != GameConstants.GameStates.LOST)
gameBoard.GameState = GameConstants.GameStates.IN_PLAY;
}
}
#endregion
代码和命令被绑定了,我只是没有得到MouseBehaviors对CanExecute()的自动调用。我确实在Execute方法中得到了我希望得到的调用。这可能是因为我只需要像现在这样在我的Execute方法中调用CanExecute?是这样吗?如果是,为什么?我想,为了使调用自动化,命令绑定到什么以及如何绑定可能很重要?
当您将ICommand
绑定到MenuItem
或Button
时,WPF将自动调用其CanExecute()
方法。这是因为事情是如何在WPF:中实现的
if (command.CanExecute(parameter))
{
command.Execute(parameter);
}
由于Shape
本身不支持命令,并且您通过附加的属性添加了此功能,因此应该以相同的方式实现它。
因此,解决方案是:在事件处理程序中,替换
command.Execute(e);
带有
if (command.CanExecute(e))
{
command.Execute(e);
}