0

Not sure if this is something I am not understanding about WPF or about Catel, but I have a treeview with 3 datatemplates for different node types. 2 of the node types can be bound to a delete button. The binding of the button command binds to the viewmodel of the parent control (rather than to the node itself) and a command parameter of the node where the button was clicked is passed. I am providing a small snippet of one of the data templates (the whole thing is too large to enter here):

<Grid Margin="10" x:Name="CriteriaGrid">
   <TreeView ItemsSource="{Binding Criteria}" >
     <DataTemplate DataType="{x:Type self:Leaf}">
         <Button Command="{Binding Source={x:Reference CriteriaGrid}, Path=DataContext.DeleteLeaf}" 
                 CommandParameter="{Binding}">X</Button>

     </DataTemplate>
   </TreeView>
</Grid>

ViewModel (again just a small extract):

public class ManageCriteriaViewModel : ViewModelBase
{
    public ManageCriteriaViewModel()
    {
        DeleteLeaf = new Command<Leaf>(OnDeleteLeaf, CanDeleteLeaf);
    }

    private bool CanDeleteLeaf(Leaf leafNode)
    {
        return (leafNode?.Parent as Group) != null;
    }

    private void OnDeleteLeaf(Leaf leafNode)
    {
        // Some code
    }

    public Command<Leaf> DeleteLeaf { get; private set; }
}

The problem is that when the Tree is initially being constructed, the command parameter is always null, and my CanExecute test returns false if the parameter is null. So when my tree initially displays, all my buttons are disabled.

However, if I click any of the buttons, all of them get re-evaluated and become enabled because now the command parameter is being passed correctly.

I have tried adding:

protected override Task InitializeAsync()
{
    CommandManager.InvalidateRequerySuggested();
    ViewModelCommandManager.InvalidateCommands(true);
    return base.InitializeAsync();
}

In an attempt to re-evaluate all the commands after the UI is loaded but this does not seem to work. What am I missing here?

Bitfiddler
  • 3,942
  • 7
  • 36
  • 51

1 Answers1

0

Try switching the order of the command parameter and command object. The reason is that the CommandParameter is not bindable, and does not raise any change notifications. Therefore, the command is not being re-evaluated after "updating" (it's still the initial binding process).

If that doesn't work, something like this could:

protected override async Task InitializeAsync()
{
    await base.InitializeAsync();

    _dispatcherService.BeginInvoke(() => ViewModelCommandManager.InvalidateCommands(true););
}
Geert van Horrik
  • 5,689
  • 1
  • 18
  • 32
  • Thanks for the suggestions Geert, I tried both options and neither seems to work. Perhaps I need to dive deeper and debug the source. Maybe something is going on under the covers that would explain why InvalidateCommands does not do the same thing as clicking the mouse. – Bitfiddler Apr 14 '16 at 17:53
  • Try using object as parameter instead, that night help you find the issue – Geert van Horrik Apr 14 '16 at 21:36
  • Tried using object, unfortunately the parameter is simply null the first time the tree is displayed. – Bitfiddler Apr 26 '16 at 18:06