Команда. Как применять параметр
От: Аноним  
Дата: 24.06.10 19:10
Оценка:
У меня непонимание как применять команды, где в методах имеется параметр:
ICommand {
void Execute(Object param);
bool CanExecute(Object param);
event EventHandler CanExecuteChanged;
}

Допустим я создаю комманду и цепляю ее на разные кнопки (Меню, статусбар и т.д.)
ICommand cmd = new MyCommand();

btn.Enabled = cmd.CanExecute(null);
cmd.CanExecuteChanged += { btn.Enabled = cmd.CanExecute(null); }
cmd.Click += { cmd.Execute(null); }

В данном примере я передаю в методы Execute и CanExecute null, но выполнение комманды и изменение его сотояния должно зависеть от данных, в моей интерпретации параметров. Если определять этот параметр в методе Click, то вызов должен выглядеть подобным образом:

cmd.Click += {
// найти комманду
// определить данные для параметра
// вызвать метод cmd.Execute(параметр);
}


но получается, что данные состояния команды находятся вне команды, и когда это состояние меняется, тогда тоже не понятно. Что бы выяснить изменение сосояния "CanExecute" нужно переодически вызывать btn.Enabled = cmd.CanExecute(нужные_данные);
Но это на мой взгляд бред, хотя WPF, кажется, примерно так и делает. Но у меня и не WPF, а WinForm

Получается, что нужно это состояние команды определять внутри команды и оно не должно зависеть от параметра.
Тогда зачем этот параметр вообще? Когда применять этот параметр, непонятно. Поясните, плз
??
Re: Команда. Как применять параметр
От: Sinix  
Дата: 25.06.10 00:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Но это на мой взгляд бред, хотя WPF, кажется, примерно так и делает. Но у меня и не WPF, а WinForm


У оригинальной команды ЕМНИП есть событие CanExecuteChanged
Re: Команда. Как применять параметр
От: _FRED_ Черногория
Дата: 25.06.10 05:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>У меня непонимание как применять команды, где в методах имеется параметр:

[c#] — не пренебрегайте форматированием
А>ICommand {
А>void Execute(Object param);
А>bool CanExecute(Object param);
А>event EventHandler CanExecuteChanged;
А>}
[/c#]
А>Допустим я создаю комманду и цепляю ее на разные кнопки (Меню, статусбар и т.д.)
А>ICommand cmd = new MyCommand();
А>btn.Enabled = cmd.CanExecute(null);
А>cmd.CanExecuteChanged += { btn.Enabled = cmd.CanExecute(null); }
А>cmd.Click += { cmd.Execute(null); }

А>В данном примере я передаю в методы Execute и CanExecute null, но выполнение комманды и изменение его сотояния должно зависеть от данных, в моей интерпретации параметров. Если определять этот параметр в методе Click, то вызов должен выглядеть подобным образом:
А>cmd.Click += { 
А>// найти комманду
А>// определить данные для параметра
А>// вызвать метод cmd.Execute(параметр);
А>}

А>но получается, что данные состояния команды находятся вне команды, …

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

А>и когда это состояние меняется, тогда тоже не понятно.


А для чего это знать? Опять же, при необходимости, тот, кто меняет данные может позаботиться (или дать возможность позаботиться) о том, что бы компоненты, завязанные на команды, обновили своё состояние.

А>Что бы выяснить изменение сосояния "CanExecute" нужно переодически вызывать btn.Enabled = cmd.CanExecute(нужные_данные);

А>Но это на мой взгляд бред, хотя WPF, кажется, примерно так и делает. Но у меня и не WPF, а WinForm

Обычно все так и делают [с той или иной степенью хитрости]. Это если речь о [постоянно видимых пользователем] кнопках. Есть речь о пунктах меню, например, их состояние можно обновлять перед отображением.

А>Получается, что нужно это состояние команды определять внутри команды и оно не должно зависеть от параметра.


Не вижу, как это "получается". С ваших слов вывод со стороны мне, например, не кажется очевидным…

А>Тогда зачем этот параметр вообще? Когда применять этот параметр, непонятно. Поясните, плз


А вот на это можно ответить. В WPF можно параметр команды привязать к источнику команды. А вот "зачем" — тут каждый решает для себя сам :о)) Через него можно передать в команду всё, что угодно.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Команда. Как применять параметр
От: Аноним  
Дата: 25.06.10 11:09
Оценка:
S>У оригинальной команды ЕМНИП есть событие CanExecuteChanged
Не знаю что ты понимаешь под оригинальной, комманду, которая появилась в дотнете с выходом WPF? То, что есть событие CanExecuteChanged я тоже не отрицал и привел в первом посте. Если вызов этого события зависит от данных параметра, то использовать такую комманду крайне не удобно, но это если ее вручную привязывать. Я просто подумал, что чего-то недопонимаю, и попросил разьяснений, как можно использовать команду с параметром, где данные параметра — необходимая информация для вычисления состояния комманды ( в том числе возможно вызывается CanExecuteChanged)
Re[3]: Команда. Как применять параметр
От: Sinix  
Дата: 25.06.10 11:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не знаю что ты понимаешь под оригинальной

