当前位置:   article > 正文

WPF 制作侧边栏菜单之MenuItem

wpf menuitem

有小伙伴问我有没有做过菜单栏,这我确实没做过,不过现在做还不晚吧,e3cb6c59ca54e4285fe289b4d5cead9d.png

先来做一个MenuItem,使用MVVM模式写,这样创建菜单的时候,只要绑定datacontext,就ok了,使用极为方便,还可以自定义颜色相关的属性。

先来看一下效果:

下面就来看看代码喽:

首先创建一个自定义控件类:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Markup;
  7. using System.Windows.Media;
  8. namespace WPFDemos
  9. {
  10. [DefaultProperty("MenuItems")]
  11. [ContentProperty("MenuItems")]
  12. [TemplatePart(Name = LB, Type = typeof(ListBox))]
  13. public class SideMenuItem : Control
  14. {
  15. private const string LB = "LB";
  16. private ListBox _listBox;
  17. public bool IsExpanded
  18. {
  19. get { return (bool)GetValue(IsExpandedProperty); }
  20. set { SetValue(IsExpandedProperty, value); }
  21. }
  22. public static readonly DependencyProperty IsExpandedProperty =
  23. DependencyProperty.Register("IsExpanded", typeof(bool), typeof(SideMenuItem), new PropertyMetadata(false));
  24. public List<object> MenuItems
  25. {
  26. get { return (List<object>)GetValue(MenuItemsProperty); }
  27. set { SetValue(MenuItemsProperty, value); }
  28. }
  29. public static readonly DependencyProperty MenuItemsProperty =
  30. DependencyProperty.Register("MenuItems", typeof(List<object>), typeof(SideMenuItem), new PropertyMetadata(default(List<object>)));
  31. public Brush ToggleBackground
  32. {
  33. get { return (Brush)GetValue(ToggleBackgroundProperty); }
  34. set { SetValue(ToggleBackgroundProperty, value); }
  35. }
  36. public static readonly DependencyProperty ToggleBackgroundProperty =
  37. DependencyProperty.Register("ToggleBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(0x2d, 0x2d, 0x30))));
  38. public Brush MenuItemBackground
  39. {
  40. get { return (Brush)GetValue(MenuItemBackgroundProperty); }
  41. set { SetValue(MenuItemBackgroundProperty, value); }
  42. }
  43. public static readonly DependencyProperty MenuItemBackgroundProperty =
  44. DependencyProperty.Register("MenuItemBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(0x16, 0x18, 0x1D))));
  45. public Brush MenuItemSelectedBackground
  46. {
  47. get { return (Brush)GetValue(MenuItemSelectedBackgroundProperty); }
  48. set { SetValue(MenuItemSelectedBackgroundProperty, value); }
  49. }
  50. public static readonly DependencyProperty MenuItemSelectedBackgroundProperty =
  51. DependencyProperty.Register("MenuItemSelectedBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(Brushes.Green));
  52. public static readonly RoutedEvent MenuItemSelectedChangedEvent = EventManager.RegisterRoutedEvent("MenuItemSelectedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SideMenuItem));
  53. public event RoutedEventHandler MenuItemSelectedChanged
  54. {
  55. add { AddHandler(MenuItemSelectedChangedEvent, value); }
  56. remove { RemoveHandler(MenuItemSelectedChangedEvent, value); }
  57. }
  58. public override void OnApplyTemplate()
  59. {
  60. base.OnApplyTemplate();
  61. _listBox = (GetTemplateChild(LB) as ListBox) ?? throw new Exception("listbox Named with \"LB\" not found in the Template");
  62. _listBox.SelectionChanged -= _listBoxSelectionChanged;
  63. _listBox.SelectionChanged += _listBoxSelectionChanged;
  64. }
  65. private void _listBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
  66. {
  67. if (!(e.Source is ListBox)) return;
  68. RoutedEventArgs args = new RoutedEventArgs()
  69. {
  70. RoutedEvent = MenuItemSelectedChangedEvent,
  71. Source = _listBox,
  72. };
  73. RaiseEvent(args);
  74. }
  75. }
  76. }

然后创建一个控件的ViewModel类,BaseViewModel类就是大家都知道的基类,就不粘代码了,如果需要可以联系我:

  1. using System.Collections.Generic;
  2. using System.Windows.Media;
  3. namespace WPFDemos
  4. {
  5. public class SideMenuItemViewModel : BaseViewModel
  6. {
  7. private string _headerText;
  8. public string HeaderText
  9. {
  10. get { return _headerText; }
  11. set
  12. {
  13. _headerText = value;
  14. OnPropertyChanged(nameof(HeaderText));
  15. }
  16. }
  17. private List<object> _items = new List<object>();
  18. public List<object> Items
  19. {
  20. get { return _items; }
  21. set
  22. {
  23. _items = value;
  24. OnPropertyChanged(nameof(Items));
  25. }
  26. }
  27. private Geometry _iconGeometry;
  28. public Geometry IconGeometry
  29. {
  30. get { return _iconGeometry; }
  31. set {
  32. _iconGeometry = value;
  33. OnPropertyChanged(nameof(IconGeometry));
  34. }
  35. }
  36. }
  37. }

然后在创建一个资源字典SideMenu.xaml,添加控件所需的样式:

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  3. xmlns:local="clr-namespace:WPFDemos">
  4. <Geometry x:Key="DownGeometry">M445.406 731.963L93.35 339.737A87.354 87.354 0 0 1 71 281.387C71 233.123 110.15 194 158.444 194h704.111a87.476 87.476 0 0 1 58.39 22.336c35.95 32.226 38.951 87.474 6.704 123.4L575.593 731.964a87.415 87.415 0 0 1-6.705 6.7c-35.95 32.227-91.235 29.227-123.482-6.7z</Geometry>
  5. <Geometry x:Key="UpGeometry">M575.594 216.037L927.65 608.263a87.354 87.354 0 0 1 22.35 58.35C950 714.877 910.85 754 862.556 754H158.445a87.476 87.476 0 0 1-58.39-22.336c-35.95-32.226-38.951-87.474-6.704-123.4l352.056-392.227a87.415 87.415 0 0 1 6.705-6.7c35.95-32.227 91.235-29.227 123.482 6.7z</Geometry>
  6. <Geometry x:Key="IconInfo">M497 87c245.214 0 444 198.786 444 444S742.214 975 497 975 53 776.214 53 531 251.786 87 497 87z m1.15 331.275c-18.423 0-33.357 14.934-33.357 33.357v331.275c0 18.423 14.934 33.357 33.357 33.357 18.423 0 33.358-14.934 33.358-33.357V451.632c0-18.423-14.935-33.357-33.358-33.357zM497 254.938c-24.14 0-43.71 19.054-43.71 42.56 0 23.504 19.57 42.559 43.71 42.559s43.71-19.055 43.71-42.56c0-23.505-19.57-42.56-43.71-42.56z</Geometry>
  7. <Style x:Key="ToggleButtonStyle1" TargetType="ToggleButton">
  8. <Setter Property="Background" Value="Transparent"/>
  9. <Setter Property="VerticalContentAlignment" Value="Center"/>
  10. <Setter Property="Padding" Value="0"/>
  11. <Setter Property="Margin" Value="0"/>
  12. <Setter Property="VerticalAlignment" Value="Center"/>
  13. <Setter Property="HorizontalContentAlignment" Value="Center"/>
  14. <Setter Property="BorderThickness" Value="0"/>
  15. <Setter Property="HorizontalAlignment" Value="Center"/>
  16. <Setter Property="Template">
  17. <Setter.Value>
  18. <ControlTemplate TargetType="ToggleButton">
  19. <Border SnapsToDevicePixels="true"
  20. BorderThickness="{TemplateBinding BorderThickness}"
  21. BorderBrush="{TemplateBinding BorderBrush}"
  22. Background="{TemplateBinding Background}">
  23. <ContentPresenter Name="UnCheckedElement"
  24. Margin="{TemplateBinding Padding}"
  25. HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  26. VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
  27. RecognizesAccessKey="True"
  28. SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
  29. </Border>
  30. <ControlTemplate.Triggers>
  31. <Trigger Property="IsMouseOver" Value="True">
  32. <Setter Property="Opacity" Value="0.9"/>
  33. </Trigger>
  34. <Trigger Property="IsPressed" Value="True">
  35. <Setter Property="Opacity" Value="0.6"/>
  36. </Trigger>
  37. <Trigger Property="IsEnabled" Value="False">
  38. <Setter Property="Opacity" Value="0.4"/>
  39. </Trigger>
  40. </ControlTemplate.Triggers>
  41. </ControlTemplate>
  42. </Setter.Value>
  43. </Setter>
  44. </Style>
  45. <Style x:Key="MenuHeaderStyle1" TargetType="Expander">
  46. <Setter Property="Foreground" Value="LightGray" />
  47. <Setter Property="Background" Value="#2D2D30" />
  48. <Setter Property="HorizontalContentAlignment" Value="Left" />
  49. <Setter Property="VerticalContentAlignment" Value="Center" />
  50. <Setter Property="BorderThickness" Value="0" />
  51. <Setter Property="MinHeight" Value="50" />
  52. <Setter Property="MinWidth" Value="220" />
  53. <Setter Property="FontSize" Value="14" />
  54. <Setter Property="Template" >
  55. <Setter.Value>
  56. <ControlTemplate TargetType="Expander">
  57. <Grid>
  58. <Grid.RowDefinitions>
  59. <RowDefinition Height="Auto" />
  60. <RowDefinition Height="Auto" />
  61. </Grid.RowDefinitions>
  62. <Border x:Name="BorderHeader"
  63. ClipToBounds="True"
  64. BorderBrush="{TemplateBinding BorderBrush}"
  65. BorderThickness="{TemplateBinding BorderThickness}"
  66. Background="{TemplateBinding Background}">
  67. <ToggleButton HorizontalAlignment="Stretch"
  68. HorizontalContentAlignment="Stretch"
  69. Focusable="False"
  70. Padding="10,0,0,0"
  71. Foreground="{TemplateBinding Foreground}"
  72. IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
  73. Width="{TemplateBinding Width}"
  74. Height="{TemplateBinding MinHeight}"
  75. Style="{StaticResource ToggleButtonStyle1}">
  76. <Grid>
  77. <Grid.ColumnDefinitions>
  78. <ColumnDefinition Width="40" />
  79. <ColumnDefinition />
  80. <ColumnDefinition Width="32" />
  81. </Grid.ColumnDefinitions>
  82. <Path Name="PathIcon"
  83. IsHitTestVisible="False"
  84. Grid.Column="0"
  85. Stretch="Uniform"
  86. Fill="{TemplateBinding Foreground}"
  87. Height="16"
  88. Data="{Binding DataContext.IconGeometry,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
  89. VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
  90. HorizontalAlignment="Center" />
  91. <ContentPresenter ContentSource="Header"
  92. Grid.Column="1"
  93. HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  94. VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
  95. <Path Name="PathArrow"
  96. IsHitTestVisible="False"
  97. Grid.Column="2"
  98. Stretch="Uniform"
  99. Fill="{TemplateBinding Foreground}"
  100. Data="{StaticResource DownGeometry}"
  101. Margin="0,0,10,0" Width="12"
  102. Height="12"
  103. VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
  104. HorizontalAlignment="Center" />
  105. </Grid>
  106. </ToggleButton>
  107. </Border>
  108. <Border x:Name="LeftFlag" Width="5" Visibility="Collapsed" Background="#009688" HorizontalAlignment="Left"/>
  109. <ContentPresenter Name="ExpandSite" Visibility="Collapsed" Grid.Row="1" />
  110. </Grid>
  111. <ControlTemplate.Triggers>
  112. <Trigger Property="IsExpanded" Value="true">
  113. <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible" />
  114. <Setter Property="Data" TargetName="PathArrow" Value="{StaticResource UpGeometry}" />
  115. </Trigger>
  116. <Trigger Property="IsMouseOver" Value="True" SourceName="BorderHeader">
  117. <Setter Property="Visibility" Value="Visible" TargetName="LeftFlag" />
  118. <Setter Property="Foreground" Value="White" />
  119. </Trigger>
  120. <Trigger Property="IsExpanded" Value="True">
  121. <Setter Property="Visibility" Value="Visible" TargetName="LeftFlag" />
  122. <Setter Property="Foreground" Value="White" />
  123. </Trigger>
  124. </ControlTemplate.Triggers>
  125. </ControlTemplate>
  126. </Setter.Value>
  127. </Setter>
  128. </Style>
  129. <Style x:Key="ListBoxStyle1" TargetType="ListBox">
  130. <Setter Property="BorderThickness" Value="0"/>
  131. <Setter Property="Margin" Value="0"/>
  132. <Setter Property="Padding" Value="0"/>
  133. <Setter Property="Background" Value="Red"/>
  134. <Setter Property="Template">
  135. <Setter.Value>
  136. <ControlTemplate TargetType="ListBox">
  137. <Border BorderThickness="{TemplateBinding BorderThickness}">
  138. <ScrollViewer Margin="{TemplateBinding Padding}"
  139. Focusable="false">
  140. <StackPanel IsItemsHost="True" />
  141. </ScrollViewer>
  142. </Border>
  143. </ControlTemplate>
  144. </Setter.Value>
  145. </Setter>
  146. </Style>
  147. <Style x:Key="MenuItemStyle1" TargetType="ListBoxItem">
  148. <Setter Property="SnapsToDevicePixels" Value="true"/>
  149. <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
  150. <Setter Property="Foreground" Value="LightGray"/>
  151. <Setter Property="Margin" Value="0"/>
  152. <Setter Property="Padding" Value="0"/>
  153. <Setter Property="MinHeight" Value="40"/>
  154. <Setter Property="Template">
  155. <Setter.Value>
  156. <ControlTemplate TargetType="ListBoxItem">
  157. <Border Name="Border"
  158. BorderThickness="0"
  159. Padding="40 0 0 0"
  160. Background="{Binding MenuItemBackground,Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
  161. SnapsToDevicePixels="True">
  162. <ContentPresenter VerticalAlignment="Center"/>
  163. </Border>
  164. <ControlTemplate.Triggers>
  165. <Trigger Property="IsSelected" Value="true">
  166. <Setter TargetName="Border" Property="Background" Value="{Binding MenuItemSelectedBackground,Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"/>
  167. <Setter Property="Foreground" Value="White"/>
  168. </Trigger>
  169. <Trigger Property="IsEnabled" Value="false">
  170. <Setter Property="Foreground" Value="LightGray"/>
  171. </Trigger>
  172. </ControlTemplate.Triggers>
  173. </ControlTemplate>
  174. </Setter.Value>
  175. </Setter>
  176. </Style>
  177. <Style TargetType="local:SideMenuItem">
  178. <Setter Property="Template">
  179. <Setter.Value>
  180. <ControlTemplate TargetType="local:SideMenuItem">
  181. <Expander BorderThickness="0"
  182. Header="{Binding HeaderText}"
  183. IsExpanded="{Binding IsExpanded,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
  184. Background="{TemplateBinding ToggleBackground}"
  185. Style="{StaticResource MenuHeaderStyle1}">
  186. <ListBox x:Name="LB"
  187. Style="{StaticResource ListBoxStyle1}"
  188. ItemsSource="{Binding Items}"
  189. ItemContainerStyle="{StaticResource MenuItemStyle1}">
  190. </ListBox>
  191. </Expander>
  192. </ControlTemplate>
  193. </Setter.Value>
  194. </Setter>
  195. </Style>
  196. </ResourceDictionary>

然后在App.xaml里面添加引用:

  1. <Application x:Class="WPFDemos.App"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:WPFDemos">
  5. <Application.Resources>
  6. <ResourceDictionary>
  7. <ResourceDictionary.MergedDictionaries>
  8. <ResourceDictionary Source="pack://application:,,,/WPFDemos;component/Styles/SideMenu.xaml"/>
  9. </ResourceDictionary.MergedDictionaries>
  10. </ResourceDictionary>
  11. </Application.Resources>
  12. </Application>

最后就是创建一个窗体使用控件喽:

  1. <Window x:Class="WPFDemos.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WPFDemos"
  7. mc:Ignorable="d"
  8. x:Name="widnow"
  9. UseLayoutRounding="True"
  10. Background="LightBlue"
  11. Title="下拉菜单控件" Height="450" Width="800">
  12. <Grid>
  13. <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 20 0 0">
  14. <local:SideMenuItem DataContext="{Binding ItemViewModel}"
  15. MenuItemSelectedChanged="S"/>
  16. <local:SideMenuItem DataContext="{Binding ItemViewModel}"
  17. Margin="10 0 0 0"
  18. MenuItemBackground="#24ACF2"
  19. MenuItemSelectedBackground="YellowGreen"
  20. ToggleBackground="#007ACC"
  21. MenuItemSelectedChanged="S"/>
  22. </StackPanel>
  23. <TextBlock x:Name="log" HorizontalAlignment="Center" FontSize="30" VerticalAlignment="Bottom" Margin="0 0 0 50"/>
  24. </Grid>
  25. </Window>

窗体的后台代码如下,定义了viewmodel实体和绑定了方法:

  1. using System.Collections.Generic;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Media;
  5. namespace WPFDemos
  6. {
  7. public partial class MainWindow : Window
  8. {
  9. public SideMenuItemViewModel ItemViewModel { get; set; }
  10. public MainWindow()
  11. {
  12. ItemViewModel = new SideMenuItemViewModel()
  13. {
  14. HeaderText = "快速开始",
  15. IconGeometry = FindResource("IconInfo") as Geometry,
  16. Items = new List<object>()
  17. {
  18. "5.0新变化",
  19. "第一个项目",
  20. "第一个模块",
  21. "自定义用户",
  22. "捐赠",
  23. "FAQ"
  24. }
  25. };
  26. InitializeComponent();
  27. DataContext = this;
  28. }
  29. private void S(object sender, RoutedEventArgs e)
  30. {
  31. var s = e.OriginalSource as ListBox;
  32. var str = s.SelectedItem;
  33. log.Text = str.ToString();
  34. }
  35. }
  36. }

这里,视频中演示的效果就实现啦,效果图如下:

c4c18d1241c450aaac4b1b715e4d70af.png

结束喽~

如果喜欢,点个赞呗~

-----------------------------------

公众号【Csharp编程大全】,需要进技术群交流的,请添加小编mm1552923!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/493445
推荐阅读
相关标签
  

闽ICP备14008679号