65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight 菜单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (71投票s)

2010年9月26日

CPOL

7分钟阅读

viewsIcon

424104

downloadIcon

10433

一个轻量级、外观专业、支持 MVVM 的 Silverlight 下拉菜单

Silverlight Menus

目录

引言 

最近,我花了一些时间创建了一个 Silverlight 菜单组件,我将在我的项目中开始使用它。市场上的确有更好的组件,但是你可以免费使用这个组件,甚至用于商业目的,并且可以根据需要进行扩展。

本文首先介绍了 Silverlight 菜单的功能,以及实现细节。它有一些有趣的功能,例如 MVVM 支持、XAML 支持、命令、可勾选的菜单项、深层菜单和基本样式配置。虽然我远非专家,但我希望本文能让读者对如何使用 Silverlight 中的简单组件构建有用的组件有所了解。

你可以在此页面查看实时演示。

系统要求

要使用本文中描述的应用程序,你可以直接从 Microsoft 下载以下 100% 免费的开发工具

默认用法

使用 Silverlight 菜单最简单的方法是直接在 XAML 中声明 Menu 元素,将 MenuItem 分配给静态资源,并将 MenuItemClicked 事件绑定到某个事件处理程序

<l:Menu 
    x:Name="mnuTop"  
    MenuItem="{StaticResource mnuRoot}" 
    MenuItemClicked="Menu_MenuItemClicked"/>

这是简单部分。“困难”的部分是在页面或用户控件的 Resources 部分中声明 MenuItem 层次结构。请注意,上面的代码片段引用了 “mnuRoot” MenuItem,因此你必须使用 x:Key 值设置为 “mnuRoot”MenuItem 开始你的菜单树。顾名思义,这是我们层次结构树的根,紧随其下的是第一级菜单项,它们位于水平顶部面板中。下一级由第一级 MenuItem 的子项组成,它们将形成垂直菜单。接下来的所有级别都将是垂直菜单,显示在其父 MenuItem 元素的右侧。

以下是你可以自定义的 MenuItem 属性列表

  • MenuItems:这是菜单项内的子菜单列表。
  • Name:唯一标识菜单项的名称。请注意,每个分隔符也必须有一个唯一的名称。
  • ParentName[此属性仅供内部使用。]
  • Text:菜单项的显示文本。
  • ImagePath:显示在文本左侧的图像源的相对路径。如果找不到路径,则不显示图像。如果未提供图像,应用程序将查找位于 Menu 元素的 ImagesPath 属性 + 菜单项名称 + “.png” 的文件。
  • IsEnabled:布尔属性,用于启用/禁用特定菜单项。
  • IsCheckable:布尔属性,定义菜单项是否可以勾选。
  • IsChecked:如果菜单项是可勾选的,并且菜单项已被勾选,则会显示一个“checked.png”图像,否则不显示图像。
  • Level[此属性仅供内部使用。]
  • MenuGrid[此属性仅供内部使用。]

下面是我们的示例的 MenuItem 层次结构(请注意,此示例取自 Visual Studio 2010 菜单)。起初,这似乎需要做很多工作,但由于它是 XAML,你可以使用 Intellisense 来发现每个 MenuItem 可以自定义的属性