Уппс, поторопился. Надо было так: "у оригинального ICommand". Вы ведь не подключаете wpf-сборки ради одного интерфейса?

А>как можно использовать команду с параметром, где данные параметра — необходимая информация для вычисления состояния комманды ( в том числе возможно вызывается CanExecuteChanged)


Примерно так (полноценная реализация для wpf значительно сложнее, там надо химичить с CommandBinding):
  public abstract class CommandBase : ICommand
  {
    #region Fields
    private bool canExecute; 
    #endregion

    #region Properties & notifications
    public bool CanExecute
    {
      get { return canExecute; }
      set
      {
        if (canExecute != value)
        {
          canExecute = value;
          OnCanExecuteChanged(EventArgs.Empty);
        }
      }
    } 

    public event EventHandler CanExecuteChanged;
    protected virtual void OnCanExecuteChanged(EventArgs e)
    {
      EventHandler temp = CanExecuteChanged;
      if (temp != null)
      {
        temp(this, e);
      }
    }
    #endregion

    public void Execute()
    {
      if (CanExecute) // или throw - на усмотрение.
      {
        ExecuteOverride();
      }
    }

    protected abstract void ExecuteOverride();

    #region Explicit ICommand members
    bool ICommand.CanExecute(object parameter)
    {
      return CanExecute;
    }
    void ICommand.Execute(object parameter)
    {
      Execute();
    } 
    #endregion
  }


CanExecute биндится к соответствующему свойству контроллера (который и хранит состояние), для полного щастья заводится наследник ActionCommand, после чего команды плодятся пачками.
Re[4]: Команда. Как применять параметр
От: Аноним  
Дата: 27.06.10 13:36
Оценка:
S>Примерно так (полноценная реализация для wpf значительно сложнее, там надо химичить с CommandBinding):
S>
S>  public abstract class CommandBase : ICommand
S>  {
S>    #region Fields
S>    private bool canExecute; 
S>    #endregion

S>    #region Properties & notifications
S>    public bool CanExecute
S>    {
S>      get { return canExecute; }
S>      set
S>      {
S>        if (canExecute != value)
S>        {
S>          canExecute = value;
S>          OnCanExecuteChanged(EventArgs.Empty);
S>        }
S>      }
S>    } 

S>    public event EventHandler CanExecuteChanged;
S>    protected virtual void OnCanExecuteChanged(EventArgs e)
S>    {
S>      EventHandler temp = CanExecuteChanged;
S>      if (temp != null)
S>      {
S>        temp(this, e);
S>      }
S>    }
S>    #endregion

S>    public void Execute()
S>    {
S>      if (CanExecute) // или throw - на усмотрение.
S>      {
S>        ExecuteOverride();
S>      }
S>    }

S>    protected abstract void ExecuteOverride();

S>    #region Explicit ICommand members
S>    bool ICommand.CanExecute(object parameter)
S>    {
S>      return CanExecute;
S>    }
S>    void ICommand.Execute(object parameter)
S>    {
S>      Execute();
S>    } 
S>    #endregion
S>  }
S>


