赞
踩
有小伙伴问我有没有做过菜单栏,这我确实没做过,不过现在做还不晚吧,
先来做一个MenuItem,使用MVVM模式写,这样创建菜单的时候,只要绑定datacontext,就ok了,使用极为方便,还可以自定义颜色相关的属性。
先来看一下效果:
下面就来看看代码喽:
首先创建一个自定义控件类:
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Markup;
- using System.Windows.Media;
-
-
- namespace WPFDemos
- {
- [DefaultProperty("MenuItems")]
- [ContentProperty("MenuItems")]
- [TemplatePart(Name = LB, Type = typeof(ListBox))]
- public class SideMenuItem : Control
- {
- private const string LB = "LB";
- private ListBox _listBox;
- public bool IsExpanded
- {
- get { return (bool)GetValue(IsExpandedProperty); }
- set { SetValue(IsExpandedProperty, value); }
- }
- public static readonly DependencyProperty IsExpandedProperty =
- DependencyProperty.Register("IsExpanded", typeof(bool), typeof(SideMenuItem), new PropertyMetadata(false));
-
-
- public List<object> MenuItems
- {
- get { return (List<object>)GetValue(MenuItemsProperty); }
- set { SetValue(MenuItemsProperty, value); }
- }
- public static readonly DependencyProperty MenuItemsProperty =
- DependencyProperty.Register("MenuItems", typeof(List<object>), typeof(SideMenuItem), new PropertyMetadata(default(List<object>)));
-
-
- public Brush ToggleBackground
- {
- get { return (Brush)GetValue(ToggleBackgroundProperty); }
- set { SetValue(ToggleBackgroundProperty, value); }
- }
- public static readonly DependencyProperty ToggleBackgroundProperty =
- DependencyProperty.Register("ToggleBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(0x2d, 0x2d, 0x30))));
-
-
- public Brush MenuItemBackground
- {
- get { return (Brush)GetValue(MenuItemBackgroundProperty); }
- set { SetValue(MenuItemBackgroundProperty, value); }
- }
- public static readonly DependencyProperty MenuItemBackgroundProperty =
- DependencyProperty.Register("MenuItemBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(0x16, 0x18, 0x1D))));
-
-
-
-
-
-
- public Brush MenuItemSelectedBackground
- {
- get { return (Brush)GetValue(MenuItemSelectedBackgroundProperty); }
- set { SetValue(MenuItemSelectedBackgroundProperty, value); }
- }
- public static readonly DependencyProperty MenuItemSelectedBackgroundProperty =
- DependencyProperty.Register("MenuItemSelectedBackground", typeof(Brush), typeof(SideMenuItem), new PropertyMetadata(Brushes.Green));
-
-
- public static readonly RoutedEvent MenuItemSelectedChangedEvent = EventManager.RegisterRoutedEvent("MenuItemSelectedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SideMenuItem));
-
-
- public event RoutedEventHandler MenuItemSelectedChanged
- {
- add { AddHandler(MenuItemSelectedChangedEvent, value); }
- remove { RemoveHandler(MenuItemSelectedChangedEvent, value); }
- }
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- _listBox = (GetTemplateChild(LB) as ListBox) ?? throw new Exception("listbox Named with \"LB\" not found in the Template");
- _listBox.SelectionChanged -= _listBoxSelectionChanged;
- _listBox.SelectionChanged += _listBoxSelectionChanged;
- }
-
-
- private void _listBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (!(e.Source is ListBox)) return;
- RoutedEventArgs args = new RoutedEventArgs()
- {
- RoutedEvent = MenuItemSelectedChangedEvent,
- Source = _listBox,
- };
- RaiseEvent(args);
- }
- }
- }
然后创建一个控件的ViewModel类,BaseViewModel类就是大家都知道的基类,就不粘代码了,如果需要可以联系我:
- using System.Collections.Generic;
- using System.Windows.Media;
- namespace WPFDemos
- {
- public class SideMenuItemViewModel : BaseViewModel
- {
- private string _headerText;
- public string HeaderText
- {
- get { return _headerText; }
- set
- {
- _headerText = value;
- OnPropertyChanged(nameof(HeaderText));
- }
- }
- private List<object> _items = new List<object>();
- public List<object> Items
- {
- get { return _items; }
- set
- {
- _items = value;
- OnPropertyChanged(nameof(Items));
- }
- }
- private Geometry _iconGeometry;
- public Geometry IconGeometry
- {
- get { return _iconGeometry; }
- set {
- _iconGeometry = value;
- OnPropertyChanged(nameof(IconGeometry));
- }
- }
- }
- }
然后在创建一个资源字典SideMenu.xaml,添加控件所需的样式:
- <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WPFDemos">
- <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>
- <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>
- <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>
-
-
- <Style x:Key="ToggleButtonStyle1" TargetType="ToggleButton">
- <Setter Property="Background" Value="Transparent"/>
- <Setter Property="VerticalContentAlignment" Value="Center"/>
- <Setter Property="Padding" Value="0"/>
- <Setter Property="Margin" Value="0"/>
- <Setter Property="VerticalAlignment" Value="Center"/>
- <Setter Property="HorizontalContentAlignment" Value="Center"/>
- <Setter Property="BorderThickness" Value="0"/>
- <Setter Property="HorizontalAlignment" Value="Center"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="ToggleButton">
- <Border SnapsToDevicePixels="true"
- BorderThickness="{TemplateBinding BorderThickness}"
- BorderBrush="{TemplateBinding BorderBrush}"
- Background="{TemplateBinding Background}">
- <ContentPresenter Name="UnCheckedElement"
- Margin="{TemplateBinding Padding}"
- HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
- RecognizesAccessKey="True"
- SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
- </Border>
- <ControlTemplate.Triggers>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Opacity" Value="0.9"/>
- </Trigger>
- <Trigger Property="IsPressed" Value="True">
- <Setter Property="Opacity" Value="0.6"/>
- </Trigger>
- <Trigger Property="IsEnabled" Value="False">
- <Setter Property="Opacity" Value="0.4"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <Style x:Key="MenuHeaderStyle1" TargetType="Expander">
- <Setter Property="Foreground" Value="LightGray" />
- <Setter Property="Background" Value="#2D2D30" />
- <Setter Property="HorizontalContentAlignment" Value="Left" />
- <Setter Property="VerticalContentAlignment" Value="Center" />
- <Setter Property="BorderThickness" Value="0" />
- <Setter Property="MinHeight" Value="50" />
- <Setter Property="MinWidth" Value="220" />
- <Setter Property="FontSize" Value="14" />
- <Setter Property="Template" >
- <Setter.Value>
- <ControlTemplate TargetType="Expander">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
- <Border x:Name="BorderHeader"
- ClipToBounds="True"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}"
- Background="{TemplateBinding Background}">
- <ToggleButton HorizontalAlignment="Stretch"
- HorizontalContentAlignment="Stretch"
- Focusable="False"
- Padding="10,0,0,0"
- Foreground="{TemplateBinding Foreground}"
- IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
- Width="{TemplateBinding Width}"
- Height="{TemplateBinding MinHeight}"
- Style="{StaticResource ToggleButtonStyle1}">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="40" />
- <ColumnDefinition />
- <ColumnDefinition Width="32" />
- </Grid.ColumnDefinitions>
- <Path Name="PathIcon"
- IsHitTestVisible="False"
- Grid.Column="0"
- Stretch="Uniform"
- Fill="{TemplateBinding Foreground}"
- Height="16"
- Data="{Binding DataContext.IconGeometry,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
- HorizontalAlignment="Center" />
- <ContentPresenter ContentSource="Header"
- Grid.Column="1"
- HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
- <Path Name="PathArrow"
- IsHitTestVisible="False"
- Grid.Column="2"
- Stretch="Uniform"
- Fill="{TemplateBinding Foreground}"
- Data="{StaticResource DownGeometry}"
- Margin="0,0,10,0" Width="12"
- Height="12"
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
- HorizontalAlignment="Center" />
- </Grid>
- </ToggleButton>
- </Border>
- <Border x:Name="LeftFlag" Width="5" Visibility="Collapsed" Background="#009688" HorizontalAlignment="Left"/>
- <ContentPresenter Name="ExpandSite" Visibility="Collapsed" Grid.Row="1" />
- </Grid>
- <ControlTemplate.Triggers>
- <Trigger Property="IsExpanded" Value="true">
- <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible" />
- <Setter Property="Data" TargetName="PathArrow" Value="{StaticResource UpGeometry}" />
- </Trigger>
- <Trigger Property="IsMouseOver" Value="True" SourceName="BorderHeader">
- <Setter Property="Visibility" Value="Visible" TargetName="LeftFlag" />
- <Setter Property="Foreground" Value="White" />
- </Trigger>
- <Trigger Property="IsExpanded" Value="True">
- <Setter Property="Visibility" Value="Visible" TargetName="LeftFlag" />
- <Setter Property="Foreground" Value="White" />
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <Style x:Key="ListBoxStyle1" TargetType="ListBox">
- <Setter Property="BorderThickness" Value="0"/>
- <Setter Property="Margin" Value="0"/>
- <Setter Property="Padding" Value="0"/>
- <Setter Property="Background" Value="Red"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="ListBox">
- <Border BorderThickness="{TemplateBinding BorderThickness}">
- <ScrollViewer Margin="{TemplateBinding Padding}"
- Focusable="false">
- <StackPanel IsItemsHost="True" />
- </ScrollViewer>
- </Border>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <Style x:Key="MenuItemStyle1" TargetType="ListBoxItem">
- <Setter Property="SnapsToDevicePixels" Value="true"/>
- <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
- <Setter Property="Foreground" Value="LightGray"/>
- <Setter Property="Margin" Value="0"/>
- <Setter Property="Padding" Value="0"/>
- <Setter Property="MinHeight" Value="40"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="ListBoxItem">
- <Border Name="Border"
- BorderThickness="0"
- Padding="40 0 0 0"
- Background="{Binding MenuItemBackground,Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
- SnapsToDevicePixels="True">
- <ContentPresenter VerticalAlignment="Center"/>
- </Border>
- <ControlTemplate.Triggers>
- <Trigger Property="IsSelected" Value="true">
- <Setter TargetName="Border" Property="Background" Value="{Binding MenuItemSelectedBackground,Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"/>
- <Setter Property="Foreground" Value="White"/>
- </Trigger>
- <Trigger Property="IsEnabled" Value="false">
- <Setter Property="Foreground" Value="LightGray"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
-
-
- <Style TargetType="local:SideMenuItem">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="local:SideMenuItem">
- <Expander BorderThickness="0"
- Header="{Binding HeaderText}"
- IsExpanded="{Binding IsExpanded,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SideMenuItem}}"
- Background="{TemplateBinding ToggleBackground}"
- Style="{StaticResource MenuHeaderStyle1}">
- <ListBox x:Name="LB"
- Style="{StaticResource ListBoxStyle1}"
- ItemsSource="{Binding Items}"
- ItemContainerStyle="{StaticResource MenuItemStyle1}">
- </ListBox>
- </Expander>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- </ResourceDictionary>
然后在App.xaml里面添加引用:
- <Application x:Class="WPFDemos.App"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WPFDemos">
- <Application.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
- <ResourceDictionary Source="pack://application:,,,/WPFDemos;component/Styles/SideMenu.xaml"/>
- </ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
- </Application.Resources>
- </Application>
最后就是创建一个窗体使用控件喽:
- <Window x:Class="WPFDemos.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:local="clr-namespace:WPFDemos"
- mc:Ignorable="d"
- x:Name="widnow"
- UseLayoutRounding="True"
- Background="LightBlue"
- Title="下拉菜单控件" Height="450" Width="800">
- <Grid>
- <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 20 0 0">
- <local:SideMenuItem DataContext="{Binding ItemViewModel}"
- MenuItemSelectedChanged="S"/>
-
-
- <local:SideMenuItem DataContext="{Binding ItemViewModel}"
- Margin="10 0 0 0"
- MenuItemBackground="#24ACF2"
- MenuItemSelectedBackground="YellowGreen"
- ToggleBackground="#007ACC"
- MenuItemSelectedChanged="S"/>
- </StackPanel>
- <TextBlock x:Name="log" HorizontalAlignment="Center" FontSize="30" VerticalAlignment="Bottom" Margin="0 0 0 50"/>
- </Grid>
- </Window>
窗体的后台代码如下,定义了viewmodel实体和绑定了方法:
- using System.Collections.Generic;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media;
- namespace WPFDemos
- {
- public partial class MainWindow : Window
- {
- public SideMenuItemViewModel ItemViewModel { get; set; }
- public MainWindow()
- {
- ItemViewModel = new SideMenuItemViewModel()
- {
- HeaderText = "快速开始",
- IconGeometry = FindResource("IconInfo") as Geometry,
- Items = new List<object>()
- {
- "5.0新变化",
- "第一个项目",
- "第一个模块",
- "自定义用户",
- "捐赠",
- "FAQ"
- }
- };
- InitializeComponent();
- DataContext = this;
- }
- private void S(object sender, RoutedEventArgs e)
- {
- var s = e.OriginalSource as ListBox;
- var str = s.SelectedItem;
- log.Text = str.ToString();
- }
- }
- }
这里,视频中演示的效果就实现啦,效果图如下:
结束喽~
如果喜欢,点个赞呗~
-----------------------------------
公众号【Csharp编程大全】,需要进技术群交流的,请添加小编mm1552923!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。