开发者

How do I create drop lines while dragging a menu item on a WinForm?

开发者 https://www.devze.com 2022-12-26 17:27 出处:网络
I want to mimic the functionality of Google Chrome/FireFox for example, when rearranging your bookmarks, when you are dragging the menu item, it creates a black line at the proposed drop point开发者_运

I want to mimic the functionality of Google Chrome/FireFox for example, when rearranging your bookmarks, when you are dragging the menu item, it creates a black line at the proposed drop point开发者_运维技巧, like this:

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

I've already implemented the Drag/Drop functionality to rearrange the menu, but I would like to add these separator lines as an additional feature.

Is there a way to do this within the .NET Framework (3.5) or shall I have to resort to Win32 api calls? Just wanted to ask before I went down that path.


A common way to do this in pure .NET code is to create a borderless Form that is coloured and sized to look like the drop point line. Also set the TopMost property to True on this form.

Then use the MouseDown/MouseUp/MouseMove events to determine when and where to display the drop line in response to user actions.

To correctly position the drop line form you will need to look into the Control.PointToScreen and/or Control.RectangleToScreen (and maybe Control.PointToClient) methods .


I think the easiest way to do this is to get the handle of the popped-up menu you're dragging over. Once you have the handle, you can draw directly onto it with a Graphics object.

Getting the handle probably requires some API mojo. I'm looking it up.

Update: not much mojo at all, although there's an ironic catch (see below). To do this, add

using System.Runtime.InteropServices;

at the top of your form or class or whatever. Add this declaration somewhere:

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

A popup-menu window (meaning the part you don't normally see) is a topmost window with the classname "#32768". This code shows how to get the menu's windows handle and draw directly onto it:

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));
    }
}

This sample just draws a 20x20 red square in the upper left corner of the menu. To render the drop line, you'd have to do a bit more work to figure out where exactly it should be, and then draw whatever you want there. It looks to me like it's just a two-pixel high black line with little partial arrows on each end, so it shouldn't be hard to mimic.

You may have to worry about cleaning up whatever you draw, but I doubt it. Popup menu windows are temporary, and I think they will automatically repaint anyway as you move your drop cursor over them. If not, you may have to send a repaint message to the popup menu window each time the drop line changes position.

It appears to work even when you have multiple nested menus open (which all presumably have the class name "#32768") - FindWindow appears to always return the top-most one in the z-order. One other good thing - because you're drawing onto the menu window itself, the line will be under the semi-transparent drop cursor, which is what you want.

The ironic catch: I tested this out on a bunch of different programs and menus. It worked on all of them and all the menus, except the Favorites menu in Internet Explorer. I'm guessing that that particular menu uses something other than the built-in Windows menus. If you're doing this with regular .Net menus, it should work fine.

0

精彩评论

暂无评论...
验证码 换一张
取 消