Понимание реализации ICommand без MVVM

Пытаюсь понять, как работать с командами. Я много читал о командах и знаю, что в большинстве случаев команды используются в шаблоне MVVM. Также я знаю, что есть класс RoutedCommand, который часто используется для экономии времени при разработке.

Но - я хочу понять основы - и именно в этом проблема. Вот так:

В своем приложении я определил класс MyCommand:

 public class MyCommand :ICommand
{
    public void Execute(object parameter)
    {
        Console.WriteLine("Execute called!");
        CanExecuteChanged(null, null);
    }

    public bool CanExecute(object parameter)
    {
        Console.WriteLine("CanExecute called!");
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

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

 public static class AppCommands
    {
        private static ICommand anyCommand = new MyCommand();

        public static ICommand AnyCommand
        {
            get { return anyCommand; }
        }
    }

Почти там. Теперь я поместил две кнопки в свое MainWindow. Один из них привязан к команде:

<StackPanel>
    <Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
    <Button Content="Button" Height="23" Name="button2" Width="75" Command="{x:Static local:AppCommands.AnyCommand}" CommandParameter="Hello"/>
</StackPanel>

А вот и MainWindow.cs:

public MainWindow()


  {
        InitializeComponent();
        AppCommands.AnyCommand.CanExecuteChanged += MyEventHandler;
    }


    private void button1_Click(object sender, RoutedEventArgs e)
    {
       // Nothing for the moment
    }

    private void MyEventHandler(object sender, EventArgs e)
    {
        Console.WriteLine("MyEventHandler called");
    }

Итак - запустим мой проект. Как видите, я сделал несколько консольных выходов. Если я нажму кнопку 2, вывод будет:

CanExecute вызван! Казнить зовут! CanExecute вызван! MyEventHandler вызвал

Итак, на мой взгляд, происходит следующее: 1.) команда на кнопке «активирована». Чтобы проверить, следует ли вызывать метод execute, вызывается метод CanExecute. 2.) Если метод CanExecute возвращает true, то вызывается метод Execute. 3.) В методе execute, как я определил, должно быть вызвано событие CanExecuteChanged. При его вызове сначала проверяется CanExecute, а затем вызывается обработчик событий.

Мне это непонятно. Единственный способ вызвать событие - использовать метод Execute. Но метод Execute вызывается через логику команды после проверки CanExecute. Вызов события также проверяет CanExecute, но почему? Я смущен.

И все становится еще более запутанным, когда я пытаюсь отключить кнопку. Допустим, есть CommandParameter, и теперь с ним работает CanExecute. Возможно, метод вернет false. В этом случае кнопка отключена - хорошо.

Но: как мне его снова активировать? Как мы уже знаем: я могу вызвать событие CanExecuteChange только из своего командного класса. Итак, поскольку мы не можем нажать отключенную кнопку, команда не будет вызывать метод CanExecute (или даже Execute).

Мне кажется, есть что-то важное, чего я не вижу - но я действительно не могу этого найти.

Не могли бы вы мне помочь?


person CodeCannibal    schedule 30.05.2012    source источник
comment
Я изменил ваши теги, чтобы они соответствовали теме вопроса. Я выбрал WPF, но не уверен, это ли это или Silverlight / WP.   -  person Adam Houldsworth    schedule 30.05.2012


Ответы (1)


Ваш CanExecuteChanged не должен повышаться с помощью Execute, он должен повышаться, когда CanExecute начнет возвращать другое значение. Когда это зависит от вашего командного класса. В простейшей форме вы можете добавить свойство:

public class MyCommand : ICommand
{
    bool canExecute;

    public void Execute(object parameter)
    {
        Console.WriteLine("Execute called!");
    }

    public bool CanExecute(object parameter)
    {
        Console.WriteLine("CanExecute called!");
        return CanExecuteResult;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecuteResult
    {
        get { return canExecute; }
        set {
            if (canExecute != value)
            {
                canExecute = value;
                var canExecuteChanged = CanExecuteChanged;
                if (canExecuteChanged != null)
                    canExecuteChanged.Invoke(this, EventArgs.Empty);
            }
        }
    }
}
person Community    schedule 30.05.2012
comment
БОЛЬШОЙ! Решение настолько простое, что это больно :) Большое спасибо - вы сделали мой день! - person CodeCannibal; 30.05.2012
comment
Не могли бы вы вложить в свой ответ файлы всего проекта? - person Fulproof; 10.03.2014
comment
@Fulproof Это странный вопрос. Целая куча нечитаемых XML не улучшит этот ответ, поэтому мне хочется сказать «нет», я не собираюсь этого делать. Но если вы можете объяснить какую-либо часть этого, с которой у вас возникли проблемы, я буду рад взглянуть. - person ; 10.03.2014
comment
@hvd, спасибо, я уже спросил и получил ответил - person Fulproof; 11.03.2014