Inconsistent behavior of data-bound menus vs hard-coded menus

Ribbon for WPF Forum

Posted 3 years ago by Henry McCord - Senior Software Dev, RAFB
Version: 21.1.1
Platform: .NET 4.7
Environment: Windows 10 (64-bit)
Avatar

I've got an app that we're currently converting most of our controls over to Actipro.

In the process of transitioning the ribbon portion, I found a couple of issues related to data-bound items since nearly everything in our app uses collections and datatemplating. I was using the sample browser and wanted to use your theme selection (which uses MenuItems) and port it to ribbon.

Here's a minimal repro showing a few issues.

  • In both data-bound collections, the hover to open popup menu doesn't function on some items
  • Application Menu
    • Long description of menu item isn't wrapped on hard-code or data-bound items
    • Data-bound popupbutton sub-menu are a different size than hard-coded
    • When hovering the hard-coded collection, you can see the popout is way off to the side

I was wondering if I was doing something wrong anywhere or if there is another underlying issue.

MainWindow.xaml

<ribbon:RibbonWindow x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ribbon="http://schemas.actiprosoftware.com/winfx/xaml/ribbon"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <ribbon:Ribbon KeyTipModeShortcuts="All">
        <ribbon:Ribbon.ApplicationMenu>
            <ribbon:ApplicationMenu MinHeight="400">
                <ribbon:PopupButton Label="Hard-code" KeyTipAccessText="C">
                    <StackPanel>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Application Theme" />
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:PopupButton Label="Standard" KeyTipAccessText="S">
                                <ribbon:Menu>
                                    <ribbon:Button Label="Dark" KeyTipAccessText="D" />
                                    <ribbon:Button Label="Light" KeyTipAccessText="L" />
                                </ribbon:Menu>
                            </ribbon:PopupButton>
                            <ribbon:PopupButton Label="Metro" KeyTipAccessText="M">
                                <ribbon:Menu>
                                    <ribbon:Button Label="Metro Dark" KeyTipAccessText="D" />
                                    <ribbon:Button Label="Metro Light" KeyTipAccessText="L" />
                                </ribbon:Menu>
                            </ribbon:PopupButton>
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Options" />
                            <ribbon:Button Label="Match Windows Settings"
                                               MenuItemDescription="Auto-switch themes to match the light/dark or high-contrast Windows setting"
                                               KeyTipAccessText="A">
                            </ribbon:Button>
                        </ribbon:Menu>
                    </StackPanel>
                </ribbon:PopupButton>
                <ribbon:PopupButton Label="Data-bound" KeyTipAccessText="D">
                    <StackPanel>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Application Theme" />
                        </ribbon:Menu>
                        <ribbon:Menu ItemsSource="{Binding ThemeGroups}">
                            <ribbon:Menu.Resources>
                                <DataTemplate DataType="{x:Type local:ActiproThemeGroup}">
                                    <ribbon:PopupButton Context="MenuItem"
                                                        Label="{Binding GroupName}" 
                                                        KeyTipAccessText="{Binding KeyTip}">
                                        <ribbon:Menu ItemsSource="{Binding Themes}" />
                                    </ribbon:PopupButton>
                                </DataTemplate>
                                <DataTemplate DataType="{x:Type local:ActiproTheme}">
                                    <ribbon:Button Context="MenuItem"
                                                   Label="{Binding DisplayName}"
                                                   KeyTipAccessText="{Binding KeyTip}"/>
                                </DataTemplate>
                            </ribbon:Menu.Resources>
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Options" />
                            <ribbon:Button Label="Match Windows Settings"
                                               MenuItemDescription="Auto-switch themes to match the light/dark or high-contrast Windows setting"
                                               KeyTipAccessText="A">
                            </ribbon:Button>
                        </ribbon:Menu>
                    </StackPanel>
                </ribbon:PopupButton>
            </ribbon:ApplicationMenu>
        </ribbon:Ribbon.ApplicationMenu>
        <ribbon:Tab Label="Home" KeyTipAccessText="H">
            <ribbon:Group>
                <ribbon:PopupButton Label="Hard-code" KeyTipAccessText="C">
                    <StackPanel>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Application Theme" />
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:PopupButton Label="Standard" KeyTipAccessText="S">
                                <ribbon:Menu>
                                    <ribbon:Button Label="Dark" KeyTipAccessText="D" />
                                    <ribbon:Button Label="Light" KeyTipAccessText="L" />
                                </ribbon:Menu>
                            </ribbon:PopupButton>
                            <ribbon:PopupButton Label="Metro" KeyTipAccessText="M">
                                <ribbon:Menu>
                                    <ribbon:Button Label="Metro Dark" KeyTipAccessText="D" />
                                    <ribbon:Button Label="Metro Light" KeyTipAccessText="L" />
                                </ribbon:Menu>
                            </ribbon:PopupButton>
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Options" />
                            <ribbon:Button Label="Match Windows Settings"
                                               MenuItemDescription="Auto-switch themes to match the light/dark or high-contrast Windows setting"
                                               KeyTipAccessText="A">
                            </ribbon:Button>
                        </ribbon:Menu>
                    </StackPanel>
                </ribbon:PopupButton>
                <ribbon:PopupButton Label="Data-bound" KeyTipAccessText="D">
                    <StackPanel>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Application Theme" />
                        </ribbon:Menu>
                        <ribbon:Menu ItemsSource="{Binding ThemeGroups}">
                            <ribbon:Menu.Resources>
                                <DataTemplate DataType="{x:Type local:ActiproThemeGroup}">
                                    <ribbon:PopupButton Context="MenuItem"
                                                        Label="{Binding GroupName}" 
                                                        KeyTipAccessText="{Binding KeyTip}">
                                        <ribbon:Menu ItemsSource="{Binding Themes}" />
                                    </ribbon:PopupButton>
                                </DataTemplate>
                                <DataTemplate DataType="{x:Type local:ActiproTheme}">
                                    <ribbon:Button Context="MenuItem"
                                                   Label="{Binding DisplayName}"
                                                   KeyTipAccessText="{Binding KeyTip}"/>
                                </DataTemplate>
                            </ribbon:Menu.Resources>
                        </ribbon:Menu>
                        <ribbon:Menu>
                            <ribbon:Separator Label="Options" />
                            <ribbon:Button Label="Match Windows Settings"
                                               MenuItemDescription="Auto-switch themes to match the light/dark or high-contrast Windows setting"
                                               KeyTipAccessText="A">
                            </ribbon:Button>
                        </ribbon:Menu>
                    </StackPanel>
                </ribbon:PopupButton>
            </ribbon:Group>
        </ribbon:Tab>
    </ribbon:Ribbon>
