WPF中文网

Menu菜单

Menu控件继承于MenuBase,而MenuBase继承于ItemsControl。所以学习Menu之前,要先了解一下MenuBase基类。它是一个抽象类,拥有一个ItemContainerTemplateSelector模板选择器,并重写了一些关于键盘和鼠标的方法。

Menu的子项必须为MenuItem。这个MenuItem和前面的TreeViewItem类似,拥有共同的HeaderedItemsControl父类,也就是说,MenuItem本身也是一个集合控件,若要以代码形式加载Menu的内容,也必须要掌握递归的加载思路。

在本节中,我们将以两种方式加载Menu的数据。但是在学习之前,先熟悉一下MenuItem元素,因为,实际上,我们主要是操作MenuItem元素。

一、MenuItem元素

public class MenuItem : HeaderedItemsControl, ICommandSource
{
    public static readonly RoutedEvent ClickEvent;
    public static readonly DependencyProperty UsesItemContainerTemplateProperty;
    public static readonly DependencyProperty ItemContainerTemplateSelectorProperty;
    public static readonly DependencyProperty IsSuspendingPopupAnimationProperty;
    public static readonly DependencyProperty IconProperty;
    public static readonly DependencyProperty InputGestureTextProperty;
    public static readonly DependencyProperty StaysOpenOnClickProperty;
    public static readonly DependencyProperty IsCheckedProperty;
    public static readonly DependencyProperty IsHighlightedProperty;
    public static readonly DependencyProperty IsCheckableProperty;
    public static readonly DependencyProperty IsPressedProperty;
    public static readonly DependencyProperty IsSubmenuOpenProperty;
    public static readonly DependencyProperty CommandTargetProperty;
    public static readonly DependencyProperty CommandParameterProperty;
    public static readonly DependencyProperty CommandProperty;
    public static readonly RoutedEvent SubmenuClosedEvent;
    public static readonly RoutedEvent SubmenuOpenedEvent;
    public static readonly RoutedEvent UncheckedEvent;
    public static readonly RoutedEvent CheckedEvent;
    public static readonly DependencyProperty RoleProperty;

    public MenuItem();

    public static ResourceKey SubmenuHeaderTemplateKey { get; }
    public static ResourceKey SubmenuItemTemplateKey { get; }
    public static ResourceKey SeparatorStyleKey { get; }
    public static ResourceKey TopLevelItemTemplateKey { get; }
    public static ResourceKey TopLevelHeaderTemplateKey { get; }
    public bool IsCheckable { get; set; }
    public object CommandParameter { get; set; }
    public IInputElement CommandTarget { get; set; }
    public bool IsSubmenuOpen { get; set; }
    public MenuItemRole Role { get; }
    public bool IsPressed { get; protected set; }
    public bool IsHighlighted { get; protected set; }
    public bool StaysOpenOnClick { get; set; }
    public string InputGestureText { get; set; }
    public object Icon { get; set; }
    public bool IsSuspendingPopupAnimation { get; }
    public ItemContainerTemplateSelector ItemContainerTemplateSelector { get; set; }
    public bool UsesItemContainerTemplate { get; set; }
    public bool IsChecked { get; set; }
    public ICommand Command { get; set; }
    protected override bool IsEnabledCore { get; }
    protected internal override bool HandlesScrolling { get; }

    public event RoutedEventHandler Unchecked;
    public event RoutedEventHandler Click;
    public event RoutedEventHandler Checked;
    public event RoutedEventHandler SubmenuClosed;
    public event RoutedEventHandler SubmenuOpened;

