简体   繁体   中英

Wpf Mouse Events outside the bounds of a user control issue

I have a weird issue I have no ideea how to fix.

I'm creating a color picker from scratch. I'm doing so by creating a set of user controls and putting them together in a "master control".

When a user drags over the hue picker, for example, I handle the mouse down, move and up (inside the hue picker user control).

A simple bool dictates what happens, as far as the actual moving goes.

//Mouse down
 _isDrag = true;

//Mouse Move
if(!_isDrag) return; 
//Moving the position indicator shape thingy
//Calculating the hue

//Mouse Up
_isDrag = false;

But, if the mouse up occurs outside of the bounds of the hue picker, the mouse up event doesn't fire. Thus, when the user returns to the area of the hue picker, the shape indicator thingy runs rampart.

I am certain an answer lies somewhere but I'm afraid my searching skills are not up to the task. I've no idea what to look for.

Thank you for your time.

Solution:

private bool _isDrag;

    //Request Mouse capture for the Container
    private void MsDown(object sender, MouseButtonEventArgs e)
    {
        _isDrag = true;
        Mouse.Capture(MainContainer);
    }

    //Release Mouse capture
    private void MsUp(object sender, MouseButtonEventArgs e)
    {
        _isDrag = false;
        Mouse.Capture(null);
    }

    //Move the handle vertically along the main container, with respect to it's width - so it's centered.
    private void MsMove(object sender, MouseEventArgs e)
    {
        if (!_isDrag) return;
        Canvas.SetTop(Handle, e.GetPosition(ContentRow).Y - Handle.ActualHeight / 2);
    }

Thank you for your answer!

Edit 2:

Following up on my issue. While Capture basically did the trick, I noticed that, if fast dragging outside the bounds of the user control , sometimes the handle would get stuck close to the edge. If I would move the mouse slowly, this wouldn't happen. Weird. Also, I could never reach 0 and .ActualHeight

So I'll post my fix here, just in case another dude encounters this issue.

I split my grid like this:

<Grid.ColumnDefinitions>
        <ColumnDefinition Width="7"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
        <ColumnDefinition Width="7"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="7"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="7"></RowDefinition>
    </Grid.RowDefinitions>

With 7 being half the size of my handle (a circle).

The content area (the actual area you can interact with visually) is in the middle cell (in a separate grid with false hit test visibility).

Spanning the entire main grid is an invisible rectangle used for hit testing.

And to move the handle

        private void MoveHandle()
    {
        _pos.X = _pos.X - Handle.ActualWidth/2;
        _pos.Y = _pos.Y - Handle.ActualHeight / 2;
         //this is just to be sure. I'm paranoid. Being a color picker, these actually matter a lot.
        _pos.X = Math.Max(Math.Min(_pos.X, RectColor.ActualWidth - Handle.ActualWidth/2), -Handle.ActualWidth / 2);
        _pos.Y = Math.Max(Math.Min(_pos.Y, RectColor.ActualHeight -Handle.ActualWidth/2), -Handle.ActualHeight/2);

        Canvas.SetLeft(Handle, _pos.X);
        Canvas.SetTop(Handle, _pos.Y);
    }

I have no idea why the previous code I had almost worked. It's basically the same thing as before. But, somehow, this performs a million times better. Good luck!

The search term you are looking for is Mouse Capture . Capture in your MouseDown, and you can get mouse events even after the mouse leaves your control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM