2

I'm trying to implement "Mega Menu" style menus using WPF. To see examples of mega menus in web design, see here.

So far, I've tried creating a similar interface by using TextBlocks as the highest level of the menu, and then using the mouse hover event to display an additional window that appears positioned below the text block. This is cumbersome and inflexible, future changes would require adding/removing TextBlocks dynamically.

I have considered using the WPF Menu control, because I know the styles can be dramatically modified, but I haven't seen any way to produce multi-column layouts with the hierarchical model that the Menu control uses.

Is there a better way to do this? Am I going to have to stick with custom windows and relative positioning? Can someone point me to an example of this that has already been implemented?

robr
  • 919
  • 1
  • 7
  • 16

4 Answers4

1

You could use a HeaderedItemsControl and swap out the Panel to suit your needs; by default it uses a StackPanel however a WrapPanel may suit you better. The pop out and mouse over behavior do not exist by default and would need to be implemented.

A more robust approach would be to leverage a custom Expander; as it provides the pop out behavior you are after and the linked to walkthrough provides the mouse over behavior.

Aaron McIver
  • 24,527
  • 5
  • 59
  • 88
1

I wonder if the Ribbon control can be retrofitted to do this? It provides tabs, labels, columns and all that.

Please use this UI design sparingly and make sure that it only opens and closes when the user specifically requests such. It's tremendously annoying when a popup mega-menu appears over a website I'm viewing, and I can't get it to close, except for when I want to click on it and it goes away.

djdanlib
  • 21,449
  • 1
  • 20
  • 29
  • This a desktop app which consists of only the menu itself and it docks to the top of the screen, so stray mouse hovers should be minimal. If the users decide it is annoying I'll change it to be click-based instead of hover-based. – robr Apr 04 '11 at 20:48
  • I would be careful about adaptations of Microsoft's ribbon controls. They have very specific usages allowed when a developer signs up to use the controls. There may be other "ribbonesque" controls out there that would be great starting points. – Dave White Apr 04 '11 at 22:43
  • 1
    @Dave The licensing has changed. It is going to be part of .NET FW soon enough; it is safe to use. http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=2bfc3187-74aa-4154-a670-76ef8bc2a0b4 – Aaron McIver Apr 04 '11 at 23:02
  • @Aaron - Awesome! Thanks for the link and info! – Dave White Apr 05 '11 at 01:44
1

Instead of using custom Windows and positioning, you could use a Popup control. Your can use the StaysOpen=false setting to have it close when the user clicks off-screen.

If you can settle for clicking a menu item instead of hovering, the following custom control will work:

[TemplatePart(Name="PART_HoverArea", Type=typeof(FrameworkElement))]
[TemplatePart(Name="PART_Popup", Type=typeof(Popup))]
public class MegaMenuItem : HeaderedContentControl
{
    private FrameworkElement hoverArea;
    private Popup popup;

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        // Unhook old template
        if (hoverArea != null)
        {
            hoverArea.PreviewMouseUp -= ShowPopupOnMouseDown;
        }

        hoverArea = null;
        popup = null;

        if (Template == null)
            return;

        // Hook up new template
        hoverArea = (FrameworkElement)Template.FindName("PART_HoverArea", this);
        popup = (Popup)Template.FindName("PART_Popup", this);
        if (hoverArea == null || popup == null)
            return;

        hoverArea.PreviewMouseUp += ShowPopupOnMouseDown;
    }

    private void ShowPopupOnMouseDown(object sender, MouseEventArgs e)
    {
        popup.PlacementTarget = hoverArea;
        popup.Placement = PlacementMode.Bottom;
        popup.StaysOpen = false;
        popup.IsOpen = true;
    }
}

You would need a style to display it - something like this. Note the PART_ template part names:

<Style TargetType="WpfApplication14:MegaMenuItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="WpfApplication14:MegaMenuItem">
                <Grid>
                    <Border Name="PART_HoverArea" Background="#fb9c3b" BorderBrush="White" BorderThickness="0,0,1,0">
                        <ContentPresenter Content="{TemplateBinding Header}" />
                    </Border>

                    <Popup 
                        Name="PART_Popup" 
                        PlacementTarget="{Binding ElementName=HoverArea}"
                        >
                        <Border MinWidth="100" MaxWidth="400" MinHeight="40" MaxHeight="200" Background="#0d81c3">
                            <ContentPresenter Content="{TemplateBinding Content}" />
                        </Border>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>    
</Style>

The XAML for your menu would then be:

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <WpfApplication14:MegaMenuItem Header="Parent 1">
        <WrapPanel Margin="5">
            <TextBlock Text="Put any content you want here" Margin="5" />
            <TextBlock Text="Put any content you want here" Margin="5" />
            <TextBlock Text="Put any content you want here" Margin="5" />
        </WrapPanel>
    </WpfApplication14:MegaMenuItem>
    <WpfApplication14:MegaMenuItem Header="Parent 2">
        <WrapPanel Margin="5">
            <TextBlock Text="Put any content you want here" Margin="5" />
            <TextBlock Text="Put any content you want here" Margin="5" />
            <TextBlock Text="Put any content you want here" Margin="5" />
        </WrapPanel>
    </WpfApplication14:MegaMenuItem>
</StackPanel>

Making the menu appear on hover is much harder, because of the way Popups steal focus (you can show the menu, but you can't easily hide it if they mouse over another menu). For that a custom window might work better.

Paul Stovell
  • 32,377
  • 16
  • 80
  • 108
0

Custom windows and relative position are essentially how the WPF Menu/MenuItem control works... but as you've found, it's non-trivial. Best bet would be to retemplate the Menu/MenuItem controls to meet your need.

Robert Levy
  • 28,747
  • 6
  • 62
  • 94