Alain
Alain

Reputation: 27250

Trouble binding a hyperlink Command an ICommand in my view

I'm binding the command property of two hyperlinks in my xaml to a command in the view (which is the datacontext):

<TextBlock>
   <Hyperlink x:Name="linkCheckAll" Command="{Binding CheckAllZonesCommand}" CommandParameter="{Binding}">Check All</Hyperlink>
   <TextBlock Margin="0,0,20,0"/>
   <Hyperlink x:Name="linkUncheckAll" Command="{Binding UncheckAllZonesCommand}" CommandParameter="{Binding}">Uncheck All</Hyperlink>
</TextBlock>

Which looks like this:

enter image description here

I'm getting the following error when binding my commands:

System.Windows.Data Error: 40 : BindingExpression path error: 'CheckAllZonesCommand' property not found on 'object' ''ZonesView' (HashCode=56756307)'. BindingExpression:Path=CheckAllZonesCommand; DataItem='ZonesView' (HashCode=56756307); target element is 'Hyperlink' (HashCode=50738642); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 40 : BindingExpression path error: 'UncheckAllZonesCommand' property not found on 'object' ''ZonesView' (HashCode=56756307)'. BindingExpression:Path=UncheckAllZonesCommand; DataItem='ZonesView' (HashCode=56756307); target element is 'Hyperlink' (HashCode=53994596); target property is 'Command' (type 'ICommand')

"ZonesView" is my my dataContext, and I'm positive it contains the commands in question:

public class ZonesView : BaseViewModel
{
    public static ICommand CheckAllZonesCommand = new DelegateCommand()
    {
        ExecuteMethod = new Action<object>(delegate(object o) { ((ZonesView)o).CheckAllZones(); }),
        CanExecuteMethod = new Func<bool>(delegate() { return true; })
    };
    public void CheckAllZones()
    {
        foreach( CheckBox cb in ZonesCheckBoxes.Values.Where(cb => (cb.IsChecked != true) && cb.Name.Contains((String)ActiveTab.Header) ))
        {
            cb.IsChecked = true;
            ZoneCheckBoxClicked(cb, null);
        }
    }

    public static ICommand UncheckAllZonesCommand = new DelegateCommand()
    {
        ExecuteMethod = new Action<object>(delegate(object o) { ((ZonesView)o).UncheckAllZones(); }),
        CanExecuteMethod = new Func<bool>(delegate() { return true; })
    };
    public void UncheckAllZones()
    {
        foreach( CheckBox cb in ZonesCheckBoxes.Values.Where(cb => (cb.IsChecked != false) && cb.Name.Contains((String)ActiveTab.Header)) )
        {
            cb.IsChecked = false;
            ZoneCheckBoxClicked(cb, null);
        }
    }

From what I can tell, I've done everything right. The commands are public, they are the correct type, and the datacontext of the hyperlinks is correct (as you can tell by the BindingExpression path error message) - so what's going wrong?


I've tried making the Commands in the ZonesView class static, but it didn't change anything.

Upvotes: 1

Views: 8254

Answers (3)

Alain
Alain

Reputation: 27250

I guess the solution is similar to some of the things posted, but it isn't the same as any of them. I'm not sure about the subtleties of this difference, but by merely making my commands private, and then returning them through a public property get method, it started working:

public ICommand PublicCommand { get { return _privateCommand; } }

Here's the fix to the above code:

protected static DelegateCommand _CheckAllZonesCommand = new DelegateCommand()
{
    ExecuteMethod = new Action<object>(delegate(object o) { ((ZonesView)o).CheckAllZones(); }),
    CanExecuteMethod = new Func<bool>(delegate() { return true; })
};
public ICommand CheckAllZonesCommand { get { return _CheckAllZonesCommand; } }

protected static DelegateCommand _UncheckAllZonesCommand = new DelegateCommand()
{
    ExecuteMethod = new Action<object>(delegate(object o) { ((ZonesView)o).UncheckAllZones(); }),
    CanExecuteMethod = new Func<bool>(delegate() { return true; })
};
public ICommand UncheckAllZonesCommand { get { return _UncheckAllZonesCommand; } }

Upvotes: 0

k.m
k.m

Reputation: 31484

Since my comment raised no attention whatsoever: you should be binding to properties, but you do to fields instead. Explanation of why it's done this way has already been provided in this question:

Change CheckAllZonesCommand and UncheckAllZonesCommand to properties:

public ICommand UncheckAllZonesCommand { get; set; }
public ICommand CheckAllZonesCommand { get; set; }

And initialize them in, let's say - constructor.

Upvotes: 7

Muad&#39;Dib
Muad&#39;Dib

Reputation: 29266

try something like this... so that you are biding to properties, not fields. you may even want to raise PropertyChanged events in the setter.

public class ZonesView : BaseViewModel
{
   public ZonesView()
   {
      this.CheckAllZonesCommand = new DelegateCommand()
      {
         ExecuteMethod = new Action<object>(delegate(object o){ ((ZonesView)o).CheckAllZones(); }),
         CanExecuteMethod = new Func<bool>(delegate() { return true; })
       };
   }

    public ICommand CheckAllZonesCommand {get;private set;}
}

Upvotes: 1

Related Questions