views:

218

answers:

4

I create a VM based on MVVM light toolkit. In VM, there is a simple ICommand(RelayCommand)

  private RelayCommand _myCommand = null;
    public RelayCommand MyCommand
    {
        get
        {
            if (_myCommand == null)  //set break point here for debug
            {
                _myCommand = new RelayCommand(() =>
                {
                    try
                    {
                       //....
                    }
                    catch (Exception ex)
                    {
                        // notify user if there is any error
                        //....
                    }
                }
                , () => true);
            }
            return _myCommand;
        }
    }

then in xaml, just bind this Command property to a button like:

 <Button Grid.Column="1"  x:Name="Test" Content="Test" Margin="2,0,2,0" Command="{Binding Path=MyCommand}" />

Then run the app, and click on the button, there is no response at all. No error. VM is working fine. The data has been loaded to a datagrid before I click on the Test button.

If debug the app and put break point, the point is never reached.

How to resolve this problem?

+2  A: 

Add a setter to your MyCommand property.

As always, check the Output window for any data binding errors when the XAML is rendered.

Also, try adding a test value converter and putting a breakpoint in the convert method to see if data binding is even being executed on that command. If the breakpoint isn't hit, you know you have a problem in your XAML. If the breakpoint is hit, take a look at the value to see if the data context is correct.

<UserControl.Resources>
    <ResourceDictionary>
        <TestConverter x:Key="TestConverter" />
    </ResourceDictionary>
    <Button Grid.Column="1" x:Name="Test" Content="Test" Margin="2,0,2,0" Command="{Binding Path=MyCommand, Converter={StaticResource TestConverter}}" />
</UserControl>

Test value converter - very useful for debugging data binding issues.

public class TestConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Debug.WriteLine("TestConverter.Convert(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
            value, targetType, parameter, culture);
        return value; // put break point here to test data binding
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Debug.WriteLine("TestConverter.ConvertBack(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
            value, targetType, parameter, culture);
        return value;
    }
}
Matt Casto
Just to clarify, setters are not necessary for the Command binding to work. A setter would, however, be useful so you don't have to put all that messy code in one getter like that. Yuck!
Brian Genisio
love the idea of testconverter. any more related (or completely unrelated) tips?
Simon_Weaver
+2  A: 

Works on my machine :)

Seriously, I made a simple project, created a ViewModel, pasted in your code, and it worked. I am guessing you are dealing with some other issue.

Here is my C# code.

Here is my XAML code.

Time to evangelize a bit

This ViewModel code reeks. You might consider using some sort MVVM framework or helpers. If you look at ViewModelSupport, for instance, you can write your ViewModel like this:

public class MyViewModel : ViewModelBase
{
    public void Execute_MyCommand()
    {
        // Your execution code here
    }
}

Then, you avoid all that messy plumbing. Just think about it :)

Brian Genisio
I hadn't thought of some of the stuff you're doing in your base ViewModel class. I especially like the DependentUpon attribute. Very nice!
Matt Casto
A: 

the code looks fine. so you just have to check the output window for databinding errors. maybe you did not set the datacontext of the view correct. btw you should add your breakpoint in the try-catch of the command.

blindmeis
A: 

1) Make sure you're returning true from the relay command's CanExecute delegate. (I see you are doing this but good to double check).

2) Is the button inside a ListBox, DataGrid or DataForm?

For a ListBox or DataGrid:

If so you need to modify your binding expression to refer to the VM DataContext as opposed to the databound item. See this answer.

For a DataForm :

More tricky, but look at this question.

Simon_Weaver