How to Bind a Command in WPF
Asked Answered
G

6

14

Sometimes we used complex ways so many times, we forgot the simplest ways to do the task.

I know how to do command binding, but i always use same approach.

Create a class that implements ICommand interface and from the view model i create new instance of that class and binding works like a charm.

This is the code that i used for command binding

 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();
    }
}

But i want to know the basic way to do this, no third party dll no new class creation. Do this simple command binding using a single class. Actual class implements from ICommand interface and do the work.

Garden answered 12/12, 2012 at 11:36 Comment(0)
K
16

Prism already provided Microsoft.Practices.Prism.Commands.DelegateCommand

I'm not sure is it considered as 3rd party. At least it's official and documented on MSDN.

Some native build-in commands such copy, paste implements ICommand interface. IMHO it following the Open(for extends)/Close(for changes) principle. so that we can implement our own command.


Update

As WPF Commanding documented here, an excerpt...

WPF provides a set of predefined commands. such as Cut, BrowseBack and BrowseForward, Play, Stop, and Pause.

If the commands in the command library classes do not meet your needs, then you can create your own commands. There are two ways to create a custom command. The first is to start from the ground up and implement the ICommand interface. The other way, and the more common approach, is to create a RoutedCommand or a RoutedUICommand.

I've tried RoutedCommand model at the beginning and ended up with implementing ICommand.

sample XAML binding

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

RoutedCommand is not different from RoutedEvent. this seems like a better button's 'Clicked' event handler. It serves the purpose: To separate app logic from View but require some attach DependencyProperty or code-behind.

personally I feel more comfortable with just implement my ICommand.

Ketose answered 12/12, 2012 at 12:7 Comment(5)
It is definately considered as third party. I dont have any kind of grudge against thirsd party. I am using GalaSoft MVVM but i want to know the simple, basic, actual way to di it. Thanks anyways.Garden
Upvoted for being the only guy who seem to have actually read the question.Intuitional
@Intuitional Constructive comment for being the only guy who understands my pain. :-)Garden
Did actually checked DelegateCommand ? Minimal implementation look like this. And in your ViewModel class you write public ICommand Save { get { return new DelegateCommand(new Action<object>((t) => { ViewModelMethodSave(); })); } } It looks pretty simple for me.Mover
updated my answer. WPF didn't provided any simple command binding out of the box. the RoutedCommand they claim to be common approach is not suitable for View-ViewModel binding. You need attachable dependency property.Ketose
L
3

I tend to use the MVVM light framework which comes with a RelayCommand built in.

You add an ICommand property to your view model, then assign a relaycommand to it:-

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

In the xaml you just use normal binding:-

<Button Content='Push me' Command='{Binding ClickMeCommand}' />
Lentz answered 20/12, 2012 at 16:38 Comment(0)
K
2

Please use routed command in case of you don't want to create new class. here is a small snippet. I have created a routed command as Save and bind it to command binding of window , raise the command from button.and voila!..... I hope this may help you

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

I hope I understood your problem well.

PS: The need of command design pattern is to decouple the logic of execution and invoker of command.So Command class is a way to encapsulate the logic.

Klecka answered 20/12, 2012 at 5:38 Comment(0)
E
1

Judging from what you do without running the Code in VS, your problem is that you call InitializeComponent (render XAML), then set the DataContext without any value being in your test Property and finally set a private member. How is the UI supposed to notice that your Command is not null anymore (which was the last value it found in the Property)?

Why not instanciate the Command lazily like so :

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

That way it will be there as soon as it's required and you don't need Change notification (unless you change that command later at runtime).

By the way, there's a few spots where you get the feeling no code is being executed in the Command Binding scenario :

1) CanExecute() returns false : just return true or evaluate according to your business case.

2) The conditions of CanExecute change, so that it would return true, but it doesn't get called: You can hook your Command up with the CommandManager class, see here. Make sure 1) is solved before you try this. This ensures that your UI will requery the CanExecute pretty frequently, and if that is still not enough, call the Method CommandManager.InvalidateRequerySuggested() explicitly.

3) Your Binding is wrong. Change the binding code like so:

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

This will spam your output window whenever the value of the binding is pulled or pushed. Look out for the term "using final value". If it's null, your Command isn't where it's supposed to be (yet).

Embellish answered 18/12, 2012 at 12:11 Comment(3)
My binding is fine, no problem about that. I just want to know how to bind the command without Implementing ICommand in another class and then use that class. In my case its MeCommand.Garden
CommandBinding only works with implementations of ICommand. It's WPF Convention, can't be helped. Probably you might want to think about using something like the RelayCommand found here. Check it out.Embellish
Honestly, why downvote all of us? Think that this helps the community?Embellish
E
0

Well, you almost have it. Just make sure that CanExecute() will return true, otherwise your code won't be executed. (I think it actually will, but still). Also make sure that add "NotifyPropertyChanged('yourCommand')" to

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

to here.

You can alternatively do test = new MeCOmmand(); DataContext = this;

Elfie answered 16/12, 2012 at 9:38 Comment(3)
Where is the method that i want to execute upon execution of this command? and In alternatively section you are saying to use MeCommand class, but i dont want to use any custom class as i mentioned.Garden
As already said, command system is impemented by WPF and you can't change that. There are implementations such as RelayCommand/DelegateCommand, but if you want to use commands, you have to implement ICommand interface. SImple as that. Perhaps start using events if you want direct method execution.Elfie
You Downvote just because just you haven't made yourself clear in your question. Not good style.Embellish
H
0

In the WPF Window constructor, to link a keyboard shortcut, simply add a binding with a delegate, and associate it with a key gesture.

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)));
   ...
}

Create a simple WindowCommand class which takes an execution delegate to fire off any method set on it.

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();
        }
    }
}
Hygrothermograph answered 27/7, 2016 at 0:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.