比较MouseMove事件流,鼠标位置不会减少

时间:2014-11-13 22:35:40

标签: c# winforms system.reactive

我有一个Windows窗体应用程序,我使用Rx查询MouseMove事件流并根据鼠标的位置(当前和上一个)生成结果。我的代码看起来像: (label1显示结果,label2显示" log"以及当前和以前的位置。)

        var observable = Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove");
        observable                
            .PairWithPrevious()
            .Select(tuple =>
                    {
                        if (tuple.Item2 == null || tuple.Item1 == null) return Tuple.Create(0, 0);
                        var currPosition = tuple.Item2.EventArgs.Location;
                        var prevPosition = tuple.Item1.EventArgs.Location;
                        var x = 0;
                        if (currPosition.X > prevPosition.X) x = 1;
                        else if (currPosition.X < prevPosition.X) x = -1;
                        var y = 0;
                        if (currPosition.Y > prevPosition.Y) y = 1;
                        else if (currPosition.Y < prevPosition.Y) y = -1;
                        label2.Text = string.Format("Curr X: {0} * Y: {1} |||| Prev X: {2} * Prev Y: {3}", currPosition.X, currPosition.Y, prevPosition.X, prevPosition.Y);
                        return Tuple.Create(x, y);
                    })
            .Subscribe(x =>
                       {
                           label1.Text = string.Format("X: {0} ** Y: {1}", x.Item1, x.Item2);
                       });

PairWithPrevious函数:

    public static IObservable<Tuple<TSource, TSource>> PairWithPrevious<TSource>(this IObservable<TSource> source)
    {
        return source.Scan(
            Tuple.Create(default(TSource), default(TSource)),
            (acc, current) => Tuple.Create(acc.Item2, current));
    }

问题是:当你向左或向上移动鼠标时,前一个和当前(x,y)是相同的值,结果(label1)从不显示&#34; -1&#34;值。

我尝试使用Zip功能来比较之前和当前的值,但结果是一样的:

      Zip(observable.Skip(1), Tuple.Create)

那么,为什么会这样呢?以及如何解决它?

1 个答案:

答案 0 :(得分:0)

如果您观察MouseMove事件触发的频率,您将看到导致此问题的原因。我已更新您的代码以包含计数。我还添加了一个包含三列的简单列表视图,并将Listview的视图设置为详细信息,以便它非常明显。

我的一些代码与您的代码不同。它主要是一种风格问题。但我改变了PairWithPrevious只是WithPrevious并隐藏了元组

//http://www.zerobugbuild.com/?p=213 with a tweak to hide the Tuple
public static IObservable<TResult> WithPrevious<TSource, TResult>(this IObservable<TSource> source, Func<TSource, TSource, TResult> projection)
{
    return source.Scan(Tuple.Create(default(TSource), default(TSource)),
                       (previous, current) => Tuple.Create(previous.Item2, current))
                 .Select(t => projection(t.Item1, t.Item2));
}

RX Select运算符的int重载只是一个计数器。我将使用它来添加到一个匿名对象链接下来。 WithPrevious现在只是投射到另一个包含我们想要的数据的匿名对象。然后在订阅中,我们将更新两个标签和新的列表视图。

var observable = Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
                                   .Select((eventPattern, count) => new {eventPattern.EventArgs, Count = count})
                                   .WithPrevious((previous, current) =>
                                       {
                                           var currentPoint = current == null
                                                                  ? new Point(0, 0)
                                                                  : current.EventArgs.Location;
                                           var previousPoint = previous == null
                                                                   ? new Point(0, 0)
                                                                   : previous.EventArgs.Location;

                                           return
                                               new
                                                   {
                                                       CurrentPoint = currentPoint,
                                                       PreviousPoint = previousPoint,
                                                       Count = current == null ? 0 : current.Count
                                                   };
                                       })
                                   .Subscribe(a =>
                                       {
                                           label2.Text =
                                               String.Format(
                                                   "Curr X: {0} * Y: {1} |||| Prev X: {2} * Prev Y: {3} - Count = {4}",
                                                   a.CurrentPoint.X, a.CurrentPoint.Y,
                                                   a.PreviousPoint.X, a.PreviousPoint.Y,
                                                   a.Count);


                                           label1.Text = String.Format("X: {0} ** Y: {1}",
                                                                       a.CurrentPoint.X.CompareTo(
                                                                           a.PreviousPoint.X),
                                                                       a.CurrentPoint.Y.CompareTo(
                                                                           a.PreviousPoint.Y));
                                           var listItem = new ListViewItem(a.Count.ToString());
                                           listItem.SubItems.Add(a.CurrentPoint.X.ToString());
                                           listItem.SubItems.Add(a.CurrentPoint.Y.ToString());
                                           listView1.Items.Add(listItem);
                                           listView1.EnsureVisible(listView1.Items.Count - 1);
                                       });

你现在可以看到你是慢速向下移动鼠标还是向右移动事件只发射一次,但是在我的电脑上,如果你向上或向左移动鼠标,我可以得到的最少数量的事件是最后一个始终与前一个相同。这就是为什么它总是零,零。

现在,如果我们在WithPrevious之后和订阅之前添加.DistinctUntilChanged(a =&gt; a.CurrentPoint),您可以获得更多您想要的内容。我说的最多,因为移动鼠标对角线我的电脑上的事件不会让X和Y都不同。您可能可以使用Throttle - 类似.Throttle(TimeSpan.FromMilliseconds(25),CurrentThreadScheduler.Instance)之后选择和之前WithPrevious。这对我的电脑有所帮助,但并不完美。