1
votes

I want to display either no context menu or a single item or two items in the context menu. I am using the MVVM pattern.

I have tried linking the context menu visibility to a bool property, this appears to work, but an empty context menu is rendered behind the current control, and becomes visible once the current control is closed. I've tried adding a data trigger bound to the same property - but this does not get fired. examining the visual tree shows that the default property is set for the context menu.

MenuItem Visibility works fine, so I can get 1 or 2 items displaying. But when No context menu is needed, a blank menu appears behind enter image description here

Note: same results with Visibility Hidden or Collapsed

The context menu is bound to a DataGrid as a static resource:

  RowStyle="{StaticResource PagedGridRowStyle}"
       <ContextMenu x:Key="BlankMenu" Visibility="Hidden">
        </ContextMenu>
        <ContextMenu x:Key="PagedGridMenu"
                     Visibility="{Binding Path=DataContext.ContextMenuEnabled, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource VisConverter}}"
                     DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
            <MenuItem Header="{Binding Path=DataContext.MenuActionName1, RelativeSource={RelativeSource AncestorType=UserControl}}"
                      Visibility="{Binding Path=DataContext.ContextMenuEnabled, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource VisConverter}}"
                      CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}"
                      Command="{Binding Path=DataContext.MenuActionCommand1, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
            <MenuItem Header="{Binding Path=DataContext.MenuActionName2, RelativeSource={RelativeSource AncestorType=UserControl}}"
                      Visibility="{Binding Path=DataContext.ContextMenu2Enabled, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource VisConverter}}"
                      CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}"
                      Command="{Binding Path=DataContext.MenuActionCommand2, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
        </ContextMenu>
        <Style x:Key="PagedGridRowStyle"
               TargetType="{x:Type DataGridRow}">
            <Setter Property="ContextMenu"
                    Value="{StaticResource PagedGridMenu}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ContextMenuEnabled}" Value="false">
                    <Setter Property="ContextMenu" Value="{StaticResource BlankMenu}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

Note VisConverter simply toggles Visibility.Visible and Visibility.Collapsed on the boolean value

Style.Triggers - above: This is an attempt to replace the complete context menu - to try to avoid the blank context menu opening behind control. - but it doesn't get fired.

       private bool _contextMenu2Enabled;
        public bool ContextMenu2Enabled
        {
            get => _contextMenu2Enabled;
            set
            {
                _contextMenu2Enabled = value;
                OnPropertyChanged();
            }
        }

        private bool _contextMenuEnabled;
        public bool ContextMenuEnabled
        {
            get => _contextMenuEnabled;
            set
            {
                _contextMenuEnabled = value;
                OnPropertyChanged();
            }
        }

Binding Error:

When ContextMenuEnabled = false: (and ContextMenu2Enabled = false)

System.Windows.Data Error: 40 : BindingExpression path error: 'ContextMenuEnabled' property not found on 'object' ''DataRowView' (HashCode=33440573)'. BindingExpression:Path=ContextMenuEnabled; DataItem='DataRowView' (HashCode=33440573); target element is 'DataGridRow' (Name=''); target property is 'NoTarget' (type 'Object')

The Context menu does not appear, but an empty context menu is rendered behind the datagrid, and becomes visible after the datagrid is closed

When ContextMenuEnabled = true (and ContextMenu2Enabled = false) Same BindingExpression Error - but the context menu shows a single item as expected.

When ContextMenuEnabled = true and ContextMenu2Enabled = true Same BindingExpression error, - but Both Context menu items are shown as expected.

1
Where is the ContextMenuEnabled property defined? And why don't you just set the ContextProperty to null instead of setting it to an empty menu with no items: <Setter Property="ContextMenu" Value="{x:Null}"/>? - mm8
ContextMenuEnabled is on the ViewModel . Thanks for informing me about {x:Null} I now know how to nullify in xaml :) And I changed the data trigger binding to Binding="{Binding DataContext.ContextMenuEnabled, RelativeSource={RelativeSource AncestorType=UserControl}}" which has solved the problem and fixed the BindingExpression Errors - TomFp

1 Answers

1
votes

Instead of displaying an empty ContextMenu, you could set the ContextMenu property to null in your setter:

<Setter Property="ContextMenu" Value="{x:Null}"/>

And if the ContextMenuEnabled property is defined in your view model, you should use a RelativeSource to bind to it:

Binding="{Binding DataContext.ContextMenuEnabled, 
   RelativeSource={RelativeSource AncestorType=UserControl}}"