В нашем приложении есть элемент управления, к которому привязана команда . Мы также привязываем к команде метод CanExecute, который должен включать или отключать элемент управления в зависимости от текущих условий. Однако когда мы определяем команду как RelayCommandWpf, функция CanExecute перестает работать корректно — она срабатывает только один раз при инициализации и больше никогда после этого.
Удивительно, но если мы изменим тип команды на RelayCommandWpf, метод CanExecute будет работать так, как ожидалось, а элемент управления будет включаться/отключаться так, как должен.
Мой код в основном определяется следующим образом:
Команда
Код: Выделить всё
public RelayCommandWpf MotorCommand => _motorCommand ??= new RelayCommandWpf(SendMotorConfig, CanSendMotorConfig);
Код: Выделить всё
Код: Выделить всё
using System;
using System.Diagnostics.CodeAnalysis;
using System.Windows.Input;
namespace VGUI.Boilerplate
{
///
/// A generic command whose sole purpose is to relay its functionality to other objects by
/// invoking delegates. The default return value for the CanExecute method is 'true'. This class
/// allows you to accept command parameters in the Execute and CanExecute callback methods.
///
///
///
/// If you are using this class in WPF4.5 or above, you need to use the
/// GalaSoft.MvvmLight.CommandWpf namespace (instead of GalaSoft.MvvmLight.Command). This will
/// enable (or restore) the CommandManager class which handles automatic enabling/disabling of
/// controls based on the CanExecute delegate.
///
///
/// The type of the command parameter.
public class RelayCommandWpf : ICommand
{
private readonly WeakAction _execute;
private readonly WeakFunc _canExecute;
///
/// Initializes a new instance of the RelayCommand class that can always execute.
///
///
///
The execution logic. IMPORTANT: If the action causes a
/// closure, you must set keepTargetAlive to true to avoid side
/// effects.
/// (Optional) If true, the target of the Action will be kept as
/// a hard reference, which might cause a memory leak. You should
/// only set this parameter to true if the action is causing a
/// closure. See http://galasoft.ch/s/mvvmweakaction.
///
/// ### If the execute argument is null.
public RelayCommandWpf(Action execute, bool keepTargetAlive = false)
: this(execute, null, keepTargetAlive)
{
}
/// Initializes a new instance of the RelayCommand class.
///
/// If the execute argument is null.
///
/// The execution logic. IMPORTANT: If the action causes a
/// closure, you must set keepTargetAlive to true to avoid side
/// effects.
/// The execution status logic. IMPORTANT: If the func causes a
/// closure, you must set keepTargetAlive to true to avoid side
/// effects.
/// (Optional) If true, the target of the Action will be kept as
/// a hard reference, which might cause a memory leak. You should
/// only set this parameter to true if the action is causing a
/// closure. See http://galasoft.ch/s/mvvmweakaction.
public RelayCommandWpf(Action execute, Func canExecute, bool keepTargetAlive = false)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = new WeakAction(execute, keepTargetAlive);
if (canExecute != null)
{
_canExecute = new WeakFunc(canExecute, keepTargetAlive);
}
}
/// Occurs when changes occur that affect whether the command should execute.
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
/// Raises the event.
[SuppressMessage(
"Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "The this keyword is used in the Silverlight version")]
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
///
/// Defines the method that determines whether the command can execute in its current state.
///
///
/// Data used by the command. If the command does not require data to
/// be passed, this object can be set to a null reference.
///
/// true if this command can be executed; otherwise, false.
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
if (_canExecute.IsStatic || _canExecute.IsAlive)
{
if (parameter == null
&& typeof(T).IsValueType)
{
return _canExecute.Execute(default(T));
}
if (parameter == null || parameter is T)
{
return (_canExecute.Execute((T)parameter));
}
}
return false;
}
/// Defines the method to be called when the command is invoked.
///
/// Data used by the command. If the command does not require data to
/// be passed, this object can be set to a null reference.
public virtual void Execute(object parameter)
{
var val = parameter;
if (parameter != null
&& parameter.GetType() != typeof(T))
{
if (parameter is IConvertible)
{
val = Convert.ChangeType(parameter, typeof(T), null);
}
}
if (CanExecute(val)
&& _execute != null
&& (_execute.IsStatic || _execute.IsAlive))
{
if (val == null)
{
if (typeof(T).IsValueType)
{
_execute.Execute(default(T));
}
else
{
// ReSharper disable ExpressionIsAlwaysNull
_execute.Execute((T)val);
// ReSharper restore ExpressionIsAlwaysNull
}
}
else
{
_execute.Execute((T)val);
}
}
}
}
}
Будем благодарны за любую помощь или идеи. Спасибо!
Подробнее здесь: https://stackoverflow.com/questions/791 ... n-wpf-view