DataWindowButton CanExecute не срабатывает, Catel 4.0

Я только что обновил проект с Catel 3.4 до Catel 4.0, и пользовательская кнопка «Применить», которая работала, теперь не активируется.

AddCustomButton(new DataWindowButton("Apply", ExecuteApply, canExecuteApply));

В Catel 3.4 функция canExecuteApply вызывалась, когда окно получало фокус или изменялся какой-либо элемент управления. В версии 4.0 он вызывается дважды при создании окна и никогда больше.

Я подозреваю, что это как-то связано с частью руководства по обновлению IViewPropertySelector, однако регистрация реализации по умолчанию не имела никакого эффекта, и я не могу понять, в каком пространстве имен находится метод расширения AutoDetectViewPropertiesToSubscribe.

Изменить: я обнаружил, что получаю такое же поведение с некоторыми экземплярами AsynchronousCommand в другом месте приложения. Делегат CanExecute срабатывает при создании элемента управления и никогда больше.

Редактировать 2: это была одна и та же проблема с разными решениями. Объяснение проблемы см. в ответе Герта ван Хоррика.

Если команда зарегистрирована в модели представления, вы можете использовать

ViewModelCommandManager.InvalidateCommands(true);

чтобы получить состояние выполнения для повторной оценки. Для DataWindowButton, как описано выше, мне пришлось вручную вызвать RaiseCanExecuteChanged для команды кнопки, поскольку, насколько я могу судить, эта команда не принадлежит модели vie.

var catelCommand = (applyButton.Command as ICatelCommand);
if (catelCommand != null)
{
    catelCommand.RaiseCanExecuteChanged();
}

В любом случае это далеко не подход с лучшими характеристиками производительности, но если желательно то же поведение, что и до обновления, вы можете сделать эти вызовы в следующей подписке на событие:

System.Windows.Input.CommandManager.RequerySuggested += RequerySuggested;

Надеюсь, это поможет кому-нибудь еще столкнуться с этой проблемой.


person Dwayne    schedule 18.11.2014    source источник


Ответы (2)


Причина в том, что в прошлом (до версии 4.0) Catel подписывался на CommandManager WPF и аннулировал все команды во всех моделях представлений почти во всем (перемещение мыши, фокус и т. д.). Чтобы повысить производительность (намного), мы решили автоматически аннулировать команды только при изменении свойства в конкретной модели представления.

Например, если у вас есть виртуальная машина, в которой вы меняете свойство, она автоматически переоценит команды на этой виртуальной машине. Вы все еще можете вручную переоценить команды, используя этот код (внутри виртуальной машины):

ViewModelCommandManager.InvalidateCommands(true);
person Geert van Horrik    schedule 19.11.2014
comment
Для явных экземпляров AsynchronousCommand в моделях представлений это сработало. Сделал это в подписке на System.Windows.Input.CommandManager.RequerySuggested, чтобы восстановить старое поведение для этих виртуальных машин. Однако где мне это сделать для DataWindowButton? - person Dwayne; 19.11.2014
comment
С моей точки зрения, он реализует ту же логику. В противном случае, пожалуйста, проверьте исходный код, в этом сила открытого исходного кода ;-) - person Geert van Horrik; 19.11.2014
comment
Итак, что бы вы предложили, если у вас есть вложенный пользовательский элемент управления, и когда свойства пользовательского элемента управления изменяются, команды во внешнем представлении должны быть признаны недействительными? - person pjdupreez; 07.01.2015
comment
Я немного поиграл и нашел другой способ ... посмотрите мой ответ и скажите, что вы думаете, пожалуйста. - person pjdupreez; 07.01.2015
comment
Я сходил с ума несколько часов, прежде чем нашел это. - person craftworkgames; 28.11.2015

Как насчет этого? У меня была проблема, когда мои вложенные пользовательские элементы управления должны были вызывать обновление команд моего внешнего пользовательского элемента управления. Это не элегантно, но выполняет свою работу за меня, пока я не найду лучший способ.

public partial class App : Application
{

    private static IViewModelManager _ViewModelManager;

    public App()
        : base()
    {
        var dependencyResolver = this.GetDependencyResolver();

        _ViewModelManager = dependencyResolver.Resolve<IViewModelManager>();

        System.Windows.Input.CommandManager.RequerySuggested += RequerySuggested;
    }

    private void RequerySuggested(object sender, EventArgs e)
    {
        foreach (IViewModel viewModel in _ViewModelManager.ActiveViewModels)
        {
            (viewModel as ViewModelBase).GetViewModelCommandManager().InvalidateCommands(true);
        }
    }
}
person pjdupreez    schedule 07.01.2015
comment
Это тоже рабочее решение. Просто убедитесь, что это не слишком сильно влияет на производительность. - person Geert van Horrik; 07.01.2015
comment
Да, я заметил небольшую проблему с производительностью, но незначительную. Если я правильно понимаю, должны быть затронуты только активные модели представления, но будет ли это отличаться от того, как это работало до версии 4.0? - person pjdupreez; 08.01.2015
comment
Дело в том, что RequestSuggested часто срабатывает (я имею в виду много). Есть причина, по которой мы изменили это поведение в Catel 4.0 (ранее для команд использовалось RequerySuggested). - person Geert van Horrik; 08.01.2015