</ribbon:RibbonWindow>

Supporting classes.

    public class MainWindowViewModel
    {
        public IList<ActiproThemeGroup> ThemeGroups { get; }

        public MainWindowViewModel()
        {
            ThemeGroups = new List<ActiproThemeGroup>
            {
                new ActiproThemeGroup
                {
                    GroupName = "Standard",
                    KeyTip = "S",
                    Themes = new List<ActiproTheme>
                    {
                        new ActiproTheme { DisplayName = "Dark", KeyTip = "D" },
                        new ActiproTheme { DisplayName = "Light", KeyTip = "L" },
                    }
                },
                new ActiproThemeGroup
                {
                    GroupName = "Metro",
                    KeyTip = "M",
                    Themes = new List<ActiproTheme>
                    {
                        new ActiproTheme { DisplayName = "Metro Dark", KeyTip = "D" },
                        new ActiproTheme { DisplayName = "Metro Light", KeyTip = "L" },
                    }
                },
            };
        }
    }

    public abstract class KeyTipBase
    {
        public abstract string KeyTip { get; set; }
    }

    public class ActiproThemeGroup
    {
        public string GroupName { get; set; }
        public IList<ActiproTheme> Themes { get; set; }
        public string KeyTip { get; set; }
    }

    public class ActiproTheme
    {
        public string DisplayName { get; set; }
        public string KeyTip { get; set; }
    }

Comments (2)

Answer - Posted 3 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Henry,

The current Ribbon API unfortunately doesn't play well with MVVM creation of UI.  What is happening is that in the hard-code portions of your sample, you are setting up the correct control hierarchies for things to work.  Whereas the data-bound portions are creating an intermediary "container" element (due to how ItemsControl's generator works) and the PopupButton ends up being nested inside that container element.  Then the Menu isn't able to handle things like hover, etc. properly due to that separation.

We are starting to look into designing a more modern API for controls like Ribbon (and the single-line Ribbon variants), and with that we'd like to improve support for MVVM scenarios if possible since that has been requested by others in the past as well.

As for the menu item description not wrapping, that is a bug.  That same bug seems to be triggering the issue where the sub-menu popups are pushed off to the right.  A shorter menu item description positions the sub-menu popup where it should be.  We've fixed the description-not-wrapping bug for the next build and that resolves the sub-menu popup location issue as well.

For the data-bound buttons not showing in the larger size, that's again due to the container element separation described above and the Menu isn't knowing to get the PopupButton/Button and set VariantSize="Large" on them.  You could do that manually in XAML though.


Actipro Software Support

Posted 3 years ago by Henry McCord - Senior Software Dev, RAFB
Avatar

Thanks for the quick reply and the workarounds. I'm glad I could get a legimate bug reported!

I also have another workaround for the sub-popup menus not flying out on hover.

I just set the ClickMode="Hover" and that works.

The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.