<UserControl.Resources>
    <l:MenuItem x:Key="mnuRoot" Name="mnuRoot">
            <l:MenuItem Name="mnuFile" Text="File">
                <l:MenuItem Name="mnuNewProject" Text="New Project..."/>
                <l:MenuItem Name="mnuNewWebSite" Text="New Web Site..."/>
                <l:MenuItem Name="mnuNewFile" Text="New File..."/>
                <l:MenuItem Name="mnuSeparator1" Text="-"/>
                <l:MenuItem Name="mnuOpenProject" Text="Open Project..."/>
                <l:MenuItem Name="mnuOpenWebSite" Text="Open Web Site..."/>
                <l:MenuItem Name="mnuOpenFile" Text="Open File..."/>
                <l:MenuItem Name="mnuSeparator2" Text="-"/>
                <l:MenuItem Name="mnuAdd" Text="Add">
                    <l:MenuItem Name="mnuNewProject2" Text="New Project...">
                        <l:MenuItem Name="mnuNewASPNETProject" 
			Text="New ASP.NET Project"/>
                        <l:MenuItem Name="mnuNewSilverlightProject" 
			Text="New Silverlight Project"/>
                    </l:MenuItem>
                    <l:MenuItem Name="mnuNewWebSite2" Text="New Web Site..."/>
                    <l:MenuItem Name="mnuSeparator11" Text="-"/>
                    <l:MenuItem Name="mnuExistingProject" Text="Existing Project..."/>
                    <l:MenuItem Name="mnuExistingWebSite" Text="Existing Web Site..."/>
                </l:MenuItem>
                <l:MenuItem Name="mnuSeparator3" Text="-"/>
                <l:MenuItem Name="mnuClose" Text="Close"/>
                <l:MenuItem Name="mnuCloseSolution" Text="Close Solution"/>
                <l:MenuItem Name="mnuSeparator4" Text="-"/>
                <l:MenuItem Name="mnuSave" Text="Save" IsEnabled="False"/>
                <l:MenuItem Name="mnuSaveAs" Text="Save As..." IsEnabled="False"/>
                <l:MenuItem Name="mnuSaveAll" Text="Save All"/>
                <l:MenuItem Name="mnuExportTemplate" Text="Export Template..."/>
                <l:MenuItem Name="mnuSeparator5" Text="-"/>
                <l:MenuItem Name="mnuPageSetup" Text="Page Setup..."/>
                <l:MenuItem Name="mnuPrint" Text="Print..."/>
                <l:MenuItem Name="mnuSeparator6" Text="-"/>
                <l:MenuItem Name="mnuRecentFiles" Text="Recent Files"/>
                <l:MenuItem Name="mnuRecentProjectsandSolutions" 
			Text="Recent Projects and Solutions"/>
                <l:MenuItem Name="mnuSeparator7" Text="-"/>
                <l:MenuItem Name="mnuExit" Text="Exit"/>
            </l:MenuItem>
            <l:MenuItem Name="mnuEdit" Text="Edit">
                <l:MenuItem Name="mnuUndo" Text="Undo"/>
                <l:MenuItem Name="mnuRedo" Text="Redo"/>
                <l:MenuItem Name="mnuSeparator8" Text="-"/>
                <l:MenuItem Name="mnuCut" Text="Cut"/>
                <l:MenuItem Name="mnuCopy" Text="Copy"/>
                <l:MenuItem Name="mnuPaste" Text="Paste"/>
                <l:MenuItem Name="mnuDelete" Text="Delete"/>
                <l:MenuItem Name="mnuSeparator9" Text="-"/>
                <l:MenuItem Name="mnuSelectAll" Text="Select All"/>
                <l:MenuItem Name="mnuSeparator10" Text="-"/>
                <l:MenuItem Name="mnuQuickFind" Text="Quick Find"/>
                <l:MenuItem Name="mnuQuickReplace" Text="Quick Replace"/>
            </l:MenuItem>
            <l:MenuItem Name="mnuView" Text="View">
                <l:MenuItem Name="mnuStartPage" Text="Start Page"/>
                <l:MenuItem Name="mnuOtherWindows" Text="Other Windows">
                    <l:MenuItem Name="mnuDatabaseExplorer" Text="Database Explorer"/>
                    <l:MenuItem Name="mnuErrorList" Text="Error List"/>
                    <l:MenuItem Name="mnuPropertiesWindow" Text="Properties Window"/>
                    <l:MenuItem Name="mnuSolutionExplorer" Text="Solution Explorer"/>
                    <l:MenuItem Name="mnuToolbox" Text="Toolbox"/>
                    <l:MenuItem Name="mnuSeparator30" Text="-"/>
                    <l:MenuItem Name="mnuWebBrowser" Text="Web Browser"/>
                    <l:MenuItem Name="mnuSeparator31" Text="-"/>
                    <l:MenuItem Name="mnuFindResults1" Text="Find Results 1"/>
                </l:MenuItem>
                <l:MenuItem Name="mnuSeparator12" Text="-"/>
                <l:MenuItem Name="mnuToolbars" Text="Toolbars">
                    <l:MenuItem Name="mnuBuild" Text="Build" 
			IsCheckable="True" IsChecked="True"/>
                    <l:MenuItem Name="mnuDataDesign" 
			Text="Data Design" IsCheckable="True"/>
                    <l:MenuItem Name="mnuDatabaseDiagram" 
			Text="Database Diagram" IsCheckable="True" IsChecked="True"/>
                    <l:MenuItem Name="mnuDebug2" Text="Debug" 
			IsCheckable="True" IsChecked="True"/>
                    <l:MenuItem Name="mnuFormatting" 
			Text="Formatting" IsCheckable="True"/>
                    <l:MenuItem Name="mnuHTMLSourceEditing" 
			Text="HTML Source Editing" IsCheckable="True"/>
                    <l:MenuItem Name="mnuLayout" Text="Layout" IsCheckable="True"/>
                    <l:MenuItem Name="mnuQueryDesigner" 
			Text="Query Designer" IsCheckable="True"/>
                    <l:MenuItem Name="mnuStandard" 
			Text="Standard" IsCheckable="True" IsChecked="True"/>
                    <l:MenuItem Name="mnuStyleSheet" 
			Text="Style Sheet" IsCheckable="True"/>
                    <l:MenuItem Name="mnuTableDesigner" 
			Text="Table Designer" IsCheckable="True"/>
                    <l:MenuItem Name="mnuTextEditor" 
			Text="Text Editor" IsCheckable="True"/>
                    <l:MenuItem Name="mnuViewDesigner" 
			Text="View Designer" IsCheckable="True"/>
                    <l:MenuItem Name="mnuWebBrowser2" 
			Text="Web Browser" IsCheckable="True"/>
                    <l:MenuItem Name="mnuWebOneClickPublish" 
			Text="Web One Click Publish" IsCheckable="True"/>
                    <l:MenuItem Name="mnuSeparator32" Text="-" IsCheckable="True"/>
                    <l:MenuItem Name="mnuCustomize2" 
			Text="Customize" IsCheckable="True"/>
                </l:MenuItem>
                <l:MenuItem Name="mnuFullScreen" Text="Full Screen"/>
                <l:MenuItem Name="mnuSeparator13" Text="-"/>
                <l:MenuItem Name="mnuPropertyPages" Text="Property Pages"/>
            </l:MenuItem>
            <l:MenuItem Name="mnuProject" Text="Project">
                <l:MenuItem Name="mnuAddClass" Text="Add Class..."/>
                <l:MenuItem Name="mnuAddNewItem" Text="Add New Item..."/>
                <l:MenuItem Name="mnuAddExistingItem" Text="Add Existing Item"/>
                <l:MenuItem Name="mnuSeparator14" Text="-"/>
                <l:MenuItem Name="mnuAddReference" Text="Add Reference"/>
                <l:MenuItem Name="mnuAddServiceReference" 
			Text="Add Service Reference..."/>
                <l:MenuItem Name="mnuSetasStartUpProject" 
			Text="Set as StartUp Project"/>
                <l:MenuItem Name="mnuProjectDependencies" 
			Text="Project Dependencies..."/>
                <l:MenuItem Name="mnuSeparator15" Text="-"/>
                <l:MenuItem Name="mnuSilverlightMenuProperties" 
			Text="SilverlightMenu Properties"/>
            </l:MenuItem>
            <l:MenuItem Name="mnuDebug" Text="Debug">
                <l:MenuItem Name="mnuStartDebugging" Text="Start Debugging"/>
                <l:MenuItem Name="mnuSeparator16" Text="-"/>
                <l:MenuItem Name="mnuBuildSilverlightMenu" Text="Build SilverlightMenu"/>
                <l:MenuItem Name="mnuSeparator17" Text="-"/>
                <l:MenuItem Name="mnuStepInto" Text="Step Into"/>
                <l:MenuItem Name="mnuStepOver" Text="Step Over"/>
                <l:MenuItem Name="mnuSeparator18" Text="-"/>
                <l:MenuItem Name="mnuWindows" Text="Windows">
                    <l:MenuItem Name="mnuImmediate" Text="Immediate"/>
                    <l:MenuItem Name="mnuLocals" Text="Locals"/>
                    <l:MenuItem Name="mnuSeparator33" Text="-"/>
                    <l:MenuItem Name="mnuCallStack" Text="Call Stack"/>
                </l:MenuItem>
                <l:MenuItem Name="mnuSeparator19" Text="-"/>
                <l:MenuItem Name="mnuClearAllDataTips" Text="Clear All DataTips"/>
                <l:MenuItem Name="mnuExportDataTips" Text="Export DataTips..."/>
                <l:MenuItem Name="mnuImportDataTips" Text="Import DataTips..."/>
                <l:MenuItem Name="mnuSeparator20" Text="-"/>
                <l:MenuItem Name="mnuOptionsandSettings" 
			Text="Options and Settings..."/>
            </l:MenuItem>
            <l:MenuItem Name="mnuData" Text="Data">
                <l:MenuItem Name="mnuShowDataSources" Text="Show Data Sources"/>
                <l:MenuItem Name="mnuAddNewDataSource" Text="Add New Data Source..."/>
            </l:MenuItem>
            <l:MenuItem Name="mnuTools" Text="Tools">
                <l:MenuItem Name="mnuConnecttoDatabase" Text="Connect to Database..."/>
                <l:MenuItem Name="mnuSeparator21" Text="-"/>
                <l:MenuItem Name="mnuExtensionManager" Text="Extension Manager..."/>
                <l:MenuItem Name="mnuSeparator22" Text="-"/>
                <l:MenuItem Name="mnuSettings" Text="Settings">
                    <l:MenuItem Name="mnuBasicSettings" Text="Basic Settings"/>
                    <l:MenuItem Name="mnuCodeOnly" Text="Code Only"/>
                    <l:MenuItem Name="mnuExpertSettings" Text="Expert Settings"/>
                    <l:MenuItem Name="mnuSeparator34" Text="-"/>
                    <l:MenuItem Name="mnuReset" Text="Reset..."/>
                    <l:MenuItem Name="mnuSeparator35" Text="-"/>
                    <l:MenuItem Name="mnuImportandExportSettings" 
			Text="Import and Export Settings..."/>
                </l:MenuItem>
                <l:MenuItem Name="mnuCustomize" Text="Customize..."/>
                <l:MenuItem Name="mnuOptions" Text="Options..."/>
            </l:MenuItem>
            <l:MenuItem Name="mnuWindow" Text="Window">
                <l:MenuItem Name="mnuSplit" Text="Split"/>
                <l:MenuItem Name="mnuSeparator27" Text="-"/>
                <l:MenuItem Name="mnuFloat" Text="Float"/>
                <l:MenuItem Name="mnuDock" Text="Dock"/>
                <l:MenuItem Name="mnuDockasTabbedDocument" 
			Text="Dock as Tabbed Document"/>
                <l:MenuItem Name="mnuAutoHide" Text="Auto Hide"/>
                <l:MenuItem Name="mnuHide" Text="Hide"/>
                <l:MenuItem Name="mnuSeparator28" Text="-"/>
                <l:MenuItem Name="mnuAutoHideAll" Text="Auto Hide All"/>
                <l:MenuItem Name="mnuNewHorizontalTabGroup" 
		Text="New Horizontal Tab Group"/>
                <l:MenuItem Name="mnuNewVerticalTabGroup" Text="New Vertical Tab Group"/>
                <l:MenuItem Name="mnuCloseAllDocuments" Text="Close All Documents"/>
                <l:MenuItem Name="mnuResetWindowLayout" Text="Reset Window Layout"/>
                <l:MenuItem Name="mnuSeparator29" Text="-"/>
                <l:MenuItem Name="mnu1MainPagexaml" Text="1 MainPage.xaml"/>
                <l:MenuItem Name="mnu2Menucs" Text="2 Menu.cs"/>
                <l:MenuItem Name="mnu3MenuItemcs" Text="3 MenuItem.cs"/>
                <l:MenuItem Name="mnu4MainPagexamlcs" Text="4 MainPage.xaml.cs"/>
                <l:MenuItem Name="mnu5Appxamlcs" Text="5 App.xaml.cs"/>
                <l:MenuItem Name="mnuWindows2" Text="Windows..."/>
                
            </l:MenuItem>
            <l:MenuItem Name="mnuHelp" Text="Help">
                <l:MenuItem Name="mnuViewHelp" Text="View Help"/>
                <l:MenuItem Name="mnuManageHelpSettings" Text="Manage Help Settings"/>
                <l:MenuItem Name="mnuSeparator23" Text="-"/>
                <l:MenuItem Name="mnuMSDNForums" Text="MSDN Forums"/>
                <l:MenuItem Name="mnuSeparator24" Text="-"/>
                <l:MenuItem Name="mnuSamples" Text="Samples"/>
                <l:MenuItem Name="mnuSeparator25" Text="-"/>
                <l:MenuItem Name="mnuCustomerFeedbackOptions" 
		Text="Customer Feedback Options..."/>
                <l:MenuItem Name="mnuRegisterProduct" Text="Register Product"/>
                <l:MenuItem Name="mnuCheckforUpdates" Text="Check for Updates"/>
                <l:MenuItem Name="mnuTechnicalSupport" Text="Technical Support"/>
                <l:MenuItem Name="mnuOnlinePrivacyStatement" 
		Text="Online Privacy Statement..."/>
                <l:MenuItem Name="mnuSeparator26" Text="-"/>
                <l:MenuItem Name="mnuAboutMicrosoftVisualWebDeveloper2010Express" 
	Text="About Microsoft Visual Web Developer 2010 Express"/>
            </l:MenuItem>
        </l:MenuItem>
