RadLabel MouseUp event apparently not fired after MouseDown

2 Answers 279 Views
Label
Patgat
Top achievements
Rank 2
Iron
Iron
Iron
Patgat asked on 10 Feb 2023, 01:00 PM

Hi,

I have an issue with the following simple code where I drag a label over a GridView header. The DragDrop codes works fine.

I recently added the following ligne

            SetLabelBorder(sourceLabel, true);

In the DynamicLabel_MouseDown event handler starting the DragDrop along with the DynamicLabel_MouseUp event handler.

The labelBorder is normally setup in the MouseDown event, but even if I simply click on the label and release it, the MouseUp event is not called and the border cannot be suppressed.

Here is the related code:


RadLabel? PreviousLabelWithBorderSet = null; private void DynamicLabel_MouseDown(object? sender, MouseEventArgs e) { sourceLabel = sender as RadLabel; if (sourceLabel != null) { if (e.Button != MouseButtons.Left) return; isCurrentlyDragging = true; objCurrentlyDragged = DragObject.Label; SetLabelBorder(sourceLabel, true); gvCsvData.DragDrop += gvCsvData_DragDrop; if (sourceLabel != null) DoDragDrop(sourceLabel.Text, DragDropEffects.Copy); } } private void DynamicLabel_MouseUp(object? sender, MouseEventArgs e) { sourceLabel = sender as RadLabel; if (sourceLabel != null) { if (e.Button != MouseButtons.Left) return; if (sourceLabel != null) SetLabelBorder(sourceLabel, false); } } private void SetLabelBorder(RadLabel labelBorder, bool setBorder) {

// Temporary : At least suppress previous label border if new one is selected !! if (PreviousLabelWithBorderSet != null) { PreviousLabelWithBorderSet.LabelElement.BorderVisible = false; PreviousLabelWithBorderSet = null; } if (setBorder) { labelBorder.LabelElement.BorderVisible = true; PreviousLabelWithBorderSet = labelBorder; } else { labelBorder.LabelElement.BorderVisible = false; } }

 

What am I doing wrong ?

Thanks

Patrick

 

2 Answers, 1 is accepted

Sort by
0
Dinko | Tech Support Engineer
Telerik team
answered on 13 Feb 2023, 01:13 PM

Hi Patrick,

Thank you for the provided details.

I have tested your approach with a standalone RadLabel and the MouseUp event handler is called. To be able to investigate the cause of this behavior I will need to take a closer look at your implementation and where exactly this label is located. The mouse-up event could be handler by a parent but still, I will need to debug this to confirm it. If you could isolate this in a standalone project I would be glad to take a look.

I am looking forward to your reply.

Regards,
Dinko | Tech Support Engineer
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Patgat
Top achievements
Rank 2
Iron
Iron
Iron
commented on 17 Feb 2023, 05:33 PM

Hi Dinko,

thanks for your answer. I have prepared the attached exerpt of the issue.

Effectively, as I was extracting it from the complete code, I have seen that the MouseUp event for the 'Dynamic Labels' is in conflict with the Drag&Drop logic.

The attached sample works as follow :

The main purpose is to allow a user to drag any of the labels dynamically created onto a gridview header cell.

This works fine.

To help him, I also tried to higlight the currently selected label by setting up its border on Mouse Down and unset it on mouse up if the drag&drop move is not done (for example if the user start with the wrong label and click on another one).

So when you clic on a label the MouseDown set its border. The mouse up should unset it, but this is where vther is a conflict.

It is not clear to me how to change this without modifying the Drag&Drop code which is a bit sensible.

Another way could be to show the label being moved instead of simply setting its border, but I have no idea on how to do this.

Thanks for your feedback

Patrick

 

Dinko | Tech Support Engineer
Telerik team
commented on 22 Feb 2023, 11:07 AM

The drag-drop logic prevents the mouse up event from firing. My assumption is that you want to catch the moment when the user releases the button on top of the RadGroupBox. In this case, you can allow the drop operation to the RadGroupBox by setting the AllowDrop property to true. Then you can subscribe to the DragOver and set the effect to Move (for example). Then in the DragDrop event of the group box, you can change the reset the label border.

private void EnableCsvDataHandlersPart1()
{
    //....................
    // Drag & Drop handlers
    //....................
    gvCsvData.MouseDown += gvCsvData_MouseDown;
    gvCsvData.DragDrop += gvCsvData_DragDrop;
    gvCsvData.DragOver += gvCsvData_DragOver;
    gvCsvData.ViewCellFormatting += gvCsvData_ViewCellFormatting;
    gbFactElements.DragOver += GbFactElements_DragOver;
    gbFactElements.DragDrop += GbFactElements_DragDrop;
        
    gvCsvData.AllowDrop = true;

    //................................
    //    Dynamic labels handlers
    //................................
    for (int i = 0; i < DynLabels.Count; i++)
    {
        DynLabels[i].MouseDown += DynamicLabel_MouseDown;
        DynLabels[i].MouseUp += DynamicLabel_MouseUp;
    }
}

private void GbFactElements_DragOver(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Move;
}
private void GbFactElements_DragDrop(object sender, DragEventArgs e)
{
        //reset label border.
}

Could this approach work for you?

 

Patgat
Top achievements
Rank 2
Iron
Iron
Iron
commented on 23 Feb 2023, 03:20 PM

Hi Dinko,

I realize that didn't make myself clear, my apologies for that.

The current dragDrop works fine. However, I was looking for a way to show the user (without an animation) the name of the label he is currently 'moving' to the gridview header.

So, upon mouse down, I set the label border and start the DD operation in the same routine. However, if the user do no complete the DD operation by releasing the mouse click, the label border stay shown.

This could be confusing.

So I am only looking foa a way to hide the border if the user release the mouse click anywhere the drop is forbidden.

Patrick

0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 28 Feb 2023, 10:51 AM | edited on 28 Feb 2023, 10:53 AM

Hi, Patrick,

my colleague, Dinko is out of office today so I will be assisting you with this case. Thank you for the provided additional details. Indeed, the user is able to release the mouse at a random location. However, the standard OLE drag-and-drop functionality handles the drop operation at the target controls. Hence, you have two possible approaches here and it is up to you which one to choose:

1. The first one is to handle the DragDrop event of every possible control on the form that the mouse can be released. This requires ensuring that the drop operation is allowed in this control first. This is similar to the previously provided approach by Dinko.

2. The second one is to handle the mouse at global level and detect the mouse releasing. Even though it is outside the scope of the Telerik UI for WinForms suite, I have put some extra efforts to research in general programming forums how to handle the mouse globally. The following thread seems to be quite promising: https://stackoverflow.com/questions/11607133/global-mouse-event-handler  

After integrating the MouseHook class in your project and replacing the message that triggers the MouseAction with WM_LBUTTONUP, I have come to the following solution which result is illustrated in the gif file. Note that this is just a sample approach and it may not cover all possible cases. Feel free to further modify and extend it in a way which suits your requirements best. 

    public RadForm1()
    {
        InitializeComponent();

        MouseHook.Start();
        MouseHook.MouseAction += new EventHandler(Event);
    }
    private void Event(object sender, EventArgs e)
    {
        if (sourceLabel != null)
        {
            SetLabelBorder(sourceLabel, false);
        }       
    }

 

    public static class MouseHook
    {
        public static event EventHandler MouseAction = delegate { };

        public static void Start()
        {
            _hookID = SetHook(_proc);


        }
        public static void stop()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private static LowLevelMouseProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        private static IntPtr SetHook(LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_MOUSE_LL, proc,
                  GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        private static IntPtr HookCallback(
          int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
            {
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                MouseAction(null, new EventArgs());
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private const int WH_MOUSE_LL = 14;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
          LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
          IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);


    }

I hope this will cover the custom scenario you have.

Patgat
Top achievements
Rank 2
Iron
Iron
Iron
commented on 01 Mar 2023, 03:05 PM

Hi Dess,

A lot of thanks for this solution and the extra time you took for it. It is absolutely working fine.

I wish you a nice end of day

Patrick

Tags
Label
Asked by
Patgat
Top achievements
Rank 2
Iron
Iron
Iron
Answers by
Dinko | Tech Support Engineer
Telerik team
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or