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?

0

1 Answer 1

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););
}
Sign up to request clarification or add additional context in comments.

3 Comments

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.
Try using object as parameter instead, that night help you find the issue
Tried using object, unfortunately the parameter is simply null the first time the tree is displayed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.