应用程序样式的菜单

应用程序样式的菜单

本文介绍了如何在 WPF 中创建具有 Microsoft Web 应用程序样式的菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的任务是在 WPF 中设计一个企业应用程序,该应用程序将取代战舰灰色 Winforms 应用程序,使其具有现代感.

我们喜欢 Microsoft Web 应用程序当前拥有的外观和感觉:

我们可以用通常的方式在 WPF 中创建这些菜单:

<Menu DockPanel.Dock="Top"><MenuItem Header="_File"><MenuItem Header="_New"/><MenuItem Header="_Open"/><MenuItem Header="_Save"/><分隔符/><MenuItem Header="_Exit"/></菜单项></菜单><TextBox AcceptsReturn="True"/></DockPanel>

但我们会得到一些看起来像 Winforms 菜单的东西.

我见过一些相当令人印象深刻的样式设计,例如

这是 XAML.我选择为每个 MenuItem 使用自定义控件模板.我认为当您需要真正自定义每个项目时,它非常实用.

<窗口.资源><BooleanToVisibilityConverter x:Key="btv"/><!-- 设置顶级菜单项的样式--><ControlTemplate x:Key="VsMenuTop" TargetType="MenuItem"><StackPanel TextBlock.FontSize="15px" Height="40"><!-- 标签、图标等--><Label Content="{TemplateBinding Header}" Margin="5" Foreground="White"/><!-- 子项目--><Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False"><Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0"><StackPanel IsItemsHost="True"/></边框></弹出窗口><StackPanel.Style><Style TargetType="StackPanel"><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="#106EBE"/></触发器></Style.Triggers></风格></StackPanel.Style></StackPanel></控制模板><!-- 设置非顶级菜单项的样式--><ControlTemplate x:Key="VsMenuSub" TargetType="MenuItem"><DockPanel TextBlock.FontSize="15px" x:Name="panel"><!-- 标签、图标等--><Image Source="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}" Width="20" Margin="5,0"/><Label Content="{TemplateBinding Header}" Foreground="Black" Margin="0,5,5,5"/><!-- 仅当此菜单项有子项时才绘制向右箭头 --><Image Source="icon_right.png" Visibility="{Binding HasItems, Converter={StaticResource btv}, RelativeSource={RelativeSource TemplatedParent}}"/><!-- 子项目--><Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False" Placement="Right" ><Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0"><StackPanel IsItemsHost="True"/></边框></弹出窗口></DockPanel><ControlTemplate.Triggers><Trigger Property="IsHighlighted" Value="True"><Setter Property="Background" TargetName="panel" Value="#EFF6FC"/></触发器></ControlTemplate.Triggers></控制模板><!-- 设置分隔符的样式--><ControlTemplate x:Key="VsMenuSep" TargetType="分隔符"><边框高度="1" 背景="#E0E0E0"/></控制模板><!-- 设置 VSOnline 的样式--><ControlTemplate x:Key="VsOnline" TargetType="MenuItem"><StackPanel TextBlock.FontSize="15px" Height="40" Orientation="Horizo​​ntal" Background="#005A9E"><Label Content="{TemplateBinding Header}" Margin="5" Foreground="White"/><Image Source="icon_down.png" Height="20" Margin="0,0,5,0"/><!-- 子项目--><Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False"><Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0"><StackPanel IsItemsHost="True"/></边框></弹出窗口></StackPanel></控制模板><!-- 一些基本的东西--><Style TargetType="菜单"><Setter Property="Background" Value="#0078D7"/><Setter Property="Height" Value="40px"/></风格></Window.Resources><!-- 真正的应用程序和真正的菜单--><堆栈面板><Menu IsMainMenu="True"><MenuItem Header="_VSOnline" Template="{StaticResource VsOnline}" ><MenuItem Header="_Whatever" Template="{StaticResource VsMenuSub}"/></菜单项><MenuItem Header="_Dashboards" Template="{StaticResource VsMenuTop}"><MenuItem Header="_Overview" Template="{StaticResource VsMenuSub}"/></菜单项><MenuItem Header="_Code" Template="{StaticResource VsMenuTop}"><MenuItem Header="_Files" Template="{StaticResource VsMenuSub}"/><MenuItem Header="_Commits" Template="{StaticResource VsMenuSub}"/><MenuItem Header="_Pushes" Template="{StaticResource VsMenuSub}"/></菜单项><MenuItem Header="_Work" Template="{StaticResource VsMenuTop}"><MenuItem Header="_Backlogs" Template="{StaticResource VsMenuSub}" Icon="icon_backlogs.png"/><MenuItem Header="_Queries" Template="{StaticResource VsMenuSub}" Icon="icon_queries.png"/><Separator Template="{StaticResource VsMenuSep}"/><MenuItem Header="_New Work Item" Template="{StaticResource VsMenuSub}"><MenuItem Header="_Epic" Template="{StaticResource VsMenuSub}" Icon="icon_epic.png"/><MenuItem Header="_Feature" Template="{StaticResource VsMenuSub}" Icon="icon_feature.png"/><MenuItem Header="_Issue" Template="{StaticResource VsMenuSub}" Icon="icon_issue.png"/><MenuItem Header="_Task" Template="{StaticResource VsMenuSub}" Icon="icon_task.png"/><MenuItem Header="_Test Case" Template="{StaticResource VsMenuSub}" Icon="icon_testcase.png"/><MenuItem Header="_User Story" Template="{StaticResource VsMenuSub}" Icon="icon_userstory.png"/></菜单项><MenuItem Header="_Bug" Template="{StaticResource VsMenuSub}" Icon="icon_bug.png"/></菜单项></菜单></StackPanel></窗口>