Извиняюсь что не ответил сразу.
Спасибо за реализацию класса, хотя я в ней и не нуждался.
Интересно, что вы свели интрефейс ICommand с параметрами к классу без параметров. Почему же вы избавились от параметра в методах CanExecute и Execute, не знаете как его применить?
Re[2]: Команда. Как применять параметр
От: Аноним  
Дата: 27.06.10 14:01
Оценка:
_FR>Предлжение не очень понятно составлено, но попробую ответить: Вы можете хранить данные внутри команды, этому, по большому счёту, так же ничто не мешает, но тогда команда станет менее универсальной.

Я это понимаю, только вижу трудности при создании универсальной комманды.
Для примера рассмотрим такую комманду, как допустим удалить элемент из коллекции (честное слово, с потолка).
Допустим для определения состояния и удаления элемента доступного элемента используется подобный интерфейс, который передается в комманду через параметр:
interface IDeleteItem {
   bool CanDelete { get; }
   void DeleteCurrent() 
}


Универсальность заключается в том, что комманда может использоваться с разными типами коллекций, реализующих этот интрефейс, или с одним типом коллекций, но предствленных на форме дважды (трижды ...), и комманда активируется/деактивируется в зависимости от активной коллекции. Получается, внешнее окружение должно сликом много делать, что бы комманда работала корректно, должна вовремя вычислить CanExecute(параметр), на вызвающую сторону возлагаетя ответсвенность на передачу нужного параметра в Execute(параметр).
В общем по моему мнению гемморой. Самое интересное как эту проблему решили в wpf: Они постоянно передают в комманды данные, на основе активного элемента, и на каждый чих (а это может быть и простое движение мышкой), вычисляют CanExecute комманды.


Для меня вопрос решился (в смысле можете не утруждать себя ответом), но я и дальше готов выслушивать мнения других.
Всем спасибо
Re[5]: Команда. Как применять параметр
От: Sinix  
Дата: 27.06.10 14:44
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Почему же вы избавились от параметра в методах CanExecute и Execute?


Потому что иначе у нас происходит перемешивание логики приложения и инфраструктурного кода. Получается, состояние приложения не сосредоточено в относительно маленьком куске кода, а размазано по всем слоям приложения.

Использование параметров провоцирует плохой стиль написания кода — параметры нетипизированы (да ещё и упакованы в один object), для каждого CanExecute мы должны проводить проверку. Если то же самое действие надо выполнять без команд (например, из кода, не связанного с UI), нам надо как-то дублировать методы проверки/вызова.

Конечно, можно сделать memoize для результатов проверки, но тогда возможны утечки памяти. Для борьбы с утечками заводим weak references, чтоб со слабыми ссылками было удобно работать — врапперы... В конечном итоге получаем то, от чего пытались уйти — сильносвязанный код, да ещё и обвешанный инфраструктурой. Проще придавить проблему в зародыше, ограничившись средствами языка для описания внутреннего API. Как UI layer будет этот API дёргать — проблемы самого UI.
Re[3]: Команда. Как применять параметр
От: Аноним  
Дата: 27.06.10 14:59
Оценка:
Зы: Знаю, знаю, команда пишется с одной м
Re[3]: Команда. Как применять параметр
От: git  
Дата: 27.06.10 15:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Универсальность заключается в том, что комманда может использоваться с разными типами коллекций, реализующих этот интрефейс, или с одним типом коллекций, но предствленных на форме дважды (трижды ...), и комманда активируется/деактивируется в зависимости от активной коллекции. Получается, внешнее окружение должно сликом много делать, что бы комманда работала корректно, должна вовремя вычислить CanExecute(параметр), на вызвающую сторону возлагаетя ответсвенность на передачу нужного параметра в Execute(параметр).


Мне кажется вы просто смотрите на команды не с той стороны.
Попробуйте для начала рассуждать по-русски. Например, команда "Отменить последнее действие" — ей очевидно параметры не требуются, вся информация о состоянии находится обработчиком в текущем документе. С другой стороны, может быть команда "Показать сообщение" и в качестве параметра ей совершенно естественно будет требоваться текст сообщения. Все может быть очень просто.

У вас же —
>
>interface IDeleteItem {
>   bool CanDelete { get; }
>   void DeleteCurrent() 
>}
>