</UserControl.Resources>

在上面的示例中,你必须实现 MenuItemClicked 事件,否则当用户单击特定菜单项时,你将无法采取行动。下面是此事件的一个实现示例,它显示了一个简单的 messagebox ,其中包含菜单项的名称,并告知可勾选菜单何时被勾选/取消勾选。

private void Menu_MenuItemClicked(object sender, EventArgs e)
{
    var clickedItem = (MenuItem)sender;
    
    if (clickedItem.IsCheckable)
        MessageBox.Show(string.Format("{0} is now {1}", clickedItem.Name, 
	clickedItem.IsChecked ? "CHECKED" : "UNCHECKED"));
    else
        MessageBox.Show(string.Format("You clicked: {0}", clickedItem.Name));
        
    switch (clickedItem.Name)
    {
        case "mnuOpenProject":
            var newMenuItem = new MenuItem()
            {
                Name = string.Format("Item{0}", menuIndex),
                Text = string.Format("{0} Item {0}", menuIndex)
            };
            menuIndex++;
            mnuTop.AddMenuItem(clickedItem, newMenuItem);
            break;
    }
}

支持 MVVM 模式

如果你不了解 MVVM (Model View View Model) 模式,这里有一个非常简单的解释:在上面的示例中,我们直接在视图(MainPage.xaml 文件)中创建了菜单层次结构,并且我们直接在视图的代码隐藏(MainPage.xaml.cs 文件)中实现了 MenuItemClicked 。另一方面,在 MVVM 模式中,我们不会为此使用视图。相反,我们会配置视图(MenuTestView.xaml 文件),以便菜单属性绑定到另一个类(由 MenuTestViewModel.cs 文件表示的视图模型)的属性。