该项目可在 此处在 github 上获得.

We have been tasked with designing an enterprise application in WPF that will replace a battleship grey Winforms application with a modern look and feel.

We like the look and feel that Microsoft web applications currently possess:

We could create these menus in WPF in the usual way:

<DockPanel>
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_File">
            <MenuItem Header="_New" />
            <MenuItem Header="_Open" />
            <MenuItem Header="_Save" />
            <Separator />
            <MenuItem Header="_Exit" />
        </MenuItem>
    </Menu>
    <TextBox AcceptsReturn="True" />
</DockPanel>

But we'd get something that looks like a Winforms menu.

I've seen some rather impressive styling efforts like this one, but they all seem to have the same familiar Winforms shape. I've also seen menus in libraries like MahApps Metro, but these strike us as too spartan.

Is the WPF Menu control flexible enough to be styled as shown in the picture above, or should we go another route like building a custom menu control from Stack Panels and Lists? What are the tradeoffs?

Bonus points (i.e. a bounty) will be awarded for xaml/code that does exactly this.

An example of this menu style in action:
https://www.visualstudio.com/

解决方案

WPF was really designed with the possibility to change the look and behavior of every out-of-the-box mechanisms / controls (buttons, menus, treeview, etc.).So, in general, it's better to do this rather than to rewrite everything. For example, if you redesign your custom menu, you'll have to think about keyboard, UI automation, etc...

