How to bind WPF button to a command in ViewModelBase?
Asked Answered
M

1

67

I have a view AttributeView that contains all sorts of attributes. There's also a button that when pressed, it should set the default values to the attributes. I also have a ViewModelBase class that is a base class for all ViewModels I have. The problem is I can't seem to get the button bound to the command with WPF.

I've tried this, but it just doesn't do anything:

<Button Command="{Binding DataInitialization}" Content="{x:Static localProperties:Resources.BtnReinitializeData}"></Button>

The command is defined (in the ViewModelBase) like this:

public CommandBase DataInitialization { get; protected set; }

and on application startup a new instance is created for the command:

DataInitialization = new DataInitializationCommand()

However, the WPF binding doesn't seem to "find" the command (pressing the button does nothing). The ViewModel used in the current view is derived from the ViewModelBase. What else I can try (I'm quite new to WPF so this might be a very simple question)?

Marnamarne answered 14/9, 2012 at 10:45 Comment(6)
Does the CommandBase inherits from ICommand? Does the Buttons DataContext contains DataInitialization command? Do you have any message in output panel about the binding?Efficiency
Yes it inherits ICommand. How do I check the button's DataContext? I'm not sure about the messages in output (should there be any by default?).Marnamarne
it would be easier if you show more code about the viewmodel and the xamlEfficiency
Can you please show your VM code where the members of ICommand interface are implemented.Hyaena
Do you mean the DataInitializationCommand code (which derives from CommandBase, which in turn implements the ICommand)? How does the VM relate to ICommand interface?Marnamarne
It will be the property of your VM that will be bound to your Command of Button.Hyaena
H
157
 <Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Button Command="{Binding ClickCommand}" Width="100" Height="100" Content="wefwfwef"/>
</Grid>

the code behind for the window:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModelBase();
    }
}

The ViewModel:

public class ViewModelBase
{
    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), ()=> CanExecute));
        }
    }
     public bool CanExecute
     {
        get
        {
            // check if executing is allowed, i.e., validate, check if a process is running, etc. 
            return true/false;
        }
     }

    public void MyAction()
    {

    }
}

Command Handler:

 public class CommandHandler : ICommand
{
    private Action _action;
    private Func<bool> _canExecute;

    /// <summary>
    /// Creates instance of the command handler
    /// </summary>
    /// <param name="action">Action to be executed by the command</param>
    /// <param name="canExecute">A bolean property to containing current permissions to execute the command</param>
    public CommandHandler(Action action, Func<bool> canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    /// <summary>
    /// Wires CanExecuteChanged event 
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Forcess checking if execute is allowed
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute.Invoke();
    }

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

I hope this will give you the idea.

Hyaena answered 14/9, 2012 at 11:51 Comment(9)
This gave me a clue where to search. It turned out that the command was initialized in multiple places and one of these places (the correct one) had been commented out :) Thanks!Marnamarne
Yes this is the best explanation i found after many lookups. Thanks @EthicallogicsOvergrow
this is a very good example for command binding. But I'm curious that, is it a common practice that put command object inside viewmodel (or viewmodalbase)? @ethicallogics . Or create a class and put all the command object in that class (so that we can reference)?Aviv
Looks like you forgot to initialize the _clickCommand, hence your example will always create new CommandHandler objects whenever the ClickCommand property will be accessed...Hereabout
How would you extend this to have multiple actions for various different buttons? Do you required a whole new ViewModel for each button?Silvern
what is the purpose of _canExecute? Can't we just set that to true? e.g. return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), true));Elbertina
The purpose of CanExecute is to let you decide if the command is executable at the time of evaluating. If it evaluates to false, the control is usually disabled. Just setting it to true is common and perfectly okay.Jan
Also, to work with _canExecute, you have to implement notification about this. And WPF have builtin default mechanism to requery CanExecute property. But to do this your ICommand have to resubscribe to default command manager, like this: ` public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } `Carding
How we can pass command argument with it, is it even possibleLowborn

© 2022 - 2024 — McMap. All rights reserved.