下图显示了通用场景中的 MVVM 组件

MVVM

回到我们的应用程序:为了使用 MVVM 模式,请注释掉以下行,并使应用程序能够使用 MenuTestView 作为启动项

private void Application_Startup(object sender, StartupEventArgs e)
{
    //this.RootVisual = new MainPage();
    this.RootVisual = new MenuTestView();
}

打开 MenuTestView 视图并注意 MVVM 样式的不同之处:首先,我们必须定义 ImagesPath,因为 View 位于“\Views”文件夹中,这会改变图像的相对路径。然后我们必须配置 MenuItem 属性以绑定到 ViewModel 端的某个属性(在我们的例子中是 MVVMMenuItem)。最后是 Command 属性,它绑定到 ViewModel 端的 MenuCommand 属性。请注意,MenuCommand 的效果与实现 MenuItemClicked 事件相同,不同之处在于它是在 ViewModel 中实现而不是在代码隐藏中实现

<l:Menu 
    ImagesPath="{Binding ImagesPath}" 
    MenuItem="{Binding MVVMMenuItem}" 
    Command="{Binding Path=MenuCommand}"/>

以下代码片段显示了我们如何在视图模型中以编程方式实现菜单项层次结构。

public class MenuTestViewModel : INotifyPropertyChanged
{
    MenuItem mvvmMenuItem;
    string imagesPath = "../Images/";
    public MenuTestViewModel()
    {
        mvvmMenuItem = new MenuItem()
        {
            Name = "Root"
        };
        
        var mnuFile = new MenuItem() { Name = "mnuFile", Text = "File" };
        var mnuEdit = new MenuItem() { Name = "mnuEdit", Text = "Edit" };
        var mnuWindow = new MenuItem() { Name = "mnuWindow", Text = "Window" };
        var mnuHelp = new MenuItem() { Name = "mnuHelp", Text = "Help" };
        
        var mnuNew = new MenuItem() { Name = "mnuNew", Text = "New" };
        var mnuSeparator1 = new MenuItem() { Name = "mnuSeparator1", Text = "-" };
        var mnuOpenFile = new MenuItem() { Name = "mnuOpenFile", Text = "Open File" };
        var mnuSaveFile = new MenuItem() { Name = "mnuSave", 
			Text = "Save File", IsEnabled = false };
        var mnuCloseFile = new MenuItem() { Name = "mnuClose", 
			Text = "Close File", IsEnabled = false };
        var mnuSeparator2 = new MenuItem() { Name = "mnuSeparator2", Text = "-" };
        var mnuExit = new MenuItem() { Name = "mnuExit", Text = "Exit" };
        
        var mnuNewFile = new MenuItem() { Name = "mnuNewFile", Text = "New File" };
        var mnuNewProject = new MenuItem() { Name = "mnuNewProject", 
			Text = "New Project" };
        var mnuNewSolution = new MenuItem() { Name = "mnuNewSolution", 
			Text = "New Solution" };
        
        var mnuCut = new MenuItem() { Name = "mnuCut", Text = "Cut" };
        var mnuCopy = new MenuItem() { Name = "mnuCopy", Text = "Copy" };
        var mnuPaste = new MenuItem() { Name = "mnuPaste", Text = "Paste" };
        var mnuDelete = new MenuItem() { Name = "mnuDelete", Text = "Delete" };
        
        var mnuWindow1 = new MenuItem() { Name = "mnuWindow1", 
		Text = "Window 1", IsChecked = true, IsCheckable = true };
        var mnuWindow2 = new MenuItem() { Name = "mnuWindow2", 
		Text = "Window 2", IsChecked = false, IsCheckable = true };
        var mnuWindow3 = new MenuItem() { Name = "mnuWindow3", 
		Text = "Window 3", IsChecked = false, IsCheckable = true };
        
        var mnuAbout = new MenuItem() { Name = "mnuViewHelp", 
			Text = "About Silverlight Menu" };
        
        mnuNew.Add(mnuNewFile);
        mnuNew.Add(mnuNewProject);
        mnuNew.Add(mnuNewSolution);
        
        mnuFile.Add(mnuNew);
        mnuFile.Add(mnuSeparator1);
        mnuFile.Add(mnuOpenFile);
        mnuFile.Add(mnuSaveFile);
        mnuFile.Add(mnuCloseFile);
        mnuFile.Add(mnuSeparator2);
        mnuFile.Add(mnuExit);
        
        mnuEdit.Add(mnuCut);
        mnuEdit.Add(mnuCopy);
        mnuEdit.Add(mnuPaste);
        mnuEdit.Add(mnuDelete);
        
        mnuWindow.Add(mnuWindow1);
        mnuWindow.Add(mnuWindow2);
        mnuWindow.Add(mnuWindow3);
        
        mnuHelp.Add(mnuAbout);
        
        mvvmMenuItem.Add(mnuFile);
        mvvmMenuItem.Add(mnuEdit);
        mvvmMenuItem.Add(mnuWindow);
        mvvmMenuItem.Add(mnuHelp);
    }
            .
            .
            .

在每个 ViewModel 属性的设置器部分,我们必须调用 OnPropertyChanged 方法,以便 View 可以收到有关该更改的通知。

public MenuItem MVVMMenuItem
{
    get
    {
        return mvvmMenuItem;
    }
    set
    {
        mvvmMenuItem = value;
        OnPropertyChanged("MVVMMenuItem");
    }
}

public string ImagesPath
{
    get
    {
        return imagesPath;
    }
    set
    {
        imagesPath = value;
        OnPropertyChanged("ImagesPath");
    }
}

最后,我们实现了 Command 属性。请注意,在这种类型的绑定中,DoMenuCommand 方法引用在创建 Menu 元素时存储(请注意,DoMenuCommand 尚未触发)

public ICommand MenuCommand
{
    get { return new RelayCommand(p => DoMenuCommand(p)); }
}

public void DoMenuCommand(object param)
{
    var menuItem = (MenuItem)param;
    
    if (menuItem.IsCheckable)
        MessageBox.Show(string.Format("{0} is now {1}", 
Item.Name, menuItem.IsChecked ? "CHECKED" : "UNCHECKED"));
    else
        MessageBox.Show(string.Format("You clicked: {0}", menuItem.Name));
}

当用户单击菜单项时,Menu 类会调用 Execute 方法,并将选定的菜单项作为参数传递

