How can I let .NET wrapper for Rebar decide the mouse cursor?
Asked Answered
M

1

10

I'm making a Rebar wrapper for .NET. Here's how I've made my control.

public class Rebar : Control {

    public Rebar() : base() {
        //Control won't even work if I let UserPaint enabled
        SetStyle(ControlStyles.UserPaint, false);
    }

    protected override CreateParams CreateParams {
        get {
            CreateParams cp = base.CreateParams;
            cp.ClassName = "ReBarWindow32"; //REBARCLASSNAME
            cp.ExStyle |= 0x00000080; //WS_EX_TOOLWINDOW
            //Windows Forms will control the position and size, not the native control
            cp.Style |= 0x00000004 | 0x00000008; //CCS_NORESIZE and CCS_NOPARENTALIGN
            return cp;
        }
    }

}

I tested my control by adding a REBARBANDINFO into the control and IT WORKED.

REBARBANDINFO info = new REBARBANDINFO();
info.cbSize = Marshal.SizeOf(typeof(REBARBANDINFO));
info.fMask = RBBIM_TEXT; // 0x00000004
info.lpText = "example";
SendMessage(this.Handle, RB_INSERTBANDW, -1, ref myband);

I won't include the implementation of my p/invoke signatures because everything is fine there.

The problem starts here

The control doesn't work the way I've expected, the Rebar cursor isn't respected and Cursor property takes control over the cursor, it even overrides the resize cursor.

Expectation

Expectation of Rebar wrapper

Reality

Reality of Rebar wrapper

Is that even possible? Yes, it is

Check out this example of a ListView. It IS possible to make a Control that respects its original cursor messages.

ListView example

How can I make my Rebar decide the mouse cursor instead of Cursor property?

Aditional: I've done my best to ask a good question. I double-checked the question to ensure it can be understood.

Muscatel answered 12/2, 2018 at 22:23 Comment(6)
Normally this sort of thing is done by tracking MouseMove and comparing the coordinates to a known visual element in order to change the cursor dynamically; at least that's what I do in my custom controls ;). Is there anything useful in RBN_SPLITTERDRAG or RBN_BEGINDRAG? (I've not used Rebar before) I'm surprised there is no RBN_DRAGTorin
RBN_SPLITTERDRAG and similar notifications (they're not messages) are not useful for this because cursor can only be set while dragging. Don't forget the Cursor property affects the whole control.Muscatel
"...they're not messages..." - what do you mean? They are notifications "...sent in the form of a WM_NOTIFY message".Torin
"Cursor property affects the whole control" - yes, but there is nothing stopping you from changing it during a mouse move. That's what I do all the time. Like I said, during a mouse move you perform a hittest and set the cursor to something appropriate depending on what the mouse is overTorin
AFAIK ListView does more than hit-testing, the cursor even changes when cursor is over the separatorMuscatel
ListView is different, the header is implemented by another control which handles its own messages. Or in other words, the ListView wrapper itself never sees anything that happens in the header beyond the messages that the header control intentionally sends to its parent. Makes customizing the headers pretty tricky btw. Rebar probably doesn't work that way (look with Spy++) so you have to explicitly pass relevant messages to the native Rebar with DefWndProc() to stop the Control class message handling from being helpful.Udometer
C
3

Control class handles WM_SETCURSOR and has its own logic.

As an option you can override WndProc and let the DefWndProc handle WM_SETCURSOR:

const int WM_SETCURSOR = 0x0020;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_SETCURSOR)
        base.DefWndProc(ref m);
    else
        base.WndProc(ref m);
}
Cosher answered 13/2, 2018 at 4:42 Comment(1)
Thanks a lot, you deserve my upvote and my 'answer mark'Muscatel

© 2022 - 2024 — McMap. All rights reserved.