1
votes

Recently I am developing a context menu in WPF with the following requirement,

If all the menu items in the context menu have Visibility Hidden, set the context menu visibility to Hidden.

I have a solution myself for this in a DataTemplate, which is to set ContextMenu Hidden as default, and use a Trigger for each menu item to check their visibility, if any of them is visible, trigger the ContextMenu visibility into visible.

So the code is like

<DataTemplate>
    <ContextMenu Visibility="Hidden" x:Name="contextMenu">
        <MenuItem x:Name="menuItem1" Visibility="{Binding somebinding}" />
        <MenuItem x:Name="menuItem2" Visibliity="{Binding somebinding}" />
    </ContextMenu>
    <DataTemplate.Trigger>
        <Trigger SourceName="menuItem1" Propert"Visibility" Value="Visible">
            <Setter TargetName="contextMenu" Property="Visibility" Value="Visible" />
        </Trigger>
        <Trigger SourceName="menuItem2" Propert"Visibility" Value="Visible">
            <Setter TargetName="contextMenu" Property="Visibility" Value="Visible" />
        </Trigger>
    </DataTemplate.Trigger>
</DataTemplate>

my problem is that this really depends on the control which owns this context menu (in this case it is the DataTemplate). We actually want to make this context menu behavior independent and put it in a resource so that other controls can share with it.

I am trying to do it in a Style trigger of the context menu itself, but in a Style trigger I can't use the target name and source name.

Can anyone help me think of a better solution? Thanks.

S.

UPDATE:

Looking at the examples in the link from Nikolay, I implemented a converter as below

<ContextMenu x:Name="contextMenu" Visibility={Binding PATH=Items, Converter={StaticResource Converter}>
    <MenuItem x:Name="menuItem1" Visibility="{Binding somebinding}" />
    <MenuItem x:Name="menuItem2" Visibliity="{Binding somebinding}" />
</ContextMenu>

In the converter, it checks the visibility of each menu item and set the proper visibility value of the context menu.

But the problem I found is that WPF evaluates the bindings from top to bottom, so ContextMenu is evaluated first and then the MenuItem, in this case my converter doesn't work because at the time of binding, the Items is still None.

Any tips guys?

2
not exactly, please look at my comment, I didn't use ItemSource compared to the post, Can I build such ItemCollection in WAML?zyzyis

2 Answers

0
votes

look at the following post, it'll give you ideas.. Visibility is toggled on different controls, but the approach would be similar.

Implementing "Rename" from a ContextMenu

0
votes

Solution with converter does not work because you bind context menu visibility to items, but items collections never changes after load and binding is not being re-evaluated then visibility of subitem changes.

I don't see any easy ways to achieve this in Xaml only, but you can easily do it with code. For example, you can derive from ContextMenu and in derived class you can subscribe to changes of visibility of all subitems (via depependecy properties change notifications) and change its visibility accordingly.

Hacky way to do it in xaml only - use multibinding for ContextMenu.Visibility and bind to both items and your somebinding but use only items actually. This way wpf will call your visibility converter any time somebinding changes.