AvalonDock + UserControl + DataGrid + ContextMenu command routing issue

May 17, 2010 at 6:27 PM

Duplicating my StackOverflow question here (http://stackoverflow.com/questions/2835759/) , since no-one answers it there even after I added bounty to it:

I'm getting weird behavior with command propagation from MenuItems of ContextMenu.

I have the following kind of layout: ContextMenu is set for each DataGridRow of DataGrid inside UserControl, which in its turn is inside DockableContent of AvalonDock. If I get rid of either docking or UserControl around my grid there are no problems. ListBox instead of DataGrid doesn't have this issue either.

<Window x:Class="DockAndMenuTest.MainWindow"
       
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
       
Title="MainWindow" Height="350" Width="525">
   
<ad:DockingManager>
       
<ad:DocumentPane>
           
<ad:DockableContent Title="Doh!">
               
<UserControl>
                   
<UserControl.CommandBindings>
                       
<CommandBinding Command="Zoom"
                                       
Executed="ExecuteZoom"
                                       
CanExecute="CanZoom"/>
                   
</UserControl.CommandBindings>
                   
<DataGrid Name="_evilGrid">
                       
<DataGrid.Resources>
                           
<Style TargetType="DataGridRow">
                               
<Setter Property="ContextMenu">
                                   
<Setter.Value>
                                       
<ContextMenu>
                                           
<MenuItem Command="Zoom"/>
                                       
</ContextMenu>
                                   
</Setter.Value>
                               
</Setter>
                           
</Style>
                       
</DataGrid.Resources>
                   
</DataGrid>
               
</UserControl>
           
</ad:DockableContent>
       
</ad:DocumentPane>
   
</ad:DockingManager>
</Window>

Code-behind is trivial as well:

public partial class MainWindow
{
   
public MainWindow()
   
{
       
InitializeComponent();

        _evilGrid
.ItemsSource =
           
new[]
               
{
                   
Tuple.Create(1, 2, 3),
                   
Tuple.Create(4, 4, 3),
                   
Tuple.Create(6, 7, 1),
               
};
   
}

   
private void ExecuteZoom(object sender, ExecutedRoutedEventArgs e)
   
{
       
MessageBox.Show("zoom !");
   
}

   
private void CanZoom(object sender, CanExecuteRoutedEventArgs e)
   
{
        e
.CanExecute = true;
   
}
}

So here's the problem: right-clicking on the selected row (if it it was selected before the right click) my command comes out disabled. The command is "Zoom" in this case, but can be any other, including a custom one.

I don't know what's at fault here. SNOOP shows that in cases when this propagation fails, instead of UserControl, CanExecute is handled by "PART_ShowContextMenuButton" (Button), which is part of docking header.

I've had other issues with UI command propagation within UserControls hosted inside AvalonDock, but this one is the easiest to reproduce.

May 18, 2010 at 8:35 AM
Try to force command target on context menu adding:

CommandTarget="{Binding ElementName=_evilGrid}"

Ado

From: [email removed]
Sent: Monday, May 17, 2010 8:27 PM
To: [email removed]
Subject: AvalonDock + UserControl + DataGrid + ContextMenu command routing issue [AvalonDock:212933]

From: martsyn

Duplicating my StackOverflow question here (http://stackoverflow.com/questions/2835759/) , since no-one answers it there even after I added bounty to it:

I'm getting weird behavior with command propagation from MenuItems of ContextMenu.

I have the following kind of layout: ContextMenu is set for each DataGridRow of DataGrid inside UserControl, which in its turn is inside DockableContent of AvalonDock. If I get rid of either docking or UserControl around my grid there are no problems. ListBox instead of DataGrid doesn't have this issue either.

<Window x:Class="DockAndMenuTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
Title="MainWindow" Height="350" Width="525">
<ad:DockingManager>
<ad:DocumentPane>
<ad:DockableContent Title="Doh!">
<UserControl>
<UserControl.CommandBindings>
<CommandBinding Command="Zoom"
Executed="ExecuteZoom"
CanExecute="CanZoom"/>
</UserControl.CommandBindings>
<DataGrid Name="_evilGrid">
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Command="Zoom"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
</UserControl>
</ad:DockableContent>
</ad:DocumentPane>
</ad:DockingManager>
</Window>

Code-behind is trivial as well:

public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();

_evilGrid
.ItemsSource =
new[]
{
Tuple.Create(1, 2, 3),
Tuple.Create(4, 4, 3),
Tuple.Create(6, 7, 1),
};
}

private void ExecuteZoom(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("zoom !");
}

private void CanZoom(object sender, CanExecuteRoutedEventArgs e)
{
e
.CanExecute = true;
}
}

So here's the problem: right-clicking on the selected row (if it it was selected before the right click) my command comes out disabled. The command is "Zoom" in this case, but can be any other, including a custom one.

I don't know what's at fault here. SNOOP shows that in cases when this propagation fails, instead of UserControl, CanExecute is handled by "PART_ShowContextMenuButton" (Button), which is part of docking header.

I've had other issues with UI command propagation within UserControls hosted inside AvalonDock, but this one is the easiest to reproduce.

May 21, 2010 at 9:27 PM

Alright, I finally solved it with the help of some pointers from my post on stackoverflow: http://stackoverflow.com/questions/2835759/

The solution is to make UserControl an individual focus scope by doing:

 

<UserCotrol FocusManager.IsFocusScope="True">