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

使用图像创建 WPF 菜单(带下拉子菜单)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (7投票s)

2012 年 11 月 29 日

CPOL

6分钟阅读

viewsIcon

35213

使用 WPF 中的图像创建菜单(含下拉子菜单)。

引言

我花了几天时间浏览技术文章,试图让 WPF 像 WinForms 一样创建带有图像和下拉菜单的 ToolTip 风格菜单。我找到了很多 hack 方法,但内心深处我知道 WPF 开发者肯定实现了一些巧妙的 XAML 方法来创建菜单,其中涉及图像的相对引用和垂直下拉菜单,而不是拼凑出来的 WinForm 遗留物。

我猜对了。

然而,我还没有找到一个明确的参考。所以,我来创建一个。希望这能帮助到其他人,让你们不必像我一样经历几天的试错!

第一步:跟我一起重复:WPF 不是 WinForms。重复大约 100 次。将你对嵌入式资源的所有知识从脑海中清除。另外,删除所有关于 ToolTip 驱动菜单的知识。好的……既然我们已经解决了这个问题,就该从 WPF 的视角重新构建这些知识了。

教程

首先,创建一个 WPF 测试项目(或使用你自己的项目,因为我们都知道我们都讨厌别人说:“我们来在一个测试项目中做这件事!”,因为说实话,你只是想让它在当前项目里正常工作)。这无论你是使用 UserControl 还是 Window 都可以。无论你是编译为 DLL 还是 EXE 都可以。我保证。我已经测试过了。下面的所有代码都能工作……因为我已经编译、运行和测试过了。我郑重承诺这一点……因为我对 technet 文章最大的不满就是那些我知道从未经过编译器检验的代码。

  1. 在你的 XAML 中,添加 DataContext 指令以相对于自身进行绑定
<Window x:Class="VisualMenus.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350" Width="525"
DataContext="{Binding
RelativeSource={RelativeSource Self}}">

设置此属性可以确保你绑定到相对于当前数据上下文的资源(即,它不会回溯到父级,也不会去子级,也不会飘向云端……或任何其他类似的胡言乱语……天知道你不想意外地绑定到你的 Facebook 照片。

  1. 添加你的图像。如果你打算使用单调的文本菜单,请跳过此步。但是,如果你正在阅读本教程,你肯定不会想跳过这一步!
  • 在项目中添加一个名为 Images、Resources 或 Foo 的文件夹……这真的不重要。

  • 将你的图像添加到新文件夹中。最简单的方法是将其复制到 Windows Explorer 中刚刚创建的文件夹,然后将其作为现有文件吸入项目中。

  • 现在,这一点非常非常重要。对于每一个文件,请确保该图像的生成操作设置为“Resource”(资源),“复制到输出目录”设置为“不复制”。这是 WPF 中定义资源的改进方法。你不需要直接将其添加到生成首选项中,也不必生成 RESX 文件(记住,我说过要忘记所有那些!!)(我知道,是我刚才又提起了……我控制不了……我经过多年的训练……进步,而非完美,对吧?)

  1. 现在,进入有趣的部分……创建你的可视化菜单。
  • 回到你的 Window 或 User Control 的 XAML。创建一个 Menu。你可以从工具箱中拖放控件,也可以直接输入。我更喜欢后者……可能是我比较老派了。
  • 很漂亮,是吧?好的,现在我们来添加有趣的东西。首先,为一个菜单项定义一个 MenuItem.Icon 标签。

  • 现在,仍然在你的 XAML 中,在你的 Grid 上方创建一个名为 <Window.Resources> 的部分……或者,在 UserControl 的情况下,你将创建一个名为 <UserControl.Resources> 的部分,并将其放在你的 DockPanel、Grid 或 XAML 文件中的其他顶级可视化元素之前。添加一个 <BitmapImage> 资源定义,用于你想要关联到 MenuItem 的图像。然后,在 Image 标签中将其关联到你的 MenuItem。看看这个例子。

你会注意到我添加了几个额外的“美化”标签……对齐、高度、宽度等。这些都由你自己决定……随心所欲地让视觉效果达到你想要的样子。

这就是它在预览窗口中的样子。我喜欢预览窗口……只是随便说说。

此时,我将运行应用程序,展示这个菜单在运行时是什么样子,并证明图像确实如预期般显示。瞧!!它奏效了!!(如果你刚刚遇到这个教程,并且已经尝试了好几天才搞定,你就会理解我如此激动和欣喜的原因。)

看这里……图像正在显示,但并未复制到 bin 目录

  • 好了,现在是时候连接其余的菜单项,并继续进行这个有趣、令人兴奋的快乐部分的下拉菜单了。在你的 <Window.Resources>(或 <UserControl. Resources>)部分下,为你想要添加到菜单的每个图像添加一个引用,然后通过添加 MenuItem Icon Images 并按 Resource Key 引用来将每个引用连接到你的菜单。确保每个资源图像都有一个唯一的 Key!!

我们再测试一次,好吗?

  1. 此时,我将继续连接一些事件处理程序。
  • 菜单如果不做任何事情,那有什么意义,对吧?我发现最快的方法是转到每个 MenuItem,输入 Click="",IntelliSense 会为你提供一个选项,通过双击警报来创建一个新的事件处理程序。如果你愿意,之后可以重命名这些处理程序。

这是代码隐藏文件。我知道……这简直太明显了……但对某些人来说可能不是。别评判!

  1. 现在是下拉菜单。你知道的……那些用 WinForms 创建起来很容易,但在 WPF 中却似乎难以捉摸的菜单?是的,就是那些。它们并不像你想象的那么难。回到 XAML,在你的菜单项下方添加以下代码
<MenuItem.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
Orientation="Vertical"/>
</ItemsPanelTemplate>
</MenuItem.ItemsPanel>

现在,在该代码块下方添加菜单项,并也为它们提供事件处理程序。是的,就是这么简单。

还有……代码隐藏文件

连接你想要它完成的操作,你就完成了!!

是的,你可以像上面一样为下拉菜单项添加图像,它们会很好地显示在文本左侧。而且,因为我郑重承诺过,这里是完整的运行代码

尽情享受吧,祝你编码愉快!!

关注点

我在这次练习中学到的最重要的一点是……如果你要写一个代码教程……尽量不要想当然!当你说到“将生成操作更改为 Resource”之类的话时,明确指出在哪里进行更改将非常有帮助。项目中的一切都有一个相关的生成操作。如果你正在阅读(即使是我的)代码教程,而有些地方不清楚……请寻求澄清,因为……阅读它的其他人同样想知道作者在写的时候脑子里在想什么。

历史

初稿

© . All rights reserved.