Как привязать команду в WPF

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

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

создать класс, который реализует интерфейс ICommand и от вида модели я создаю новый экземпляр этого класса и привязка работает как шарм.

Это код, который я использовал для привязки команд

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;            
        testCommand = new MeCommand(processor);
    }

    ICommand testCommand;

    public ICommand test
    {
        get { return testCommand; }
    }
    public void processor()
    {
        MessageBox.Show("hello world");
    }
}

public class MeCommand : ICommand
{
    public delegate void ExecuteMethod();
    private ExecuteMethod meth;
    public MeCommand(ExecuteMethod exec)
    {
        meth = exec;
    }

    public bool CanExecute(object parameter)
    {
        return false;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        meth();
    }
}

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

6 ответов


Присм уже предоставленной Microsoft.Практика.Призма.Команды.Метод DelegateCommand

Я не уверен, что это считается третьей стороной. Хоть это официально и документировано в MSDN.

некоторые собственные команды сборки, такие как копировать, вставить реализует интерфейс ICommand. ИМХО это следуя принципу Open(for extends)/Close(for changes). чтобы мы могли выполнить свою команду.


обновление

как WPF Командование документально здесь, отрывок...

WPF предоставляет набор предопределенных команд. такие как Cut, BrowseBack и BrowseForward, воспроизведение, остановка и пауза.

если команды в классах библиотеки команд не отвечают вашим потребностям, затем вы можете создавать свои собственные команды. Существует два способа создания пользовательские команды. Первый-начать с нуля и реализовать интерфейс ICommand. В другую сторону, и более общий подход, это создать RoutedCommand или RoutedUICommand.

Я пробовал модель RoutedCommand в начале и закончил с реализацией ICommand.

пример привязки XAML

<CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
                    Executed="ExecutedCustomCommand"
                    CanExecute="CanExecuteCustomCommand" />

RoutedCommand не отличается от RoutedEvent. это похоже на обработчик событий "Clicked" лучшей кнопки. Он служит цели: отделить логику приложения от представления, но требует некоторого присоединения DependencyProperty или код-за.

лично я чувствую себя более комфортно, просто реализуя свою ICommand.


Я, как правило, использую MVVM light framework, который поставляется со встроенной RelayCommand.

вы добавляете свойство ICommand в модель представления, а затем назначаете ему relaycommand: -

ICommand ClickMeCommand {get;set;}
private void InitCommands()
{
   ClickMeCommand = new RelayCommand(()=>HasBeenClicked=true);
   //or
   ClickMeCommand = new RelayCommand(ClickMeEvent);
}
public void ClickMeEvent()
{
   HasBeenClicked=true;
}

в xaml вы просто используете обычную привязку: -

<Button Content='Push me' Command='{Binding ClickMeCommand}' />

пожалуйста, используйте перенаправленную команду, если вы не хотите создавать новый класс. вот небольшой фрагмент. Я создал маршрутизируемую команду как сохранить и привязать ее к привязке команды окна , поднять команду от кнопки.и вуаля!..... Надеюсь, это поможет вам

 public partial class Window1 : Window
 {
    public static readonly RoutedCommand Foo = new RoutedCommand();

    public Window1()
    {
        InitializeComponent();
    }

    void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        // The Window gets to determine if the Foo 
        // command can execute at this time.
        e.CanExecute = true;
    }

    void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        // The Window executes the command logic when the user wants to Foo.
        MessageBox.Show("The Window is Fooing...");
    }
}

 <Window.CommandBindings>
 <CommandBinding
  Command="{x:Static  local:Window1.Foo}"
  CanExecute="Foo_CanExecute"
  Executed="Foo_Executed"
  />

надеюсь, я хорошо понял вашу проблему.

PS: необходимость шаблона проектирования команды заключается в том, чтобы отделить логику выполнения и вызвать команду.Таким образом, класс Command-это способ чтобы инкапсулировать логику.


судя по тому, что вы делаете без запуска кода в VS, ваша проблема в том, что вы вызываете InitializeComponent (render XAML), затем установите DataContext без какого-либо значения, будучи в своей test свойство и, наконец, установить частный член. Как пользовательский интерфейс должен заметить, что ваша команда больше не имеет значения null (которое было последним значением, найденным в свойстве)?

почему бы не создать команду лениво так:

public ICommand test
{
    get
    { 
      if(testCommand== null)
      {
         testCommand= new MeCommand(processor);
       }
      return testCommand; 
    }
}

таким образом, он будет там, как только это потребуется и вам не нужно уведомление об изменении (если вы не измените эту команду позже во время выполнения).

кстати, есть несколько мест, где вы получаете ощущение, что код не выполняется в сценарии привязки команд:

1) CanExecute() возвращает false : просто верните true или оцените в соответствии с вашим бизнес-случаем.

2) условия изменения CanExecute, чтобы он вернул true, но он не вызывается: вы можете подключить свою команду с помощью Класс CommandManager, см. здесь. Убедитесь, что 1) решена, прежде чем попробовать это. Это гарантирует, что ваш пользовательский интерфейс запросит CanExecute довольно часто, и если этого все еще недостаточно, вызовите метод CommandManager.InvalidateRequerySuggested() явно.

3) Ваша привязка неправильная. Измените код привязки следующим образом:

Command="{Binding Path=test, PresentationTraceSources.TraceLevel=High}"

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


Ну, у тебя почти получается. Просто убедитесь, что CanExecute() вернет true, иначе ваш код не будет выполнен. (Я думаю, что это действительно будет, но все же). Также убедитесь, что добавьте " NotifyPropertyChanged ('yourCommand')" в

   public ICommand test
    {
        get { return testCommand; }
        set { testCOmmand = value; NotifyPropertyChanged("test"); }
    }

здесь.

можно делать тест = новый MeCOmmand(); DataContext = this;


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

public YourWindow() //your constructor
{
   ...
   //bind keyboard command shortcuts
   InputBindings.Add(new KeyBinding( //add a new key-binding, bind it to your command object which takes a delegate
      new WindowCommand(this)
      {
         ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
      }, new KeyGesture(Key.P, ModifierKeys.Control)));
   ...
}

создайте простой класс WindowCommand, который принимает делегат выполнения для запуска любого метода, установленного на нем.

public class WindowCommand : ICommand
{
    private MainWindow _window;
    public Action ExecuteDelegate { get; set; }

    public WindowCommand(MainWindow window)
    {
        _window = window;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        if (ExecuteDelegate != null)
        {
            ExecuteDelegate();
        }
        else
        {
            throw new InvalidOperationException();
        }
    }
}