2014-11-13 56 views
0

我有一個Windows窗體應用程序,我使用Rx查詢MouseMove事件流並根據鼠標的位置(當前和以前)生成結果。我的代碼如下所示: (該label1的顯示結果和label2顯示「登錄」當前和以前的位置。)比較MouseMove事件流,鼠標位置不會減少

 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)從不顯示「-1」值。

我以比較以前和當前值使用Zip功能嘗試,但結果是一樣的:

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

那麼,爲什麼會出現呢?以及如何解決它?

+0

如果他們是相同的值,那麼你總是會得到-1。 ('currPosition.X> prevPosition.X'將總是返回'false')。所以我懷疑你的代碼還有其他問題。這是完整的樣本嗎? –

+0

請注意,它似乎不是您的Rx查詢的問題。 –

+0

你的'Zip'例子不會工作,除非你也使用'Publish',但是'Scan'很好。 ('掃描'是我最喜歡的配對方式。) –

回答

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選擇運營商爲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 => a.CurrentPoint),您可以獲得更多您正在尋找的內容。我說最多的是因爲移動鼠標對角線的事件在我的電腦上永遠不會有X和Y的不同。你可能能夠玩Throttle - 類似.Throttle(TimeSpan.FromMilliseconds(25),CurrentThreadScheduler.Instance)在Select之後和WithPrevious之前。這有助於我的電腦,但並不完美。

+0

:o你是這篇文章的評論的作者... 感謝您的幫助! – Nicolocodev

+0

使用DistinctUntilChanged在我的機器上工作良好,但使用Throttle(我已經嘗試過)具有不同的結果...我將應用更改並使用代碼進行遊戲,如果我需要任何建議...我會評論:P。再次感謝。 – Nicolocodev