Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在WPF用户控件上使用Rx over事件,当窗口最大化时,为什么控件会收到mousedown和mousemove?_C#_Wpf_System.reactive_Maximize - Fatal编程技术网

C# 在WPF用户控件上使用Rx over事件,当窗口最大化时,为什么控件会收到mousedown和mousemove?

C# 在WPF用户控件上使用Rx over事件,当窗口最大化时,为什么控件会收到mousedown和mousemove?,c#,wpf,system.reactive,maximize,C#,Wpf,System.reactive,Maximize,这个让我有点困惑 我已经在UIElement上编写了一些扩展方法,以提供一些鼠标事件的可观察性。以下是相关信息: public static IObservable<EventPattern<MouseEventArgs>> ObserveMouseLeftButtonDown(this UIElement element) { return Observable.FromEventPattern<MouseEventArgs>(element, "M

这个让我有点困惑

我已经在UIElement上编写了一些扩展方法,以提供一些鼠标事件的可观察性。以下是相关信息:

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");
}
然后是合成物本身:

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);
}
public static IObservable ObserveMouseDrag(此UIElement)
{
返回可观测的(
element.ObserveMouseLeftButtonDown().Select(ep=>ep.EventArgs.GetPosition(元素)),
元素。ObserveMouseMove()。其中(ep=>ep.EventArgs.LeftButton==MouseButtonState.Pressed),
(md,mm)=>new{Down=md,Move=mm})
.Where(i=>MinimumDragSeen(i.Down,i.Move.EventArgs.GetPosition(元素)))
.选择(i=>i.Move);
}
这一切都很好地工作,在经历了大量的磨牙和烦恼之后,没有任何基于Rx的WPF控件拖放的好例子(大多数都是在画布上拖动图像的简单复制品)

当窗口最大化时会出现问题,特别是双击标题栏。如果在最大化布局中,订阅了自己的ObserveMouseDrag()的控件中的一个在鼠标光标下结束,它将收到一个MouseLeftButtonDown和一个MouseMove,其中一个明显在最大化之前,另一个在最大化之后。最终的结果是,它启动了一个拖动事件,当鼠标按钮被释放时,该事件立即停止,然后趋向于使控件自身掉落,这在这个应用程序中的某些情况下实际上起到了作用

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

那么,有人有什么想法吗

第二天…

修好了!(以下是李的回答,还有这个问题:)

代码现在如下所示:

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)
        );
    }
public static IObservable ObserveMouseDrag(此UIElement)
{
var mouseDown=element.ObserveMouseLeftButtonDown().Select(ep=>ep.EventArgs.GetPosition(element));
var mouseMove=element.ObserveMouseMove();
var stop=可观察的。合并(
元素。ObserveMouseUp(),
元素。ObserveMouseLeave()。其中(ep=>ep.EventArgs.LeftButton==MouseButtonState.Pressed)
);
返回mouseDown.SelectMany(
md=>mouseMove
.Where(ep=>ep.EventArgs.LeftButton==MouseButtonState.Pressed)
.Where(ep=>MinimumDragSeen(md,ep.EventArgs.GetPosition(元素)))
.TakeUntil(停止)
);
}
并处理最小拖动距离、鼠标向上移动事件以及拖动完全正常工作所需的各种事情。最大化错误也消失了(虽然我仍然不完全理解这个错误,但我怀疑鼠标上的操作可能与此有关)


这里的关键是使用SelectMany来处理多个事件流,从mouseMove到控件中的mouseUp,或者鼠标指针在按下鼠标按钮时离开它。

听起来可能是一个错误,因为我不确定在最大化窗口时为什么要先移动鼠标

我会使用selectMany+takeuntil,而不是combine latest。即:

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的特性

我也会考虑避免存储元素并将其用作状态,因为我认为这可以通过事件ARG获得。我也会考虑在MuSeMeo上使用Zip,这样你就可以得到最后一个鼠标移动变化的增量(如果合适的话)。 我很想知道你在做什么。我正在写一本关于RX的书,在工作楼里,我刚刚完成了一些使用拖放的WPF控件。

希望有帮助


Lee

你说得对,我们没有控制鼠标,这确实导致了一个我们可以演示的错误。最好对此进行修复,问题是元素本身上的MouseLeftButtonUp不够,因为MouseLeftButtonUp可能在其他地方触发。最终,如果鼠标被释放到任何地方,甚至在应用程序之外,它都需要触发,以便正确重置拖动。您的代码有一个有趣的错误,在第二次拖动操作中,where子句似乎总是正确的,在可观察到的触发之前,没有观察到的最小拖动距离,然而这是第一次。我怀疑它实际上并没有完全重置,仍然使用它看到的第一个鼠标向下移动。至于我们正在做的事情——在一个网格状的布局中拖放条目,代表一个时间表。我接受这个答案,因为它让我朝着正确的方向前进,尽管这并不完全是我所需要的。非常感谢!我也很想听听你关于Rx的书,尤其是如果你要谈论比无处不在的“拖动图像”例子更复杂的事情。自从我使用DoDragDrop后,我的解决方案有点不同,但这个答案很有帮助。此外,我还做了一些关于MinimumDragSeen方法的家庭作业,显然它并不是那么简单。底层windowsapi调用的规范说,这些数字可以是负数。我最终发现了这一点,我认为这是非常确定的。我的C版本:var rc=new Rect(开始,开始);充气(系统参数.最小水平阻力距离,系统参数.最小垂直阻力距离);回来!rc.Contains(现在);
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;