使用接收过上一个WPF用户控件的事件,为什么控制接收鼠标按下,当窗口最大化鼠标移动? [英] Using Rx over events on a WPF UserControl, why does the control receive a mousedown and mousemove when the window is maximized?

查看:303
本文介绍了使用接收过上一个WPF用户控件的事件,为什么控制接收鼠标按下,当窗口最大化鼠标移动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这一次的让我有点困惑。

This one's got me a bit baffled.

我已经写上一些的UIElement扩展方法,提供了一些鼠标事件的观测量。以下是相关的:

I've written some extension methods on UIElement to provide Observables on some of the mouse events. Here are the relevant ones:

public static IObservable<EventPattern<MouseEventArgs>> ObserveMouseLeftButtonDown(this UIElement element)
{
    return Observable.FromEventPattern<MouseEventArgs>(element, "MouseLeftButtonDown");
}

public static IObservable<EventPattern<MouseEventArgs>> ObserveMouseMove(this UIElement element)
{
    return Observable.FromEventPattern<MouseEventArgs>(element, "MouseMove");
}



到目前为止,一切都令人麻木简单。然后,我创建了一个复合事件,当用户开始拖动的UIElement检测(这是所有使用我的一个自定义的控制,它的确切性质不是特别有用)。首先这里有一个小的辅助功能,看看如果用户的拖累最小的拖动距离:

