WPF с использованием пользовательских RoutedUICommands или простых обработчиков событий? - PullRequest
5 голосов
/ 17 февраля 2009

Я говорил с кем-то сегодня о выборе шаблона проектирования для обработки логики в их программе WPF и надеялся, что сообщество SO может помочь с дальнейшими советами, чтобы облегчить принятие решения. Какие факторы в пользу команд перевешивают неудобства?

Я подготовил полный образец вместе с некоторыми UML-диаграммами первых двух из трех подходов:

  1. Использовать обработчики событий Click для кнопок и меню.
  2. Использовать команды, связанные в XAML.
  3. Используйте команды, связанные в коде, с сохранением XAML для чистого макета и стиля графического интерфейса.

Вступительный курс, на котором он был, и многие книги показывают простые обработчики событий Click как естественный способ подключения логики к объектам пользовательского интерфейса.

Он был немного ошеломлен количеством накладных расходов, необходимых для использования команд с обеими командами, создаваемыми в коде файла:

public static readonly ICommand cmdShow2 = new RoutedUICommand(
  "Show Window2", "cmdShow2", 
  typeof(TestDespatchWindow));

и еще больше кода в XAML с многословным способом, которым команда должна быть идентифицирована и ограничена:

<Window x:Class="WPFDispatchDemo.TestDespatchWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:w="clr-namespace:WPFDispatchDemo"..>

    <Window.CommandBindings>
      <CommandBinding Command="{x:Static w:TestDespatchWindow.cmdShow2}"
        Executed="OnShow2" />
    </Window.CommandBindings>
      <DockPanel>
        <StackPanel Margin="0,8,0,0">
          <Button x:Name="Show2EventBased" 
                  Margin="10,2,10,2" 
                  Click="OnShow2" 
                  Content="Show2 via WPF Event"/>
          <Button x:Name="Show2Command" 
                  Command="{x:Static w:TestDespatchWindow.cmdShow2}"
                  Margin="10,2,10,2" 
                  Content="Show2 via WPF"/>
        </StackPanel>
    </DockPanel>
  </Window>

Я не могу (пока) претендовать на звание эксперта WPF, поэтому я мог бы нарисовать вещи более сложными, чем они есть на самом деле, но я подозреваю, что вы не можете упростить вещи намного больше, чем выше.

Edit:

Я нашел интересное трехстороннее сравнение между DelegateCommand, RoutedCommand и Event.

Ответы [ 4 ]

6 голосов
/ 18 февраля 2009

Команды свои преимущества и недостатки, вы должны выбрать в зависимости от вашей ситуации, Я настоятельно рекомендую вам сделать этот выбор на индивидуальной основе, не выбирайте «единственно верный путь» для всего проекта.

В некоторых случаях разделение между отправителем и получателем и возможность отправлять команды с использованием только XAML является большим преимуществом (для хорошего примера посмотрите, как шаблон элемента управления ScrollBar связывается с логикой управления на http://msdn.microsoft.com/en-us/library/ms742173.aspx).

В других случаях команды могут превратить то, что было бы двухстрочным обработчиком событий, в нечто, невозможное для отслеживания чудовищности, включая изменение 4 отдельных мест в приложении ( Как должна ViewModel закрывать форму? ).

3 голосов
/ 17 февраля 2009

Единственная причина - хорошо знать реестр команд. Означает, что события, скорее всего, являются закрытыми методами, и я чувствую, что они тесно связаны с кодом окна. В то же время Commands дает возможность хранить реализацию (событие) и определение (Command) отдельно, вы даже можете использовать другой класс (взгляните на ApplicationCommands).

Кроме того, когда я выполняю свою работу в WPF, я использую реализацию ICommand ( Command Pattern ). Вся логика команды идет в метод Execute. Это помогает мне сохранять разделение логики более структурированным способом без чрезмерного усложнения кода окна. С помощью этой опции вы можете создавать команды на вашей модели и, следовательно, связывать их без шума. Взгляни.

Создать модель.

public class Model
{
  ICommand CloseMessagePopupCommand {get; set;}
}

Затем назначьте контекст данных

public MainWindow()
{

  this.DataContext = new Model();
}

И используйте следующий код XAML.

<Button 
    Command="{Binding CloseMessagePopupCommand}"
    Content="{StaticResource Misc.Ok}" />
2 голосов
/ 18 февраля 2009

Я стараюсь оставаться верным шаблону команд, на который Майк ссылается при разработке приложений WPF, используя комбинацию подходов Энди №2 и №3.

Я могу думать только об одной обратной стороне команд, на мой взгляд: только определенные действия определенных элементов пользовательского интерфейса вызывают команды. Один из способов обойти это - заставить ваш обработчик событий вызывать метод Execute для команды. Я думаю, что команды предоставляют очень хороший способ инкапсулировать логику выполнения. Если вы поддерживаете большую часть пользовательского интерфейса и реализуете его с использованием шаблона MVC / MVC / MVVM, это становится очень очевидным.

Я рекомендую вам взглянуть на серию данных Дэна Кревье по шаблону DataModel-View-ViewModel , в частности, раздел «Команды и инкапсуляция команд». Даже если этот шаблон не соответствует вашим потребностям, он дает отличный обзор того, как вы можете инкапсулировать логику в отдельном классе.

1 голос
/ 20 февраля 2009

Другие варианты ICommand, похоже, являются популярным способом реализации сложных командных структур.

Брайан Нойес в своей статье о ПРИЗМЕ говорит

Маршрутизируемые команды в WPF очень мощные и полезные, но у них есть некоторые недостатки при применении к составному приложению. Во-первых, они полностью связаны с визуальным деревом - вызывающий должен быть частью визуального дерева, а привязка команды должна быть привязана через визуальное дерево. ... Вторым недостатком является то, что они тесно связаны с деревом фокуса пользовательского интерфейса и продолжают говорить о DelegateCommand и CompositeCommand, которые включают в себя CAL (Prism).

...