精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
This project introduces a Windows Explorer clone in an early state. It contains browsing through all files and folders on your computer, including virtual folders. It uses the same ContextMenus as Windows Explorer and includes drag and drop support.
该项目介绍了早期状态Windows资源管理器的克隆项目。它能浏览电脑上所有文件和文件夹,包括虚拟文件夹。它使用和Windows资源管理器ContextMenus相同的上下文菜单 ,包括拖放支持。
I created this project with Visual Studio 2005 (.NET 2.0) and haven't tried it with .NET 1.1. I'm pretty sure it will work with .NET 1.1, but some changes need to be made. For example, I used the ToolBarMenuStrip which isn't available in 1.1. If anyone wants a 1.1 version and isn't able to convert it, I'm willing to convert it myself and provide the code.
我用Visual Studio 2005(.NET 2.0)完成了这个项目,并没有在.NET1.1下测试。我敢肯定它会兼容.NET1.1,但有些变化需要修改。比如,在1.1平台下无ToolBarMenuStrip。如果有人想要一个1.1版本,无法将其转换,我愿意亲自将它转化成且提供代码。
Quite a lot of different new things in this update. The most important new feature is plug-ins. You can now add your own plugins to this application, which will be used to add columns to the details view and to add special views. More on this in the "Plug-ins" section. Another important update is an addition to this article which explains how to use this Control in your own application and how to use it's functions, see the "Using the Control" section for this update.
相当多的在本次更新不同的新事物。最重要的新功能是插件。现在,您可以添加自己的插件,这个应用程序,这将用于列添加到详细信息视图,并添加特殊的意见。更多关于此的“插件”部分。另一个重要的更新是一个除了本文解释如何在自己的应用程序中使用此控件,以及如何使用它的功能,请参阅“使用控制”一节此更新。
Furthermore there are some small updates, additions and bug fixes. See the "History" section for these updates.
此外,还有一些小的更新,补充和bug修复。见“历史”部分,这些更新。
A bit of a small update really, but quite a handy one. I added the "New" menu to the standard ContextMenu of the ListView. So now it's possible to add new folders and files from within the program.
有点小更新真的,而是一个非常方便的。我添加了“新建”菜单到ListView的标准上下文菜单。因此,现在可以从程序中添加新的文件夹和文件。
Also a few bug fixes and another change in the update thread has been made, which also comes with some speed improvement.
也有一些bug修复和更新的另一个线程已被更改,其中还附带了一些速度的提高。
This is quite a large improvement since the first version. It doesn't include a lot of new features, but has a lot of fixes and speed improvement. The most important fix is the memory leak fix, which was caused by the update thread. When I was solving this problem I also added another update method. This method uses theSHChangeNotifyRegister function to retrieve Shell notify messages. These messages are used to make some more updates, like changing icons, inserting media and renaming. So now when you insert a disc into your disc-drive the icon and text of the drive will change to the ones from the disc.
这是自第一个版本相当大的改善。它不包括大量的新功能,但有很多的修复和速度改进。最重要的解决方法是内存泄漏修复,这是由更新线程造成的。当我解决这个问题,我还添加了另一个更新的方法。此方法使用SHChangeNotifyRegister函数来检索外壳通知消息。这些信息被用来做一些更多的更新,如改变图标,插入媒体和重命名。当您插入光盘插入所以,现在的盘驱动器的驱动器的图标和文字将变为从光盘的人。
One new feature which needs some attention is the rename function. You can now rename items by selecting the rename item from their ContextMenu or by pressing F2. Be aware though that this will also change the extension of the file, but it will warn you if you do this. When renaming multiple items it will take the name you entered and add a number to it, different for any item, somewhat like Windows Explorer. I recommend trying the rename function on some test files to see exactly what is does, before using it on other files.
其中一个新功能,需要一些注意的是重命名功能。现在,您可以通过自己的上下文菜单中选择重命名项目或按F2重命名的项目。要知道,虽然这也将改变文件的扩展名,但如果你这样做会向您发出警告。当重命名多个项目它会带你输入的名称,并添加了一些吧,不同的任何项目,有点像Windows资源管理器。我建议在一些测试文件试图重命名功能,看看到底是什么呢,用它在其他文件之前。
For any other changes made, see the "History" section.
对于其他更改,请参阅“历史记录”一节。
I was looking for something nice to program, when I got the idea of making my own Windows Explorer. I started this project with the idea of making an enhanced version of Windows Explorer with plug-in support. But before being able to enhance the Windows Explorer, you got to have a program which works like Windows Explorer. So I started searching the Internet for solutions.
我一直在寻找一些好的方案,当我做我自己的Windows资源管理器的想法。我开始这个项目,使Windows资源管理器的增强版本插件支持的想法。但是,能够增强Windows的资源管理器之前,你必须有一个程序,它的工作方式类似Windows资源管理器。于是我开始在互联网上寻找解决方案。
While searching the Internet I found a lot of programming around Windows Explorer and Shell extensions. But none really had everything I needed and most programs where written in C++ while I really wanted one in C#. Finally I found the article I needed to start my program: An All VB.NET Explorer Tree Control with ImageList Management. Although it was written in VB I could get a really great deal of information from it and the largest part of this project relies on that article. So for more information or for a VB version see that article.
虽然在网上搜索,我发现了很多围绕Windows资源管理器和外壳扩展编程。但没有人真的有我需要的一切,并在那里用C ++编写,而我真的很想之一,C#中大多数程序。最后,我发现我需要开始我的程序文章:一个所有VB.NET资源管理器树控制的ImageList管理。虽然这是写在VB我能得到一个真正伟大的交易,从它的信息,该项目的最大部分依赖于文章。因此,对于更多的信息,或对VB版看到一篇文章。
The only problem now was that I had never worked with the Windows Shell before. So first things first, I searched for articles explaining about how the Shell works and what you can do with it. Well, you can do a lot with it, too much to explain here. If you never worked with the Shell before or don't really know how the Shell works, I recommend this article: C# does Shell. This article also provides you with some links to MSDN articles. It takes some time to read them, but it definitely helped me a lot in making this program. You can also find a lot of info about all the Shell methods, structures and enumerations used in this program on MSDN.
现在唯一的问题是,我从来没有与Windows Shell中工作过。所以,首先第一件事情,我搜索了文章解释有关Shell是如何工作的,你可以用它做什么。那么,你可以做很多事情吧,太多的解释这里。如果你从来没有与外壳工作过或真的不知道外壳是如何工作的,我推荐这篇文章:C#不外壳。本文还提供了一些链接MSDN文章。它需要一些时间来阅读,但它肯定帮助了我很多在做这个节目。您还可以找到很多信息有关此计划的MSDN上使用的所有命令行管理程序的方法,结构和枚举。
After the base of the program was created I started implementing things like the Shell ContextMenu, drag/drop support and a Windows Explorer like ComboBox. I didn't really find a nice article on CodeProject for this, but a whole bunch where available on the Internet. I programmed everything with a wrapper around the Shell functions from the Windows API and was surprised how well it worked.
创建程序的基础后,我开始实施像外壳的ContextMenu,拖/放支持和Windows资源管理器类似组合框。我并没有真正找到在CodeProject一个很好的文章,这一点,但一大堆,其中在互联网上提供。我编程一切与周围的外壳功能的包装从Windows API,惊讶以及它如何工作。
To use this control in your own program, add a reference to the dll to your project. After that you can add theBrowser control to the toolbox and add it to your own project. I've created some properties which allow you to alter the behaviour and look of the control (at design time):
要使用此控件在自己的程序,添加对DLL的引用到您的项目。之后,你可以添加浏览器控件工具箱并将其添加到自己的项目。我已经创造了一些属性,让你可以改变的行为,并期待控制的(在设计时):
ShowNavigationBar | Shows or hides the navigation bar |
ShowFolders | Shows or hides the folder TreeView |
ShowFoldersButton | Shows or hides the button for the folder TreeView |
StartUpDirectory | Enumeration indicating which directory will be opened at startup |
StartUpDirectoryOther | String indicating which directory will be opened at startup (StartUpDirectorymust be "Other") |
ShellBrowser | Sets the ShellBrowser used for retrieving ShellItems, if set to null the Browserwill create it's own |
PluginWrapper | Sets the PluginWrapper used for retrieving plug-ins, if set to null the Browser will create it's own |
SplitterDistance | Sets the distance of the Splitter between the TreeView and the ListView>/TD> |
StartUpDirectory is an enumeration of special folders which are used to determine the startup location of theBrowser. If you want to provide your own location, you must set this value to "Other" and provide your own location in the StartUpDirectoryOther property.
启动目录是用来确定theBrowser的启动位置特殊文件夹的枚举。如果你想提供自己的位置,则必须将此值设置为“其他”,并提供在启动目录的其他财产您自己的位置。
The ShellBrowser and PluginWrapper properties are used when you want to add more than one Browsercontrol to your program. You can link those Browser controls by setting the ShellBrowser andPluginWrapper to the same object. This will make the program run a lot faster and more efficient than using a different ShellBrowser and PluginWrapper for the controls. In the demo project you'll see an example of how to add two Browser controls to a project.
该ShellBrowser和插件封装的属性,当你想添加多个Browsercontrol到你的程序中使用。您可以通过ShellBrowser andPluginWrapper设置为相同的对象链接的浏览器控件。这将会使程序运行速度快了很多,更有效率比使用不同的ShellBrowser和PluginWrapper的控制。在演示项目,你会看到如何添加两个浏览器控件项目的例子。
There are also a few properties which you can only use at run-time:
也有一些属性,你只能使用在运行时:
ListViewMode | Sets the initial view of the ListView (can't be "Small Icons") |
SelectedItem | Sets the current directory (ShellItem) |
SelectedNode | Sets the current directory (TreeNode) |
ShowFoldersButton | Shows or hides the button for the folder TreeView |
Lastly, there are methods to programmatically do some actions for the Browser:
最后,有一些方法以编程方式做一些动作的浏览器:
SelectPath | Sets the current directory |
BrowserBack | Same as clicking the Back button of the Browser |
BrowserForward | Same as clicking the Forward button of the Browser |
BrowserUp | Same as clicking the Up button of the Browser |
CreateNewFolder | Creates a new directory in the current directory, if possible |
SelectPath takes 3 different Objects to set the current directory. Either the ShellItem of the folder to select, astring of the path to the directory (this can also be like "My Documents\My Music") or a value of theSpecialFolders enumeration.
SelectPath需要3个不同的对象设置当前目录。无论是文件夹的ShellItem选择,路径的目录ASTRING(这也可以像“我的文档\我的音乐”)或SpecialFolder枚举值。
These are the classes which provide the actual control.
这些是提供实际控制的类。
Browser | The actual FileBrowser control |
BrowserTreeView, BrowserListView andBrowserComboBox | The controls used in the Browser |
BrowserTreeSorter and BrowserListSorter | The classes for sorting the TreeNodes andListViewItems |
BrowserComboItem | Provides the items for the BrowserComboBox |
These classes are quite simple and don't need a lot of explanation. To use my control in your project, you actually only need to use the Browser class. Just add this control to a form and all should be working. For more info, take a look at the comment in my code. Unfortunately at the moment my code doesn't have many comments, but I will try to add more shortly.
这些类是相当简单,不需要很多解释。要使用我的控制在你的项目,你实际上只需要使用浏览器类。就在这个控件添加到形式,都应该是工作。欲了解更多信息,看看我的代码中的注释。不幸的是,目前我的代码不会有很多意见,但我会尝试添加更多不久。
These classes provide easy access to Shell functions.
这些类可以方便地查阅到外壳的功能。
ShellAPI | Includes Windows API imports, constants, structures, and enumerations |
ShellBrowser | Used to retrieve the ShellItems which represent the file system |
ShellItem | Represents a file system object, folder or file (this can be a virtual folder) |
ShellImageList | Retrieves the Shell ImageList and makes them available for the Browser |
PIDL | Build around a pointer to a PIDL-structure, which is used to identify a file system object |
ShellAPI and ShellImageList are very much like the classes in Jim Parsells' project I mentioned earlier. They are similar to ShellDll and SystemImageListManager respectively. For more info about these classes first try his article. ShellItem comes from his CShItem class, but I've completely rewritten it, to match my needs. I'm not going to go through the detail of this class, but if many people really need more info about it, I might write an article about it.
ShellAPI和ShellImageList都非常像我前面提到的类。它们分别类似于外壳DLL和系统映像ListManager。有关这些类的更多信息第一次尝试他的文章。 ShellItem来自他CShItem类,但我已经完全重写它,以满足我的需求。我不会去通过这个类的细节,但如果很多人真的需要了解它的更多信息,我可能会写一个关于它的文章。
These classes provide a wrapper around the drag/drop operations and the ContextMenus for the control.
这些类提供各地的拖/放操作的包装和上下文菜单进行控制。
BrowserTVContextMenuWrapper andBrowserLVContextMenuWrapper | Provide ContextMenus to the TreeView andListView |
ContextMenuHelper | Takes care of executing Shell ContextMenucommands |
BrowserTVDropWrapper and BrowserLVDropWrapper | Provide drop operations to the TreeView andListView |
BrowserTVDragWrapper and BrowserLVDragWrapper | Provide drag operations to the TreeView andListView |
These classes are the most important and they are the ones I will explain in the rest of this article.
这些类是最重要的,他们才是我将在本文的其余部分解释。
The first thing you'll notice when trying to find a nice article about getting the Shell ContextMenu in your program, is that almost all articles are about making extensions to the menu and not about retrieving it for your own program. Luckily I found one blog that did explain this very thoroughly: How to host an IContextMenu. It was all in C++, so I had to translate it to C#. As this is an article existing of 11 parts, I'll try to explain everything here from a C# point of view. I'm going to assume you are familiar with the Shell namespace and pidls as it would take a lot of time to explain this here and this article is meant to cover the ContextMenu. So if you are not familiar with these terms, look for an article on those things first. The one I mentioned in the start of this article was all I needed (C# does Shell).
试图找到有关获取外壳的ContextMenu程序中的一个很好的文章的时候,你会注意到的第一件事,就是几乎所有的文章都是有关使扩展菜单,而不是有关检索它自己的程序。幸运的是,我发现了一个博客,并解释得很透彻:如何举办IContextMenu。这一切都在C + +,所以我不得不把它翻译为C#。由于这是现有的11个部分的文章中,我会试着在这里解释一切从C#的观点。我会假设你所熟悉的外壳命名空间和丸,因为它会花费大量的时间在这里解释这一点,这篇文章的目的是覆盖文本菜单。所以,如果你不熟悉这些术语,寻找那些东西先的文章。我在这篇文章的开头提到的一个是我所需要的(C#不外壳)。
Before I explain the procedure for showing the ContextMenu, I'll give a short description for the interfaces we are going to use:
在我解释的程序用于显示文本菜单,我给一个简短说明,我们将要使用的界面:
IShellFolder | Is used to manage folders, it is exposed by all Shell namespace folder objects |
IContextMenu | Is called by the Shell to either create or merge a shortcut menu associated with a Shell object |
IContextMenu2 | Is used to either create or merge a shortcut menu associated with a certain object when the menu involves owner-drawn menu items |
IContextMenu3 | Is used to create or merge a shortcut menu associated with a certain object when the menu implementation needs to process the WM_MENUCHAR message |
So know let's get started with the ContextMenu stuff. To retrieve the menu you want, you'll need a few things:
所以懂得,让我们开始使用ContextMenu的东西。为了获取你想要的菜单,你需要几件事情:
Not much has to be done to obtain the IShellFolder interface. The ShellItem class provides theIShellFolder for each directory, so you just have to get the ShellItem class for the parent directory and then you'll have the IShellFolder interface. The pidls can also be retrieved from the ShellItem class. In my control each TreeNode and ListViewItem has their own ShellItem in their Tag property, so it is also quite easy to get the pidls you need. After this has been done you have everything you to get the IContextMenu interface. TheIShellFolder interface has a method which will provide a lot of different interfaces for its children, these interfaces include the IContextMenu. We need to make a call to the GetUIObjectOf method from theIShellFolder, like in the following example:
没有太多工作要做,以获得的IShellFolder接口。该ShellItem类提供的IShellFolder为每个目录,所以你只需要拿到ShellItem类的父目录,然后你会拥有的IShellFolder接口。在PIDL或者也可以检索从ShellItem类。在我的控制每个树节点和ListViewItem的都有自己的ShellItem在他们的Tag属性,所以它也很容易得到你需要的PIDL或者。在此之后已经做了你的一切,你得到IContextMenu接口。该IShellFolder接口有一个方法,该方法将为其儿童提供了很多不同的接口,这些接口包括IContextMenu。我们需要一个电话,从theIShellFolder的GetUIObjectOf方法,就像下面的例子:
public static bool GetIContextMenu( IShellFolder parent, IntPtr[] pidls, out IntPtr icontextMenuPtr, out IContextMenu iContextMenu) { if (parent.GetUIObjectOf( IntPtr.Zero, (uint)pidls.Length, pidls, ref ShellAPI.IID_IContextMenu, IntPtr.Zero, out icontextMenuPtr) == ShellAPI.S_OK) { iContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown( icontextMenuPtr, typeof(IContextMenu)); return true; } else { icontextMenuPtr = IntPtr.Zero; iContextMenu = null; return false; } }
As you can see, you need an array of IntPtr. This array includes the pidls of the items for which to retrieve theIContextMenu. This can be any number, in our program this number depends on how many items are selected. With GetUIObjectOf you'll get a pointer to the IContextMenu and to obtain the real interface you need to use the Marshal class.
正如你所看到的,你需要的IntPtr的数组。该阵列包括的项目要检索的IContextMenu的PIDL或者。这可以是任何数目,在我们的方案本数目取决于多少项目被选中。随着GetUIObjectOf你会得到一个指向IContextMenu,并获得真正的界面,您需要使用Marshal类。
Now we need a ContextMenu and because we are calling only Windows API methods, all we need is a Handle to a ContextMenu. To make a new ContextMenu the Windows API way, we just need to callShellAPI.CreatePopupMenu(), which will return a pointer to the new ContextMenu. You can now add all the menu items from the Shell ContextMenu by calling the QueryContextMenu method from the IContextMenuinterface.
现在,我们需要一个文本菜单,并因为我们只调用Windows API的方法,我们需要的是一个处理一个文本菜单。为了使新的ContextMenu Windows API的方式,我们只需要callShellAPI.CreatePopupMenu(),它会返回一个指向新的ContextMenu。现在,您可以通过调用从文本菜单界面的QueryContextMenu方法添加来自外壳的ContextMenu所有的菜单项。
contextMenu = ShellAPI.CreatePopupMenu(); iContextMenu.QueryContextMenu( contextMenu, 0, ShellAPI.CMD_FIRST, ShellAPI.CMD_LAST, ShellAPI.CMF.EXPLORE | ShellAPI.CMF.CANRENAME | ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMF.EXTENDEDVERBS : 0));
Now the contextMenu pointer points to the ContextMenu we need. After this call you can change the menu in any way you want. To change the menu you can use the API functions AppendMenu and InsertMenu from theShellAPI class. After that it's time to show our menu to the user. We do this by callingShellAPI.TrackPopupMenuEx. This method will wait for the user to select an item and will return the id of the selected item. This id is not just the index of the item in the list, but it's a special id. To execute the command that goes with the selected item we need a CMINVOKECOMMANDINFOEX structure. We can use this with theInvokeCommand method from the IContextMenu to execute the selected command. For more info about this structure see MSDN.
现在的ContextMenu指针指向我们需要的文本菜单。在此调用后,你可以改变任何你想要的菜单。要更改菜单中,您可以使用API函数AppendMenu和InsertMenu从theShellAPI类。之后,它的时间来证明我们的菜单给用户。为此,我们callingShellAPI.TrackPopupMenuEx。这种方法将等待用户选择一个项目,并返回所选择的项目的ID。这个ID不在列表中的项目只是指数,但它是一个特殊的ID。要执行一个去与我们需要一个INVOKECOMMAND讯息展结构所选项的命令。我们可以使用这个从IContextMenu的InvokeCommand方法执行所选的命令。有关此结构的更多信息请参阅MSDN。
ShellAPI.CMINVOKECOMMANDINFOEX invoke = new ShellAPI.CMINVOKECOMMANDINFOEX(); invoke.cbSize = ShellAPI.cbInvokeCommand; invoke.lpVerb = (IntPtr)cmd; invoke.lpDirectory = parentDir; invoke.lpVerbW = (IntPtr)cmd; invoke.lpDirectoryW = parentDir; invoke.fMask = ShellAPI.CMIC.UNICODE | ShellAPI.CMIC.PTINVOKE | ((Control.ModifierKeys & Keys.Control) != 0 ? ShellAPI.CMIC.CONTROL_DOWN : 0) | ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMIC.SHIFT_DOWN : 0); invoke.ptInvoke = new ShellAPI.POINT(ptInvoke.X, ptInvoke.Y); invoke.nShow = ShellAPI.SW.SHOWNORMAL; iContextMenu.InvokeCommand(ref invoke);
In the previous example the cmd variable is the selected index. All we need to do is cast this to a pointer and the Shell functions know what to do with it. As you can see I also included some code for ModfierKeys. As you might know, when you delete a file using Windows Explorer, there are two ways to do it: moving it to the recycle bin, or deleting it permanently. When you just press delete, the selected file will be moved into the recycle bin, but when you hold shift and press delete, the file will be deleted permanently. That is why you have to add theModifierKeys to the structure.
在上例中的CMD变量是选定的索引。我们需要做的是施放此为指针和外壳功能知道该怎么办。正如你可以看到我还包括了一些代码ModfierKeys。正如你可能知道,当你删除使用Windows资源管理器的文件,有两种方法可以做到这一点:其移动到回收站或删除其永久。当你只是按Delete键,所选择的文件将会被移动到回收站,但是当你按住Shift键并按删除,该文件将被永久删除。这就是为什么你必须添加的辅助按键的结构。
Another thing to notice is that we add a POINT to the structure. This POINT represents the place on the screen where you pressed the right mouse button. Have you ever noticed that when you clicked Properties on theContextMenu of Windows Explorer, that the Properties window will be shown on the point where you right clicked your mouse button? Well it does and to have the same effect in your program you will have to set thisPOINT.
另外要注意的是,我们增加一个点的结构。这点表示您按鼠标右键,在屏幕上的位置。你有没有注意到,当您单击属性在Windows资源管理器的右键菜单,该属性窗口的地步,你右键点击您的鼠标按钮来显示?那么它和在你的程序中相同的效果,你必须设置thisPOINT。
When all of this worked I was really happy, but soon I found something strange. When you select the "Open With" or the "Send To" submenus, you don't see other menu items in it. As we also want this menus to work, we need to get some more interfaces. The IContextMenu has two child classes which are needed to get the menu's to work:IContextMenu2 and IContextMenu3. To get these interfaces we simply use the Marshal class like this:
当所有这一切工作,我真的很开心,但很快我就发现了一些奇怪的事情。当您选择“打开方式”或“发送到”子菜单中,你看不到它的其他菜单项。正如我们也希望这个菜单的工作,我们需要得到一些更多的接口。该IContextMenu有这些需要得到菜单下面两个子类:IContextMenu2和IContextMenu3.要获得这些接口,我们只需使用Marshal类是这样的:
Marshal.QueryInterface( icontextMenuPtr, ref ShellAPI.IContextMenu2_IID, out context2Ptr); Marshal.QueryInterface( icontextMenuPtr, ref ShellAPI.IContextMenu3_IID, out context3Ptr); iContextMenu2 = (IContextMenu2) Marshal.GetTypedObjectForIUnknown(context2Ptr, typeof(IContextMenu2)); iContextMenu3 = (IContextMenu3) Marshal.GetTypedObjectForIUnknown(context3Ptr, typeof(IContextMenu3));
These interfaces will draw the menus for us, but they need to know when to do this. For this we need to override the WndProc method and check the messages that are being send to it. When these messages are about creating, measuring or drawing the ContextMenu items we will call the HandleMenuMsg and HandleMenuMsg2 methods from the IContextMenu2 and IContextMenu3 interfaces respectively, these methods will do the rest of the necessary work.
这些接口将绘制菜单给我们,但他们需要知道什么时候才能做到这一点。为此,我们需要重写WndProc方法检查正在发送给它的消息。当这些消息是有关创建,测量和绘制文本菜单项,我们将分别调用从IContextMenu2的HandleMenuMsg和HandleMenuMsg2方法和IContextMenu3接口,这些方法会做必要的工作休息。
As you can read on MSDN, the IContextMenu2 interface will process the WM_INITMENUPOPUP,WM_MEASUREITEM and WM_DRAWITEM messages and the IContextMenu3 interface will process the WM_MENUCHARmessage. So if you encounter one of these messages while showing the ContextMenu call the HandleMenuMsgand HandleMenuMsg2 methods to handle the specific messages.
正如你可以阅读MSDN上,该IContextMenu2接口将处理WM_INITMENUPOPUP,WM_MEASUREITEM和WM_DRAWITEM消息和IContextMenu3接口将处理WM_MENUCHARmessage。所以,如果你遇到这些消息之一,同时显示文本菜单调用HandleMenuMsgand HandleMenuMsg2的方法来处理特定的消息。
protected override void WndProc(ref Message m) { if (iContextMenu2 != null && (m.Msg == (int)ShellAPI.WM.INITMENUPOPUP || m.Msg == (int)ShellAPI.WM.MEASUREITEM || m.Msg == (int)ShellAPI.WM.DRAWITEM)) { if (iContextMenu2.HandleMenuMsg( (uint)m.Msg, m.WParam, m.LParam) == ShellAPI.S_OK) return; } if (iContextMenu3 != null && m.Msg == (int)ShellAPI.WM.MENUCHAR) { if (iContextMenu3.HandleMenuMsg2( (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == ShellAPI.S_OK) return; } base.WmdProc(ref Message m); }
Once you implemented this, you will see that now the submenu's will also work the way they are supposed to.
一旦你实现这一点,你会看到,现在的子菜单中的也将它们应该的方式。
This is the main idea to get the ContextMenus to work. My program also adds the Collapse and ExpandMenuItems on a TreeNode ContextMenu, like Windows Explorer does. It will also raise an event for showing theContextMenuItems help String when the item is being hovered over. Just check my code if you need to know how to do this.
这是让ContextMenus工作的主要思想。我的程序还向树节点上下文菜单增加了折叠和展开菜单项,就像Windows资源管理器一样。它也将引发一个事件来显示上下文菜单项帮助字符串,当鼠标划过菜单上时。只要检查我的代码,你就会知道如何做到这一点。