So far, so mind-numbingly simple. Then I create a composite event to detect when the user starts dragging on the UIElement (this is all used by a custom control of mine, the exact nature of which isn't particularly relevant). First here's a little helper function to see if the user's dragged the minimum drag distance:

private static bool MinimumDragSeen(Point start, Point end)
{
    return Math.Abs(end.X - start.X) >= SystemParameters.MinimumHorizontalDragDistance
        || Math.Abs(end.Y - start.Y) >= SystemParameters.MinimumVerticalDragDistance;
}

和再复合观察的本身:

public static IObservable<EventPattern<MouseEventArgs>> ObserveMouseDrag(this UIElement element)
{
    return Observable.CombineLatest(
        element.ObserveMouseLeftButtonDown().Select(ep => ep.EventArgs.GetPosition(element)),
        element.ObserveMouseMove().Where(ep => ep.EventArgs.LeftButton == MouseButtonState.Pressed),
        (md, mm) => new { Down = md, Move = mm })
        .Where(i => MinimumDragSeen(i.Down, i.Move.EventArgs.GetPosition(element)))
        .Select(i => i.Move);
}

这所有的作品很好,牙齿多咬牙切齿和烦恼后面还有AREN吨基于接收拖动任何像样的例子,并与WPF控件拖放(其中大部分是在画布上拖动图像的天真简单重复)。

This all works nicely, after much gnashing of teeth and annoyance that there aren't any decent examples for Rx-based drag and drop with WPF controls (most of them are naively simplistic duplicates of dragging an image around in a canvas).

问题来了当窗口最大化,具体由标题栏双击。如果,在最大化的布局,其中订阅自身ObserveMouseDrag()我的控制中的一个鼠标光标下结束了它的最大化,而另一个后前显然接收的MouseLeftButtonDown和的MouseMove,其中之一。最终的结果是,它开始拖拽事件,如鼠标按钮已被释放,然后立即停止,然后趋于导致控件拖到本身,这在本应用中的一些情况实际上做什么的。

The problem comes when the window is maximized, specifically by double-clicking on the title bar. If, in the maximized layout, one of my controls which is subscribed to its own ObserveMouseDrag() ends up under the mouse cursor it receives a MouseLeftButtonDown and a MouseMove, one of them apparently before the maximize and the other one afterwards. The net result is that it starts a drag event, which then immediately stops as the mouse button has been released, and then tends to cause the control to drop onto itself, which in some situations in this app actually does something.

这是非常奇怪的,因为我不明白为什么我应该接受的MouseDown和MouseMove事件引起的双击最大化。当然,所有参与的鼠标事件应该由Windows,因为我没有使用自定义窗口边框或类似的东西来处理。

This is extremely odd, because I do not see why I should be receiving MouseDown and MouseMove caused by a double-click maximize. Surely all the mouse events involved in that should be handled by Windows, because I'm not using custom window borders or anything like that.

所以,没有任何人有任何想法?

So, does anybody have any ideas?

第二天...

固定它! (从下李的回答一些帮助,这个问题:的什么是使用接收来确定鼠标拖动年底的正确方法?

Fixed it! (With some help from Lee's answer below, and this question: What is the proper way to determine the end of a mouse drag using Rx?)

现在的代码看起来是这样的:

The code now looks like this:

public static IObservable<EventPattern<MouseEventArgs>> ObserveMouseDrag(this UIElement element)
{
    var mouseDown = element.ObserveMouseLeftButtonDown().Select(ep => ep.EventArgs.GetPosition(element));
    var mouseMove = element.ObserveMouseMove();

    var stop = Observable.Merge(
        element.ObserveMouseUp(),
        element.ObserveMouseLeave().Where(ep => ep.EventArgs.LeftButton == MouseButtonState.Pressed)
    );

    return mouseDown.SelectMany(
        md => mouseMove
                .Where(ep => ep.EventArgs.LeftButton == MouseButtonState.Pressed)
                .Where(ep => MinimumDragSeen(md, ep.EventArgs.GetPosition(element)))
                .TakeUntil(stop)
        );
    }

和处理最小阻力的距离,鼠标向上事件和各种必要的事情拖动到完全正常工作。最大化的bug已经消失,以及(虽然我还是不完全理解了他,我怀疑鼠标操作起来可能有一些用它做)。

And handles minimum drag distance, mouse up events and all kinds of things necessary for drag to work entirely properly. The maximize bug has gone away as well (although I still don't entirely understand that one, I suspect the mouse up handling might have something to do with it).

这里的关键是使用的SelectMany来处理来自mousemove事件时多个数据流,直到mouseUp事件的控制,或将鼠标指针鼠标按钮离开它。

The key thing here is using SelectMany to handle multiple streams of events from mouseMove until either mouseUp in the control, or the mouse pointer leaving it with the mouse button down.

推荐答案

听起来像它可能是一个错误,我不知道为什么鼠标,当你最大化窗口先机。

Sounds like it could be a bug in that I am not sure why a mouse move first when you maximise the window.

我会使用+的SelectMany代替takeuntil相结合最新的。 。即:

I would use selectMany + takeuntil instead of combine latest. ie:

var mouseDown = element.ObserveMouseLeftButtonDown().Select(ep => ep.EventArgs.GetPosition(element));
var mouseUp = element.ObserveMouseLeftButtonUp();
var mouseMove = element.ObserveMouseMove();
var from md in mouseDown  
    from mm in mouseMove.TakeUntil(mouseUp)
    where MinimumDragSeen(md, mm.EventArgs.GetPosition(element)))   
    select mm;

这当鼠标下跌,现在只揭开序幕的举动,并尽快杀死它鼠标了。我不认为你在你的代码中的MouseUp的功能。

This will now only kick off a move when the mouse is down, and kill it as soon as the mouse is up. I dont think you have the feature of MouseUp in your code.

我也会考虑尽量避免存储元素,并用它作为国家,因为我认为这是可通过事件参数。我也可以考虑使用鼠标移动邮编这样你就可以得到最后的鼠标移动变化的只是差异(如适用)。

I would also consider trying to avoid storing the element and using it as state as I think this is available via the event Args. I would also consider using Zip on the MouseMove so you can get just the delta of the last mouse move change (if appropriate).

我会很急切地希望听取你在做什么。我在Rx和工作的建筑我刚刚完成buidling一些WPF控件,使用拖放。

I would be really keen to hear about what you are doing. I am in the middle of writting a book on Rx and at work building I just finished buidling some WPF controls that use Drag Drop.

希望有所帮助。

这篇关于使用接收过上一个WPF用户控件的事件,为什么控制接收鼠标按下,当窗口最大化鼠标移动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