плохой интерфейс для параметра. Попробуйте его имя и название каждого метода перевести на русский, чушь же получается.
Не знаю как там у вас всё устроено, но в идеальном мире команда на удаление могла бы не требовать параметр совсем если обработчик знает активный элемент ("Удалить активный элемент"), или в качестве параметра мог бы выступать текущий элемент ("Удалить элемент из текущей коллекци"), ну и элемент плюс коллекция ("Удалить элемент из коллекции").
Re[4]: Команда. Как применять параметр
От: Sinix  
Дата: 27.06.10 16:21
Оценка:
Здравствуйте, git, Вы писали:

git>Мне кажется вы просто смотрите на команды не с той стороны.

Мне кажется, вы тоже

Команда — это способ биндинга элементов UI к определённым методам БЛ, аналогично биндингу к данным. Поэтому она должна быть максимально простой и универсальной. Всё остальное — ересь, порождённая хайпом на MVC.

git>ПС другой стороны, может быть команда "Показать сообщение" и в качестве параметра ей совершенно естественно будет требоваться текст сообщения.

Необязательно. Может быть команда "показать текущее сообщение" (текущие элементы ака состояние — свойство контроллера, возможно, прибинденное к свойству SelectedItems в UI).

Раз уж выходные: MV*-паттерн, применённый от балды, малопригоден даже для решения тех задач, под которые он создавался.

Посмотрите, сколько геммороя вызывает дубовая система template в WPF. Пример: добавление переноса строк
Автор: Sinix
Дата: 18.06.10
(при сохранении access key). Решается переписыванием кучи стандартных шаблонов (по пять для CheckBox/RadioButton/Label) в двух версиях — для fw3.5, и fw4 — всё ради одной строчки. Разумеется, с появлением сервис пака/фикса шаблоны надо будет обновлять. Прикинув затраты, плюнули.
Re[5]: Команда. Как применять параметр
От: git  
Дата: 27.06.10 16:38
Оценка: +1 :)
Здравствуйте, Sinix, Вы писали:

S>Мне кажется, вы тоже

S>Команда — это способ биндинга элементов UI к определённым методам БЛ, аналогично биндингу к данным.
Ну я то настолько испорчен, что "команда" у меня ассоциируется даже не с GoF, а с WM_COMMAND, не говоря уже о "биндингах" Но пытаюсь бороться со своими инстинктами.

S>Необязательно. Может быть команда "показать текущее сообщение" (текущие элементы ака состояние — свойство контроллера, возможно, прибинденное к свойству SelectedItems в UI).

Я подумал что одного "например" будет достаточно, можете смело подставить "например" в начало каждого примера команды.
Речь о том, что топик стартер пытается использовать в качестве параметра какое-то нелепое творение, которое выворачивает всю логику работы и естественно натыкается на грабли.

S>Посмотрите, сколько геммороя вызывает дубовая система template в WPF. Пример: добавление переноса строк
Автор: Sinix
Дата: 18.06.10
(при сохранении access key).

Там есть пример использования команд? С виду похоже на вложенные свойства.
Re[6]: [OFF] MV* в WPF
От: Sinix  
Дата: 27.06.10 16:50
Оценка:
Здравствуйте, git, Вы писали:

Со всем выше — согласен

git>Там есть пример использования команд? С виду похоже на вложенные свойства.


Нет, там есть пример дубовой реализации классной идеи — отделения представления контрола от его поведения. В результате имеем дизайн "всё или ничего" — или пользуйся готовым шаблоном, или заменяй своим (возможно, на основе копи-пасты стандартного шаблона). Для каждой системной темы.

Примитивная аналогия: вместо того, чтобы оверрайдить метод, вы копипастите код базового класса, и заменяете содержимое нужного вам метода.
Re[4]: Команда. Как применять параметр
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.06.10 20:22
Оценка:
Здравствуйте, git, Вы писали:

git>Попробуйте для начала рассуждать по-русски. Например, команда "Отменить последнее действие" — ей очевидно параметры не требуются, вся информация о состоянии находится обработчиком в текущем документе.


Очевидно то, что не всегда текущий документ известен команде и доступен через глобальное состоение, не говоря уже об экзотике когда контекст выполнения команды удаленный, либо один набор команд может применяться к разным документам.

Так что, передавать параметр команде — не самая плохая идея.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.