	command.Execute(menuItem);

下图显示了我们 Silverlight 菜单的 MVVM 版本

MVVM Silverlight Menu

示例:配置黑色样式和白色样式菜单

根据您 Silverlight 应用程序使用的布局样式,Silverlight 菜单的默认样式可能会破坏您 Web 应用程序的视觉标识并产生不良结果。您可以通过配置 Menu 使用不同的画笔和颜色集来解决此问题,随心所欲。

以下 XAML 摘录显示了如何将 Silverlight 菜单配置为“黑色”样式

Black Style

<l:Menu 
    x:Name="mnuTop"
    BorderBrush="#FF303030" 
    TopPanelBrush="Black"
    ImageBackgroundBrush="#FF404040"
    FocusBrush="#FF808080"
    FocusBorderBrush="Gray"
    Foreground="Orange"
    Background="Black"
    MenuItem="{StaticResource mnuRoot}" 
    MenuItemClicked="Menu_MenuItemClicked"/>

下面您可以看到如何配置“白色”样式菜单

White Style

<l:Menu 
    x:Name="mnuTop"
    BorderBrush="#FFC0C0C0"
    TopPanelBrush="White"
    ImageBackgroundBrush="#FFC0C0C0"
    FocusBrush="#FFE0E0D0"
    FocusBorderBrush="#FFC0C0C0"
    Foreground="Black"
    Background="#FFF0F0F0"
    MenuItem="{StaticResource mnuRoot}" 
    MenuItemClicked="Menu_MenuItemClicked"/>  

向菜单项添加子项

在某些情况下,您需要动态添加子菜单。几乎所有处理文档的桌面应用程序都有“最近文件”功能。Silverlight 菜单已准备好处理这种情况

Adding Items

唯一的要求是,每当您想向菜单项添加子项时,都要调用 Menu 类的 AddMenuItem 方法(因为 AddMenuItem 会自动刷新菜单树)

switch (clickedItem.Name)
{
    case "mnuOpenProject":
        var newMenuItem = new MenuItem()
        {
            Name = string.Format("Item{0}", menuIndex),
            Text = string.Format("{0} Item {0}", menuIndex)
        };
        menuIndex++;
        mnuTop.AddMenuItem(clickedItem, newMenuItem);
        break;
}

可勾选的项目

如果已将菜单项配置为“可勾选”,则可以勾选/取消勾选菜单项

CheckableItems

此配置简单明了。为此,只需将菜单项标记为 Checkable="True",如下所示

<l:MenuItem Name="mnuToolbars" Text="Toolbars">
	<l:MenuItem Name="mnuBuild" Text="Build" IsCheckable="True" IsChecked="True"/>
	<l:MenuItem Name="mnuDataDesign" Text="Data Design" IsCheckable="True"/>
	<l:MenuItem Name="mnuDatabaseDiagram" Text="Database Diagram" 
		IsCheckable="True" IsChecked="True"/>
	<l:MenuItem Name="mnuDebug2" Text="Debug" IsCheckable="True" IsChecked="True"/>
	<l:MenuItem Name="mnuFormatting" Text="Formatting" IsCheckable="True"/>
	<l:MenuItem Name="mnuHTMLSourceEditing" Text="HTML Source Editing" 
		IsCheckable="True"/>
	<l:MenuItem Name="mnuLayout" Text="Layout" IsCheckable="True"/>
	<l:MenuItem Name="mnuQueryDesigner" Text="Query Designer" IsCheckable="True"/>
	<l:MenuItem Name="mnuStandard" Text="Standard" IsCheckable="True" 
		IsChecked="True"/>
	<l:MenuItem Name="mnuStyleSheet" Text="Style Sheet" IsCheckable="True"/>
	<l:MenuItem Name="mnuTableDesigner" Text="Table Designer" IsCheckable="True"/>
	<l:MenuItem Name="mnuTextEditor" Text="Text Editor" IsCheckable="True"/>
	<l:MenuItem Name="mnuViewDesigner" Text="View Designer" IsCheckable="True"/>
	<l:MenuItem Name="mnuWebBrowser2" Text="Web Browser" IsCheckable="True"/>
	<l:MenuItem Name="mnuWebOneClickPublish" Text="Web One Click Publish" 
		IsCheckable="True"/>
	<l:MenuItem Name="mnuSeparator32" Text="-" IsCheckable="True"/>
	<l:MenuItem Name="mnuCustomize2" Text="Customize" IsCheckable="True"/>
</l:MenuItem>

深层菜单

Silverlight 菜单支持“深层菜单”,也就是说,它可以处理您想要的任意多层菜单(在屏幕允许的范围内)

DeepMenus

这得益于 Menu 类中的递归方法 CreateVerticalGrid

private Grid CreateVerticalGrid(
Grid parentGrid,
double currentLeftMargin,
double currentTopMargin,
MenuItem parentMenuItem,
TextBlock txt,
Grid grdVertical)
{
    .
    .
    .
    
    int gridRow = 0;
    foreach (var mi3 in parentMenuItem.MenuItems)
    {
        .
        .
        .
        
        if (mi3.MenuItems.Count > 0)
        {
            CreateVerticalGrid(parentGrid, currentLeftMargin + verticalMenuWidth, 
		currentTopMargin, mi3, txt, grdVertical);
        }
        .
        .
        .
        
    }
    
    .
    .
    .
}

最终思考

如您所见,此 Silverlight 菜单由简单的 Silverlight 元素组成,因此如果它不提供您想要的功能,请原谅我。我很乐意听取您对其的反馈,特别是如果您在您的项目中使用它。正如我之前所说,此组件将成为我未来项目的一部分,因此我对其进行尽可能多的增强感兴趣,这就是您的反馈如此重要的原因。

历史

  • 2010-09-26:初始版本
  • 2011-04-24:修复了用户点击菜单控件外部时的一个错误(它没有自动关闭菜单) 
© . All rights reserved.