Команда CanExecute не работает должным образом в представлении WPF ⇐ C#

Место общения программистов C#
Anonymous
Команда CanExecute не работает должным образом в представлении WPF

Сообщение Anonymous »

Сейчас я работаю над экраном WPF для представления, в котором мы столкнулись с необычной проблемой с командами типа Command или Command.
В нашем приложении есть элемент управления, к которому привязана команда . Мы также привязываем к команде метод CanExecute, который должен включать или отключать элемент управления в зависимости от текущих условий. Однако когда мы определяем команду как RelayCommandWpf, функция CanExecute перестает работать корректно — она срабатывает только один раз при инициализации и больше никогда после этого.
Удивительно, но если мы изменим тип команды на RelayCommandWpf, метод CanExecute будет работать так, как ожидалось, а элемент управления будет включаться/отключаться так, как должен.
Мой код в основном определяется следующим образом:
Команда

Код: Выделить всё

public RelayCommandWpf MotorCommand => _motorCommand ??= new RelayCommandWpf(SendMotorConfig, CanSendMotorConfig);
XAML RelayCommandWpf:

Код: Выделить всё

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);
}
}
}
}
}
Кто-нибудь знает, почему RelayCommandWpf или RelayCommandWpf может привести к тому, что CanExecute перестанет работать в WPF? Есть ли известная проблема с этими типами или чем-то особенным для целочисленных или двойных команд в WPF?
Будем благодарны за любую помощь или идеи. Спасибо!

Подробнее здесь: https://stackoverflow.com/questions/791 ... n-wpf-view

Вернуться в «C#»