当前位置: 首页 > article >正文

WPF+MVVM案例实战(十五)- 实现一个下拉式菜单(上)

文章目录

  • 1 案例效果
  • 2、图标资源下载
  • 3、功能实现
    • 1.文件创建
    • 2、菜单原理分析
    • 3、一级菜单两种样式实现
      • 1、一级菜单无子项样式实现
      • 2、一级菜单有子项样式实现
  • 4、总结


1 案例效果

`提示在这里插入图片描述

2、图标资源下载

从阿里矢量素材官网下载需要的菜单图片,如下所示:
在这里插入图片描述

3、功能实现

1.文件创建

打开 Wpf_Examples 项目,在Views 文件夹下创建 窗体 DropDownMenuWindow.xaml 文件。这里我们拆解一下菜单结构,如下图所示

在这里插入图片描述
在WPF中菜单控件为 Menu 菜单项为 MenuItem。如果仅从菜单结构描述,那么如下所示即可实现三级结构。
在这里插入图片描述

 <MenuItem Header="一级菜单" Width="80" Height="30">
     <MenuItem Header="二级菜单名1" Width="80" Height="30">
         <MenuItem Header="三级菜单" Width="80" Height="30">
         </MenuItem>
     </MenuItem>
     <MenuItem Header="二级菜单名2" Width="80" Height="30">
     </MenuItem>
     <MenuItem Header="二级菜单名3" Width="80" Height="30">
     </MenuItem>
 </MenuItem>

这就是三级菜单的框架了,我们要做的其实就是美化样式和点击效果了。

2、菜单原理分析

看了上面,我们明白了菜单就是 MenuItem 的嵌套,每一层就是 MenuItem 的样式实现,那么这个样式有规律吗,答案是有的。首先观察一级菜单,发现一级菜单的面板是在菜单的正下方出现,而二级菜单是在菜单项的右侧出现。每个菜单分两种情况,有子菜单项和无子菜单项两种情况。到这里我们已经明白了,菜单其实只有四种样式,一级菜单无子项样式、一级菜单有子项样式、二级菜单无子项样式和二级菜单有子项样式。而不管多少级菜单,只要是一级菜单就使用 一级菜单无子项样式或一级菜单有子项样式,二级及以上菜单就使用二级菜单无子项样式和二级菜单有子项样式。明白了以上道理,我们来逐个实现样式。

3、一级菜单两种样式实现

1、一级菜单无子项样式实现

首先样式按照下图分割:
在这里插入图片描述
整个样式 MenuItemStyle 实现如下:

 <Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type MenuItem}">
                 <Border x:Name="border" 
                         BorderThickness="0" 
                         CornerRadius="5"
                         Background="{TemplateBinding Background}"
                         Height="{TemplateBinding Height}"
                         Width="{TemplateBinding Width}" >
                     <Grid>
                         <ContentPresenter ContentSource="Icon" HorizontalAlignment="Left"
                                           VerticalAlignment="Center" Height="16"
                                           Width="16" Margin="8 0 0 0"/>
                         <ContentPresenter ContentSource="Header" HorizontalAlignment="Left"
                                           VerticalAlignment="Center" TextBlock.Foreground="{TemplateBinding Foreground}"
                                           TextBlock.FontFamily="{TemplateBinding FontFamily}"
                                           TextBlock.FontSize="{TemplateBinding FontSize}"
                                           Margin="30 0 0 0"/>
                     </Grid>

                 </Border>
                 <ControlTemplate.Triggers>
                     <Trigger Property="IsHighlighted" Value="True">
                         <Setter Property="Background" TargetName="border" Value="#524E4F"/>
                         <Setter Property="BorderBrush" TargetName="border" Value="#524E4F"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>

结合图示,很容易就能理解每个样式属性的含义,最后加上样式触发效果,IsHighlighted 选中后背景色改变即可。
我们应用样式后效果如下:

 <MenuItem Header="一级菜单" Width="100" Height="30" Style="{StaticResource MenuItemStyle}">
         <MenuItem.Icon>
             <Image Source="/Assets/Images/bianji.png" />
         </MenuItem.Icon>
     <MenuItem Header="二级菜单名1" Width="80" Height="30">
         <MenuItem Header="三级菜单" Width="80" Height="30">
         </MenuItem>
     </MenuItem>
     <MenuItem Header="二级菜单名2" Width="80" Height="30">
     </MenuItem>
     <MenuItem Header="二级菜单名3" Width="80" Height="30">
     </MenuItem>
 </MenuItem>

在这里插入图片描述
是不是有感觉了,由于样式是不带子项的,所以子项菜单在应用无子项菜单样式就没办法看到子项面板了。那么接下来实现有子项菜单的样式。

2、一级菜单有子项样式实现

分析一下有子项的菜单,其实就是在一级菜菜单下方增加一个弹出的面板。然后再弹出的面板上实现样式。粉衣及时不难发现应该和无子项样式差不多,只需要稍微改造一下,增加一个弹出面板。MenuItemStyleDropDown 示意图如下所示:

在这里插入图片描述
按照上述示意图,很容易在一级无子项菜单的样式上改造,改造后的代码如下:

 <Style x:Key="MenuItemStyleDropDown" TargetType="MenuItem">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type MenuItem}">
                 <Border x:Name="border" Background="{TemplateBinding Background}"
                         BorderThickness="0" Height="{TemplateBinding Height}"
                         Width="{TemplateBinding Width}" CornerRadius="5">
                     <Grid>
                         <ContentPresenter ContentSource="Icon" HorizontalAlignment="Left"
                                           VerticalAlignment="Center" Height="16"
                                           Width="16" Margin="8 0 0 0"/>
                         <ContentPresenter ContentSource="Header" HorizontalAlignment="Left"
                                           VerticalAlignment="Center" TextBlock.Foreground="{TemplateBinding Foreground}"
                                           TextBlock.FontFamily="{TemplateBinding FontFamily}"
                                           TextBlock.FontSize="{TemplateBinding FontSize}"
                                           Margin="30 0 0 0"/>
                         <Image Source="/Assets/Images/small_down.png" Stretch="Uniform" HorizontalAlignment="Right"
                                VerticalAlignment="Center" Margin="0 0 10 0" Width="15" Height="15"/>
                         <Popup x:Name="PART_Popup" AllowsTransparency="True" IsOpen="{Binding IsSubmenuOpen,RelativeSource={RelativeSource TemplatedParent}}"
                                Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimation}}">
                             <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding Background}">
                                 <ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
                                     <Grid>
                                         <ItemsPresenter x:Name="ItemsPresenter"/>
                                     </Grid>
                                 </ScrollViewer>
                             </Border>
                         </Popup>
                     </Grid>

                 </Border>
                 <ControlTemplate.Triggers>
                     <Trigger Property="IsHighlighted" Value="True">
                         <Setter Property="Background" TargetName="border" Value="#524E4F"/>
                         <Setter Property="BorderBrush" TargetName="border" Value="#524E4F"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>

对比如下所示:

在这里插入图片描述
想要二级菜单显示,我们需要把二级菜单样式写出来才能看到,这里我们和一级菜单逻辑一样,先实现无子项的菜单样式 ChildMenuItemStyle 。同样二级面板和一级的无子项样式类似,复制改造后 ChildMenuItemStyle 样式如下所示:

 <Style x:Key="ChildMenuItemStyle" TargetType="{x:Type MenuItem}">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type MenuItem}">
                 <Border x:Name="border" 
                      BorderThickness="0"
                      Background="{Binding Path=Background,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Menu}}}"
                      Height="{TemplateBinding Height}"
                      Width="{TemplateBinding Width}" >
                     <Grid>
                         <ContentPresenter ContentSource="Icon" HorizontalAlignment="Left"
                                        VerticalAlignment="Center" Height="16"
                                        Width="16" Margin="8 0 0 0"/>
                         <ContentPresenter ContentSource="Header" HorizontalAlignment="Left"
                                        VerticalAlignment="Center" TextBlock.Foreground="{TemplateBinding Foreground}"
                                        TextBlock.FontFamily="{TemplateBinding FontFamily}"
                                        TextBlock.FontSize="{TemplateBinding FontSize}"
                                        Margin="30 0 0 0"/>
                         <!--菜单选中时左侧增加高亮竖线效果-->
                         <Grid x:Name="HeightLine" Height="{TemplateBinding Height}" Width="2" Background="White" HorizontalAlignment="Left" VerticalAlignment="Center" Visibility="Collapsed"/>
                     </Grid>

                 </Border>
                 <ControlTemplate.Triggers>
                     <Trigger Property="IsHighlighted" Value="True">
                         <Setter Property="Background" TargetName="border" Value="#524E4F"/>
                         <Setter Property="BorderBrush" TargetName="border" Value="#524E4F"/>
                         <Setter Property="Visibility" TargetName="HeightLine" Value="Visible"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>

然后我们使用有子项菜单样式看看例子效果:

在这里插入图片描述

4、总结

到这,我么其实已经实现了一个二级菜单的全部功能,无非就是 MenuItem 的嵌套。对WPF上位机开发感兴趣的小伙伴可以点击关注和收藏,又想要实现的功能特效欢迎留言,本人不定时按照需求推出更多案例,下一节,将讲完整个下拉菜单的实现。


http://www.kler.cn/a/374487.html

相关文章:

  • 畅捷通T+13管理员密码任意重置漏洞
  • Flask中@app.route()的methods参数详解
  • 解决 Docker 中 DataLoader 多进程错误:共享内存不足
  • 项目亮点案例
  • 矩阵:Input-Output Interpretation of Matrices (中英双语)
  • Bluetooth Spec【0】蓝牙核心架构
  • OpenCV视觉分析之目标跟踪(3)实现基于金字塔的 Lucas-Kanade 算法来进行稀疏光流计算的类SparsePyrLKOpticalFlow的使用
  • 《解锁 TDD 魔法:高效软件开发的利器》
  • 读写chrome.storage.local
  • 股票基础交易规则——涨跌幅限制、价格笼子?
  • Java:阿里云联络中心“双呼A”功能系统接入
  • vscode | 开发神器vscode快捷键删除和恢复
  • 【VM实战】VMware迁移到VirtualBox
  • 无人机之感知避让技术篇
  • 【网络】什么是 ICMP (Internet Control Message Protocol)?
  • 双指针习题篇(上)
  • 基于SpringBoot的健身房系统的设计与实现(源码+定制+开发)
  • 如何在1个账号上,1个客户6个人同时服务
  • 鸿蒙网络编程系列41-仓颉版HttpRequest模拟登录示例
  • C++——酒店管理系统
  • 二百七十二、Kettle——ClickHouse中增量导入数据重复性统计表数据(1天1次)
  • Python中的PDF处理工具:PyPDF2和ReportLab使用指南
  • 慢sql优化和Explain解析
  • MySQL数据表导入到clickhouse数据库中
  • linux命令行的艺术
  • Spring Boot + Vue:打造高效图书借阅管理平台