0

I have a View with a button as follows:

<Button Grid.Column="2" Grid.Row="1" Content="Test" Margin="10,4" 
        Command="{Binding DataContext.CmdTestButtonClicked}" 
        CommandParameter="{Binding}" />

In the view's code-behind, I set the DataContext to the ViewModel:

public GlobalSettings()
{
    InitializeComponent();

    ...

    DataContext = Helpers.IoCHelper.GlobalSettingsVM;

    ...
}

My ViewModel derives from a base class which exposes the ICommand:

public class GlobalSettingsVM : CollectionViewModel<GlobalSettings> { ... }

public abstract class CollectionViewModel<TModel> : IInstallModuleViewModel, INotifyPropertyChanged,
        INotifyDataErrorInfo where TModel : Model, new()
{
    ...

    public ICommand CmdTestButtonClicked
    {
        get
        {
            return _testButtonClicked ??
                   (_testButtonClicked = new RelayCommand(TestButtonClicked));
        }
    }

    protected virtual void TestButtonClicked(object o)
    {
        // I never get here
    }
}

I don't have any other issues using this pattern throughout my application, however all my other implementations have the Button within a ListView, so there I have to use RelativeSource={RelativeSource AncestorType={x:Type ListView}}.

Why would this command never fire? Do I need to set a RelativeSource here as well?

Mark Richman
  • 28,948
  • 25
  • 99
  • 159
  • 1
    I would try changing the `Command` on the `Button` to `{Binding Path=CmdTestButtonClicked}` otherwise you are attempting access the `DataContext` of the button which has not been set. – Stephen Ross May 12 '16 at 16:33

3 Answers3

1

This

Command="{Binding DataContext.CmdTestButtonClicked}" 

Implies that the Command will look for a property called DataContext in the object to which the button is bound. If the DataContext of the button is a GlobalSettingsVM this should work:

Command="{Binding CmdTestButtonClicked}" 
Natxo
  • 2,917
  • 1
  • 24
  • 36
  • Thanks, that solved it. I assumed the Button would just inherit the DataContext of its parent. I use the DataContext prefix elsewhere throughout my application without explicitly setting a control's DataContext and it works. Perhaps it's because I also set RelativeSource on those? – Mark Richman May 12 '16 at 17:12
  • @MarkRichman, Indeed every control inherits the DataContext of its container. And yes, when you use RelativeSource youe are refering to a property of the control itself, not of the bound viewmodel. – Natxo May 13 '16 at 07:43
  • And as a piece of advice, if you use RelativeSource to reference a DataContext you are (usually) doing something wrong or it's symptom of poor design. – Natxo May 13 '16 at 07:53
0

You could also use the MVVM Light toolkit wich is very convenient and helping on these situations.

You would get Something like this :

<Button Grid.Column="2" Grid.Row="1" Content="Test" Margin="10,4" 
     <i:Interaction.Triggers>
           <i:EventTrigger EventName="OnClick" >
                 <Command:EventToCommand Command="{Binding DataContext.CmdTestButtonClicked}" CommandParameter="{Binding}" PassEventArgsToCommand="True"/>
            </i:EventTrigger>
      </i:Interaction.Triggers>
RizzCandy
  • 121
  • 9
0

In my case, I was listening to PreviewMouseLeftButtonDown under constructor of xaml.cs class which was stopping command event callback to the view model.

 this.PreviewMouseLeftButtonDown += (s, e) => DragMove();

Instead of above line, in xaml file for window added MouseLeftButtonDown="Window_MouseLeftButtonDown" click handler and handled window drag within it, as below

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove();
}
mabiyan
  • 667
  • 7
  • 25