    public override void OnApplyTemplate();
    protected override DependencyObject GetContainerForItemOverride();
    protected override bool IsItemItsOwnContainerOverride(object item);
    protected override void OnAccessKey(AccessKeyEventArgs e);
    protected virtual void OnChecked(RoutedEventArgs e);
    protected virtual void OnClick();
    protected override AutomationPeer OnCreateAutomationPeer();
    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e);
    protected override void OnInitialized(EventArgs e);
    protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e);
    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e);
    protected override void OnKeyDown(KeyEventArgs e);
    protected override void OnMouseEnter(MouseEventArgs e);
    protected override void OnMouseLeave(MouseEventArgs e);
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e);
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e);
    protected override void OnMouseMove(MouseEventArgs e);
    protected override void OnMouseRightButtonDown(MouseButtonEventArgs e);
    protected override void OnMouseRightButtonUp(MouseButtonEventArgs e);
    protected virtual void OnSubmenuClosed(RoutedEventArgs e);
    protected virtual void OnSubmenuOpened(RoutedEventArgs e);
    protected virtual void OnUnchecked(RoutedEventArgs e);
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item);
    protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item);
    protected internal override void OnVisualParentChanged(DependencyObject oldParent);

}

MenuItem从鼠标的交互上,提供了两种方式。第一种是提供了Click事件,开发者可以订阅该事件以编写相应的业务逻辑。第二种是提供了ICommand接口属性和CommandParameter命令参数,以WPF命令的形式开发业务逻辑。

下面,我们以一种交互方式为例。

二、Menu示例

前端代码

<Window x:Class="HelloWorld.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:HelloWorld" 
        xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        mc:Ignorable="d" FontSize="14"
        Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>        
        <Menu x:Name="_Menu">
            <MenuItem Header="文件">
                <MenuItem Header="新建" Click="MenuItem_Click"/>
                <MenuItem Header="打开" Click="MenuItem_Click">
                    <MenuItem.Icon>
                        <Image Source="/Images/logo.png"/>
                    </MenuItem.Icon>
                </MenuItem>
            </MenuItem>                      
            <MenuItem Header="编辑"/>
            <MenuItem Header="视图"/>
            <MenuItem Header="项目"/>
            <MenuItem Header="调试"/>
            <MenuItem Header="测试"/>
            <MenuItem Header="分析"/>
            <MenuItem Header="工具"/>
            <MenuItem Header="帮助"/>
        </Menu>
        <TextBlock x:Name="_TextBlock" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
    </Grid>
</Window>

后端代码

public partial class MainWindow : Window
{        
    public MainWindow()
    {
        InitializeComponent();            
    }

    private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        var item = sender as MenuItem;
        _TextBlock.Text = $"你单击了 {item.Header}";
    }
}

上面演示了Menu最基本的用法,如果希望采用数据绑定的方式加载菜单,则可以参考下面的作法。

三、Menu数据绑定

我们需要创建一个实体类,来代表Menu的每一个子项。

/// <summary>
/// 主菜单的实体
/// </summary>
public class MenuModel
{
    public string Name { get; set; }
    public List<MenuModel> Children { get; set; } = new List<MenuModel>();
    public string View { get; set; }
}

在前端代码中,需要设置Menu的ItemTemplate元素模板。

<Window x:Class="HelloWorld.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:HelloWorld" 
        xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        mc:Ignorable="d" FontSize="14"
        Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>        
        <Menu x:Name="_Menu">
            <Menu.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </Menu.ItemTemplate>
        </Menu>
    </Grid>
</Window>

因为MenuModel实体中有Children集合,所以在前端将Children作为HierarchicalDataTemplate的ItemsSource。并将Name显示出来。

最后,实例化一些子项数据,形成一个数据源,将这个数据源绑定到Menu的ItemsSource即可

来看看后端代码

public partial class MainWindow : Window
{
    public List<MenuModel> Menus { get; set; } = new List<MenuModel>();

    public MainWindow()
    {
        InitializeComponent();            
         
        for (int i = 0; i < 5; i++)
        {
            MenuModel parent = new MenuModel();
            parent.Name = $"一级菜单 ";
            for (int j = 0; j < 5; j++)
            {
                MenuModel child = new MenuModel();
                child.Name = $"二级菜单 ";
                parent.Children.Add(child);
            }
            Menus.Add(parent);
        }

        _Menu.ItemsSource = Menus;
    }
    
}

当前课程源码下载:(注明:本站所有源代码请按标题搜索)

文件名:045-《Menu菜单控件》-源代码 -1,045-《Menu菜单控件》-源代码 -2
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff

——重庆教主 2023年9月8日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1