2010-12-03 6 views
2

Reactive Extensions for .NETをWPFで使用する方法をゆっくりと学習しています。ドラッグドロップや描画ルーチンを書くのがいかにシンプルであるかについてのいくつかの初心者の例がありますが、それらはすべて非常に簡単です。私はさらに一歩進んでいくつもりで、「適切な」方法が何であるかはわかりません。Rxを使用してマウスドラッグの終了を判断する適切な方法は何ですか?

例のすべては、あなたがMouseDownMouseMove、およびMouseUp

var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(..., "MouseDown") 
       select evt.EventArgs.GetPosition(...); 

var mouseMoves = from evt in Observable.FromEvent<MouseEventArgs>(..., "MouseMove") 
       select evt.EventArgs.GetPosition(...); 

var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(..., "MouseUp"); 

からイベントのストリームを定義することができる方法を示しています。そして、あなたが簡単にMouseDrag中に物事を行うことができますどのように(これは長方形の座標を表示します

var mouseDrag = from start in mouseDown 
       from currentPosition in mouseMoves.TakeUntil(mouseUp) 
       select new Rect(Math.Min(start.X, currentPosition.X), 
           Math.Min(start.Y, currentPosition.Y), 
           Math.Abs(start.X - currentPosition.X), 
           Math.Abs(start.Y - currentPosition.Y)); 

mouseDrag.Subscribe(x => 
      { 
       Info.Text = x.ToString(); 
      }); 

)現在のマウスの位置に開始ドラッグポイントから作成された私の質問は、マウスドラッグの最後にタスクを達成するために「適切」な方法は何か、ですか?しかし、より多くのデータが(今まで)とするとき、オブジェクトが配置されないことができるがある場合にonCompletedが呼ばれているようです、ドキュメントのより多くを読む

mouseDrag.Subscribe(
    onNext: x => 
      { 
       Info.Text = x.ToString(); 
      }, 
    onCompleted:() => 
       { 
       // Do stuff here...except it never gets called 
       }); 

:もともと、私はこのような何かを行うことができると思いました。

最初のオプションは、mouseUpイベントに登録して何かをしている可能性が高いと思われます。

mouseUp.Subscribe(x => 
      { 
       // Do stuff here.. 
      } 

しかし、その後、この時点で、私もちょうど「ノーマル」MouseLeftButtonUpイベントハンドラを使用するように戻ってあります。

mouseDragが完了したとき(またはTakeUntil(mouseUp)が発生したとき)に何らかのアクションを実行すると、別の方法で判断することはできますか?

答えて

5

ソース(MouseDown)が完了しない(イベント)ため、シーケンスは完了しません。 IObservableは、契約者の一部(OnNext* (OnCompleted|OnError)?)のサブスクライバのOnCompleteを複数回呼び出すことはできません。 mouseMove.TakeUntil(mouseUp)シーケンスが完了したとき、あなたはSelectManyへのコールにフックする必要があります見つけるために

public static IDisposable TrackDrag(this UIElement element, 
    Action<Rect> dragging, Action dragComplete) 
{ 
    var mouseDown = Observable.FromEvent(...); 
    var mouseMove = Observable.FromEvent(...); 
    var mouseUp = Observable.FromEvent(...); 

    return (from start in mouseDown 
      from currentPosition in mouseMove.TakeUntil(mouseUp) 
        .Do(_ => {},() => dragComplete()) 
      select new Rect(Math.Min(start.X, currentPosition.X), 
          Math.Min(start.Y, currentPosition.Y), 
          Math.Abs(start.X - currentPosition.X), 
          Math.Abs(start.Y - currentPosition.Y)); 
      ).Subscribe(dragging); 
} 

次にあなたがそうのようにそれを使用することができます興味のために

element.TrackDrag(
    rect => { }, 
    () => {} 
); 

明示的には、基礎となる拡張メソッドを使用したLINQの式を以下に示します。

return mouseDown.SelectMany(start => 
{ 
    return mouseMove 
     .TakeUntil(mouseUp) 
     .Do(_ => {},() => dragComplete()) 
     .Select(currentPosition => new Rect(...)); 
}) 
.Subscribe(dragging); 

つまり、mouseDownの各値に対して新しいシーケンスがサブスクライブされます。 シーケンスが完了したら、dragComplete()を呼び出します。

+0

はい - 私の最初の試みは、OnCompletedの道を進むべき道ではないことを動作しませんでした後に私は気づきました。 Do()を含むもっと完全な説明をありがとう: – Jedidja

関連する問題