2012-02-13 5 views
2

これは私をちょっと困惑させてしまった。WPF UserControlでRxオーバーイベントを使用すると、ウィンドウが最大化されたときにコントロールがmousedownとmousemoveを受け取るのはなぜですか?

いくつかのマウスイベントでObservablesを提供するために、いくつかの拡張メソッドを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"); 
} 

これまでのところ、覚えやすいほど単純です。次に、ユーザーがUIElementでドラッグを開始したときを検出するコンポジットイベントを作成します(これはすべてカスタムコントロールによって使用されますが、その正確な性質は特に関係ありません)。

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); 
} 

これはすべての歯と苛立ちのあまり歯ぎしりした後、うまく動作まずここで少しヘルパー関数は、ユーザーの最小ドラッグ距離をドラッグしたかどうかを確認しますRxベースのドラッグ&ドロップでWPFコントロールを使っている例はほとんどありません(そのほとんどはキャンバス内でイメージをドラッグする単純な複製です)。

問題は、ウィンドウが最大化された場合、特にタイトルバーをダブルクリックすると発生します。最大化されたレイアウトで、自分自身のObserveMouseDrag()に登録されているコントロールの1つがマウスカーソルの下にくると、MouseLeftButtonDownとMouseMoveを受け取ります。そのうち1つは明らかに最大化の前に、もう1つはその後に受け取ります。最終的にはドラッグイベントが開始され、マウスボタンが離されるとすぐに停止し、コントロールが実際に何かを行う場合があります。

これは、私がMouseDownとMouseMoveをダブルクリックの最大化によって受信する必要がある理由がわからないため、非常に奇妙です。確かに、それに関わるすべてのマウスイベントは、Windowsで処理する必要があります。なぜなら、私はカスタムウィンドウの枠線などを使用していないからです。

だから誰にもアイデアはありますか?

次の日...それを修正

! (以下リーの回答からいくつかの助け、そしてこの質問で:What is the proper way to determine the end of a mouse drag using Rx?

コードは次のようになります。

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) 
     ); 
    } 

と最小ドラッグ距離、マウスアップイベントとドラッグのために必要なあらゆる種類のものを扱います完全に正しく働く最大限のバグも消えてしまっています(私はまだ完全にそのことを理解していませんが、マウスの操作がそれと関係している可能性があります)。

ここで重要なのは、SelectManyを使用して、mouseMoveからイベントの複数のストリームを処理することです。コントロールのmouseUpまたはマウスボタンを押したままにするマウスポインタです。

+0

私のソリューションを助け

希望は少し異なることになったが、この回答は参考になりました。また、私はMinimumDragSeenのアプローチで少し宿題をしました。明らかにそれほど単純ではありません。基礎となるWindows API呼び出しの仕様によれば、これらの数値は負の値になる可能性があります。私は最終的に、私がかなり決定的だと思うhttp://blogs.msdn.com/b/oldnewthing/archive/2010/03/04/9972520.aspxを見つけました。私のC#バージョン: var rc = new Rect(start、start); rc.Inflate(SystemParameters.MinimumHorizo​​ntalDragDistance、SystemParameters.MinimumVerticalDragDistance); リターン!rc.Contains(now); – jdasilva

答えて

2

ウィンドウを最大化するとマウスが最初に動く理由がわかりません。

最新の組み合わせではなく、selectMany + takeuntilを使用します。すなわち:

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の機能を持っているとは思わない。

また、私はこれがイベントArgsを介して利用可能だと思うように、要素を格納してそれを状態として使用することを避けようと考えます。私はまた、MouseMoveでZipを使うことも考えています。そのため、最後のマウス移動の変更のデルタを得ることができます(適切な場合)。

私は本当にあなたが何をしているか知りたいです。私はRxの本を書いている最中で、仕事場ではドラッグドロップを使用するWPFコントロールを作成しました。私はDoDragDrop関数を使用していたので、

リー

+0

あなたはマウスが上手くいかないことは間違いありません。それは私たちが実証できるバグにつながります。 MouseLeftButtonUpが他の場所で発生する可能性があるため、要素自体のMouseLeftButtonUpが不十分であるという問題がありました。ドラッグが適切にリセットされるようにするには、マウスがどこにでもリリースされた場合(アプリケーションの外でも)、最終的には起動する必要があります。 –

+0

あなたのコードには興味深いバグがあります。これは、2回目のドラッグ操作では、where句が常に真であると見えますが、観察可能な発火の前に観測される最小のドラッグ距離はありません。私はそれが実際に完全にリセットされていないと思って、それが見た最初のmouseDownをまだ使用しています。私たちがやっていることは、スケジュールを表す格子状のレイアウトでエントリの並べ替えをドラッグアンドドロップします。 –

+0

私はそれが私が必要とするものではないにもかかわらず、正しい方向に私を送ったので、これを答えとして受け入れています。どうもありがとう!私はまた、Rxについてのあなたの本を聞くことに興味があります。特に、どこにでもイメージをドラッグするよりも複雑なことについて話したいと思うなら、 –

関連する問題