如何在WinForm上拖动菜单项时创建拖放线?

时间:2010-04-15 01:53:00

标签: c# menu menuitem

我想模仿Google Chrome / FireFox的功能,例如,在重新排列书签时,当您拖动菜单项时,它会在建议的放置点处创建一条黑线,如下所示:

alt text http://www.freeimagehosting.net/uploads/977900a13a.jpg

我已经实现了拖放功能来重新排列菜单,但我想添加这些分隔线作为附加功能。

有没有办法在.NET Framework(3.5)中执行此操作,还是必须使用Win32 api调用?我想走之前就想问一下。

2 个答案:

答案 0 :(得分:0)

在纯.NET代码中执行此操作的常用方法是创建一个无边框表单,其颜色和大小看起来像下拉点行。还要在此表单上将TopMost属性设置为True。

然后使用MouseDown / MouseUp / MouseMove事件确定显示下拉线的时间和位置以响应用户操作。

要正确定位下拉线表单,您需要查看Control.PointToScreen和/或Control.RectangleToScreen(以及可能的Control.PointToClient)方法。

答案 1 :(得分:0)

我认为最简单的方法是获取您拖动的弹出菜单的句柄。获得句柄后,可以使用Graphics对象直接在其上绘制。

获取句柄可能需要一些API mojo。我正在查找。

更新:根本没有多少魔力,尽管有一个具有讽刺意味的问题(见下文)。为此,请添加

using System.Runtime.InteropServices;

在您的表格或课程的顶部或其他任何地方。在某处添加此声明:

[DllImport("user32.dll", EntryPoint = "FindWindow")]
    private static extern IntPtr FindWindowA(string lpClassName, 
    string lpWindowName);

弹出菜单窗口(意味着您通常不会看到的部分)是最顶层的窗口,其类名为“#32768”。此代码显示如何获取菜单的窗口句柄并直接绘制到其上:

IntPtr hWnd = FindWindowA("#32768", null);
if (hWnd != IntPtr.Zero)
{
    using (Graphics g = Graphics.FromHwnd(hWnd))
    { 
        g.FillRectangle(Brushes.Red,
            new Rectangle(0, 0, 20, 20));
    }
}

此示例仅在菜单的左上角绘制一个20x20的红色方块。要渲染下拉线,你需要做更多的工作来确定它应该在哪里,然后在那里绘制你想要的任何东西。在我看来,它只是一个两像素高的黑色线条,每端都有很少的部分箭头,因此模仿起来应该不难。

你可能不得不担心清理你画的任何东西,但我对此表示怀疑。弹出菜单窗口是临时的,我认为当你将投影移动到它们上面时,它们会自动重新绘制。如果没有,则每次下拉线改变位置时,您可能必须向弹出菜单窗口发送重新显示消息。

即使您打开了多个嵌套菜单(可能都是类名“#32768”),它似乎也能正常工作 - FindWindow似乎总是返回z顺序中最顶层的菜单。另一个好处 - 因为你正在绘制菜单窗口本身,该行将位于半透明的放置光标下,这就是你想要的。

具有讽刺意味的问题:我在一系列不同的程序和菜单上测试了这一点。它适用于所有这些菜单和除了 Internet Explorer中的“收藏夹”菜单。我猜这个特定的菜单使用的不是内置的Windows菜单。如果您使用常规的.Net菜单进行此操作,它应该可以正常工作。