Подтвердить что ты не робот

Как связать команду в 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 и выполняет работу.

4b9b3361

Ответ 1

Призма уже предоставлена ​​Microsoft.Practices.Prism.Commands.DelegateCommand

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

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


Update

Поскольку WPF Commanding зарегистрировал здесь, выдержка...

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

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

Я пробовал модель RoutedCommand в начале и в итоге реализовал ICommand.

образец привязки XAML

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

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

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

Ответ 2

Я имею тенденцию использовать фреймворк MVVM, который поставляется с встроенной RelayCommand.

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

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}' />

Ответ 3

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

 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: Необходимость шаблона проектирования команд заключается в том, чтобы отделить логику выполнения и invoker от команды. Такой класс Command является способом инкапсуляции логики.

Ответ 4

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

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

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}"

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

Ответ 5

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

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

здесь.

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

Ответ 6

В конструкторе окна 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();
        }
    }
}