WPF с использованием пользовательских RoutedUICommands или простых обработчиков событий?

Сегодня я разговаривал с кем-то о выборе шаблона проектирования для обработки логики в их программе 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, поэтому, возможно, я нарисовал вещи более сложными, чем они есть на самом деле, но я подозреваю, что вы не можете упростить вещи намного больше, чем указано выше.

Изменить:

Я нашел интересное 3-стороннее сравнение между DelegateCommand , RoutedCommand и событие.


person Andy Dent    schedule 17.02.2009    source источник
comment
Какие факторы в пользу команды перевешивают неудобство? мне кажется вопрос. Я подумал, что объем предыстории может помочь людям увидеть, что я серьезен, и понять контекст.   -  person Andy Dent    schedule 18.02.2009


Ответы (4)


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

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

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

person Nir    schedule 18.02.2009

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

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

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

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

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

public MainWindow()
{

  this.DataContext = new Model();
}

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

<Button 
    Command="{Binding CloseMessagePopupCommand}"
    Content="{StaticResource Misc.Ok}" />
person Mike Chaliy    schedule 17.02.2009

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

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

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

person Szymon Rozga    schedule 18.02.2009

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

Брайан Нойес в своей статье о PRISM говорит

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

person Andy Dent    schedule 20.02.2009