5
votes

In my WPF application I have a sort of node graph. I have added a ContextMenu to these nodes, which appears when I right-click on stuff and so on.

The commands in the context menu come from a Service (Microsoft.Practices.ServiceLocation.ServiceLocator) with DelegateCommands, and those commands are updated with RaiseCanExecuteChanged(). The node that was right-clicked on is passed to this command service, which is used in the various CanExecute methods for the commands.

The nodes all have some properties which are used in these conditions, like whether it can be renamed or deleted, etc.

    private void ContextMenu_ContextMenuOpening(object sender, RoutedEventArgs e) {
        ServiceLocator.Current.GetInstance<IMenuCommandService>().ReloadICommandConditions();
    }

in IMenuCommandService:

    public void ReloadICommandConditions() {
        ((DelegateCommand<Node>) MyCommand).RaiseCanExecuteChanged();
    }

My ContextMenu (inside a DataTrigger & Setter):

<ContextMenu>
    <MenuItem Header="Rename"
              Command="{Binding MenuCommandService.Rename}"
              CommandParameter="{Binding Node}" />
    <MenuItem Header="Delete"
              Command="{Binding MenuCommandService.Delete}"
              CommandParameter="{Binding Node}" />
    ...
</ContextMenu>

My problem is that when I right click one of these nodes, the context menu that is displayed looks like it was configured for the previous node selected. Like if I right-click a deleteable node and then a non-deleteable node, the "Delete" command on the context menu will still be clickable. (If I then right-click the non-deleteable node, the context menu will then be correct and the "Delete" command is greyed out.)

So it looks like there's some sort of delay from when the changes made after RaiseCanExecuteChanged() is actually there for the contextmenu to "pick up". I could do a crude fix and only show the contextmenu after they have been updated (i.e. their CanExecute methods have been called), but I'd like to keep the two parts relatively separate.

Is there something obvious I'm missing, am I going about this in the wrong way, or does anyone have any other suggestions?

Thanks

1
Have you debugged through until the CanExecute() of any of your commands and checked the conditions there ? I don't think this is a delay problem but it will be the conditionvalues you check in your CanExecute like for example the currentSelectedNode or something. Maybe your SelectedNode is still the previous one when calling ContextMenuOpening ?KroaX
@Kroax The parameter of the CanExecute() methods is supplied by the ContextMenu: <MenuItem Header="Rename" Command="{Binding MenuCommandService.Rename}" CommandParameter="{Binding Node}" />. This parameter is being supplied correctly when the actual items in the contextmenu are clicked, but they aren't when it's first opened.Pyritie

1 Answers

0
votes

Sort-of-solved -- I'm now manually passing the node that was right-clicked on to my MenuCommandService through that ReloadICommandConditions() method, and it's holding a local reference to it, which it then uses instead of the parameter in its CanExecute() methods. Crude, but at least it works.

I'll keep this open for now in case anyone knows of a way that's a bit more... elegant.