Пример пользовательского шаблона команды WPF

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

12.08.2008 04:18:30
4 ОТВЕТА
РЕШЕНИЕ

Ах, ха! На вопрос я могу ответить! Во-первых, я должен отметить, что лично мне было легче определять и подключать команды в коде, а не в XAML. Это позволяет мне подключать обработчики команд немного более гибко, чем это делает весь подход XAML.

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

public static class CommandBank
{
  /// Command definition for Closing a window
  public static RoutedUICommand CloseWindow { get; private set; }

  /// Static private constructor, sets up all application wide commands.
  static CommandBank()
  {
    CloseWindow = new RoutedUICommand();
    CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
    // ...
  }

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

/// Closes the window provided as a parameter
public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e)
{
  ((Window)e.Parameter).Close();
}

/// Allows a Command to execute if the CommandParameter is not a null value
public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e)
{
  e.CanExecute = e.Parameter != null;
  e.Handled = true;
}

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

После того, как вы определили такие команды, вы можете добавить их в любой элемент пользовательского интерфейса. Далее, после того, как окно загружено, я добавляю привязки команд как в Window, так и в MenuItem, а затем добавляю привязку ввода к окну, используя цикл, чтобы сделать это для всех привязок команд. Передаваемый параметр - это само окно, поэтому приведенный выше код знает, какое окно попытаться закрыть.

public partial class SimpleWindow : Window
{
  private void WindowLoaded(object sender, RoutedEventArgs e)
  {
    // ...
    this.CommandBindings.Add(
      new CommandBinding(
        CommandBank.CloseWindow,
        CommandBank.CloseWindowExecute,
        CommandBank.CanExecuteIfParameterIsNotNull));

    foreach (CommandBinding binding in this.CommandBindings)
    {
       RoutedCommand command = (RoutedCommand)binding.Command;
       if (command.InputGestures.Count > 0)
       {
         foreach (InputGesture gesture in command.InputGestures)
         {
           var iBind = new InputBinding(command, gesture);
           iBind.CommandParameter = this;
           this.InputBindings.Add(iBind);
         }
       }
    }

    // menuItemExit is defined in XAML
    menuItemExit.Command = CommandBank.CloseWindow;
    menuItemExit.CommandParameter = this;
    // ...
  }

  // ....
}

Затем у меня также появятся обработчики событий для событий WindowClosing и WindowClosed. Я рекомендую вам сделать фактическую реализацию команд как можно более мелкой и универсальной. Как и в этом случае, я не пытался поместить код, который пытается остановить закрытие окна, если есть несохраненные данные, я твердо держал этот код внутри события WindowClosing.

Дайте мне знать, если у вас есть дополнительные вопросы. :)

38
3.03.2009 09:45:23
Ваш CanExecuteIfParameterIsNotNull содержит одну из неприятностей моего питомца. Почему бы просто не e.CanExecute = e.Parameter! = Null;
Ray 28.11.2008 00:53:44
@ Ray Это было не то, что я знал, я мог сделать! Спасибо за правку Дрю. :)
Nidonocu 7.10.2009 23:55:17

Особенность XAML в том, что он подходит для «простых» программ, но, к сожалению, он не работает, когда вы хотите делать такие вещи, как функции общего доступа. Скажем, у вас есть несколько классов и все интерфейсы, в которых есть команды, которые никогда не были отключены, вам нужно написать метод CanAlwaysExecute для каждого Window или UserControl! Это просто не очень СУХОЙ .

Прочитав несколько блогов и попробовав несколько вещей, я решил сделать XAML исключительно для внешнего вида, стилей, анимации и триггеров. Все мои подключения обработчиков событий и команд теперь в коде позади. :)

Кстати, есть еще одна проблема - привязка ввода, чтобы их можно было перехватить, необходимо сосредоточиться на объекте, который содержит привязки ввода. Например, для кратчайшего пути, который вы можете использовать в любое время (скажем, F1, чтобы открыть справку), эта входная привязка должна быть установлена ​​для объекта Window, поскольку она всегда имеет фокус, когда ваше приложение активно. Использование метода кода должно облегчить это, даже когда вы начинаете использовать UserControls, которые могут захотеть добавить привязки ввода к своему родительскому окну.

3
12.08.2008 07:57:11
Drahakar 10.05.2011 14:51:47

В сентябрьском выпуске журнала MSDN Брайан Нойес опубликовал отличную статью о RoutedCommand / RoutedEvents !!!

Вот ссылка: http://msdn.microsoft.com/en-us/magazine/cc785480.aspx

4
8.09.2008 07:42:11