これは私をちょっと困惑させてしまった。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またはマウスボタンを押したままにするマウスポインタです。
私のソリューションを助け
希望は少し異なることになったが、この回答は参考になりました。また、私は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.MinimumHorizontalDragDistance、SystemParameters.MinimumVerticalDragDistance); リターン!rc.Contains(now); – jdasilva