So, I gave a shot at your example and tried to build a minimum working sample - pure XAML - that mimics VS online menu (I've also added the hover background color change that's not by default in WPF's menu).

Here is the result and, as you see, it looks very similar:

Here is the XAML. I've chosen to use a custom control template per each MenuItem. I think it's quite practical when you need to really customize every item.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="550" Width="525">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="btv" />

        <!-- style a top level menu item -->
        <ControlTemplate x:Key="VsMenuTop" TargetType="MenuItem">
            <StackPanel TextBlock.FontSize="15px" Height="40">
                <!-- label, icons, etc. -->
                <Label Content="{TemplateBinding Header}" Margin="5" Foreground="White" />

                <!-- sub items -->
                <Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False">
                    <Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
                        <StackPanel IsItemsHost="True" />
                    </Border>
                </Popup>
                <StackPanel.Style>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver"  Value="True">
                                <Setter Property="Background" Value="#106EBE" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Style>
            </StackPanel>
        </ControlTemplate>

        <!-- style a non-top level menu item -->
        <ControlTemplate x:Key="VsMenuSub" TargetType="MenuItem">
            <DockPanel TextBlock.FontSize="15px" x:Name="panel">
                <!-- label, icons, etc. -->
                <Image Source="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}" Width="20" Margin="5,0" />
                <Label Content="{TemplateBinding Header}" Foreground="Black" Margin="0,5,5,5" />

                <!-- draw the right arrow only if this menu item has sub items -->
                <Image Source="icon_right.png" Visibility="{Binding HasItems, Converter={StaticResource btv}, RelativeSource={RelativeSource TemplatedParent}}" />

                <!-- sub items -->
                <Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False" Placement="Right" >
                    <Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
                        <StackPanel IsItemsHost="True" />
                    </Border>
                </Popup>
            </DockPanel>
            <ControlTemplate.Triggers>
                <Trigger Property="IsHighlighted" Value="True">
                    <Setter Property="Background" TargetName="panel" Value="#EFF6FC" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

        <!-- style the separator -->
        <ControlTemplate x:Key="VsMenuSep" TargetType="Separator">
            <Border Height="1" Background="#E0E0E0" />
        </ControlTemplate>

        <!-- style the VSOnline -->
        <ControlTemplate x:Key="VsOnline" TargetType="MenuItem">
            <StackPanel TextBlock.FontSize="15px" Height="40" Orientation="Horizontal" Background="#005A9E">
                <Label Content="{TemplateBinding Header}" Margin="5" Foreground="White" />
                <Image Source="icon_down.png" Height="20" Margin="0,0,5,0" />

                <!-- sub items -->
                <Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False">
                    <Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
                        <StackPanel IsItemsHost="True" />
                    </Border>
                </Popup>
            </StackPanel>
        </ControlTemplate>

        <!-- some base stuff -->
        <Style TargetType="Menu">
            <Setter Property="Background" Value="#0078D7" />
            <Setter Property="Height" Value="40px" />
        </Style>

    </Window.Resources>

    <!-- the real app and real menu -->
    <StackPanel>
        <Menu IsMainMenu="True">
            <MenuItem Header="_VSOnline" Template="{StaticResource VsOnline}" >
                <MenuItem Header="_Whatever" Template="{StaticResource VsMenuSub}" />
            </MenuItem>
            <MenuItem Header="_Dashboards" Template="{StaticResource VsMenuTop}">
                <MenuItem Header="_Overview" Template="{StaticResource VsMenuSub}" />
            </MenuItem>
            <MenuItem Header="_Code" Template="{StaticResource VsMenuTop}">
                <MenuItem Header="_Files" Template="{StaticResource VsMenuSub}" />
                <MenuItem Header="_Commits" Template="{StaticResource VsMenuSub}" />
                <MenuItem Header="_Pushes" Template="{StaticResource VsMenuSub}" />
            </MenuItem>
            <MenuItem Header="_Work" Template="{StaticResource VsMenuTop}">
                <MenuItem Header="_Backlogs" Template="{StaticResource VsMenuSub}" Icon="icon_backlogs.png" />
                <MenuItem Header="_Queries" Template="{StaticResource VsMenuSub}" Icon="icon_queries.png" />
                <Separator Template="{StaticResource VsMenuSep}" />
                <MenuItem Header="_New Work Item" Template="{StaticResource VsMenuSub}">
                    <MenuItem Header="_Epic" Template="{StaticResource VsMenuSub}" Icon="icon_epic.png" />
                    <MenuItem Header="_Feature" Template="{StaticResource VsMenuSub}" Icon="icon_feature.png" />
                    <MenuItem Header="_Issue" Template="{StaticResource VsMenuSub}" Icon="icon_issue.png" />
                    <MenuItem Header="_Task" Template="{StaticResource VsMenuSub}" Icon="icon_task.png" />
                    <MenuItem Header="_Test Case" Template="{StaticResource VsMenuSub}" Icon="icon_testcase.png" />
                    <MenuItem Header="_User Story" Template="{StaticResource VsMenuSub}" Icon="icon_userstory.png" />
                </MenuItem>
                <MenuItem Header="_Bug" Template="{StaticResource VsMenuSub}" Icon="icon_bug.png" />
            </MenuItem>
        </Menu>
    </StackPanel>
</Window>

The project is available here on github.

这篇关于如何在 WPF 中创建具有 Microsoft Web 应用程序样式的菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 07:10