Fluent.Ribbon icon indicating copy to clipboard operation
Fluent.Ribbon copied to clipboard

Custom ContextMenu for Ribbon

Open Demarsch opened this issue 9 years ago • 7 comments

I've tried to attach ContextMenu to Ribbon but looks like it is overriden by some standart ContextMenu with two options (something about minimizing ribbon and showing quick access bar below it). Is there any way to declaratively add your own items to this menu?

Demarsch avatar Dec 28 '15 18:12 Demarsch

It's not possible to add your own items to that menu. But it's possible to define your own menu and replace the ribbon provided one. You'd have to do it for each control you want your context menu to be shown at.

Have a look at ContextMenuService and at the ContextMenu code in Ribbon.

Please let me know if this answers your question.

batzen avatar Dec 29 '15 11:12 batzen

Hi Bastian thanks for your reply. Actually what I want to achieve is to show context menu with all ribbon tabs so check/uncheck these menu items would show/hide related tabs. I wasn't able to find a proper point to hijack my own context menu instead of built in so I ended up creating my own property for context menu. Below is the code

public class RibbonEx : Ribbon
{
    public static readonly DependencyProperty ContextMenuOverrideProperty = DependencyProperty.Register(
        "ContextMenuOverride", typeof (ContextMenu), typeof (RibbonEx), new PropertyMetadata(OnContextMenuChanged));

    private static void OnContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue != null)
        {
            ((ContextMenu)e.OldValue).PlacementTarget = null;
        }
        if (e.NewValue != null)
        {
            ((ContextMenu)e.NewValue).PlacementTarget = (UIElement)d;
        }
    }

    public ContextMenu ContextMenuOverride
    {
        get { return (ContextMenu)GetValue(ContextMenuOverrideProperty); }
        set { SetValue(ContextMenuOverrideProperty, value); }
    }

    protected override void OnContextMenuOpening(ContextMenuEventArgs e)
    {
        if (e.Source is IQuickAccessItemProvider)
        {
            base.OnContextMenuOpening(e);
            return;
        }
        var contextMenu = ContextMenuOverride;
        if (contextMenu != null)
        {
            contextMenu.IsOpen = true;
        }
        e.Handled = true;
    }
}

Technically it is working fine but I found strange visual glitch. See screenshots below Ribbon before right click on empty space image Ribbon after right click on empty space image

Tab headers disappeared and it looks like there is some kind of glass rectangle over bottom part. Can you advice me on this issue? Maybe you can just show me the proper point to override the context menu so I won't come accross this glitch again. Thanks

Demarsch avatar Dec 29 '15 14:12 Demarsch

You don't have to use a custom property for your context menu. You can use the regular ContextMenu property as it's not overwritten by the library. Maybe I will rewrite the whole context menu handling and make it easier to extend the current behavior and thus the context menu itself.

I can't reproduce your glass issue. Which versions are you using (.NET and Fluent.Ribbon)? If you are not using Fluent.Ribbon 4.0 could you try to reproduce it with version 4.0. And if it also occurs there, could you provide a repro for that issue?

batzen avatar Dec 29 '15 16:12 batzen

Ok, I resolved this visual issue. The reason for them is the combination of two facts: I explicitely put TextBlock instead of plain string into RibbontTabItem header and I bind MenuItem.Header in ContextMenu to RibbonTabItem.Header. This way when context menu is shown it set a new owner for every header text block thus tab item loses its header completely (still not sure why its bottom half goes glass but it is no longer matters).

However I can't just set my context menu as you said. Even if I use plain XAML like below I still see standard context menu instead of mine

 <fluent:RibbonWindow x:Class="RibbonTest.MainWindow"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:fluent="urn:fluent-ribbon"
                     Title="MainWindow" Height="350" Width="525" DataContext="">
    <fluent:Ribbon>
        <fluent:RibbonTabItem Header="XXX" />
        <fluent:RibbonTabItem Header="YYY" />
        <fluent:Ribbon.ContextMenu>
            <ContextMenu>
                <MenuItem Header="XXX" />
                <MenuItem Header="YYY" />
            </ContextMenu>
        </fluent:Ribbon.ContextMenu>
    </fluent:Ribbon>
</fluent:RibbonWindow>

Demarsch avatar Dec 29 '15 22:12 Demarsch

Nice you figured it out. The glass gets visible because the background is transparent.

I was really only talking about your custom context menu property. The custom code is still required.

If more people express their need for custom context menus for the ribbon I will think about a solution for that.

@GeertvanHorrik Maybe you need custom context menus for the ribbon too?

batzen avatar Dec 29 '15 22:12 batzen

Thanks. For now I'm fine using my solution so feel free to close this issue if no one else need the menu

Demarsch avatar Dec 29 '15 22:12 Demarsch

I have not yet needed this feature so far, but thanks for including me in this discussion.

GeertvanHorrik avatar Jan 02 '16 17:01 GeertvanHorrik