この Linq-to-Events ドラッグ アンド ドロップ コードを構造化する最良の方法は何でしょうか?
-
24-09-2019 - |
質問
マウスダウン、マウス移動、マウスアップを含むドラッグアンドドロップインタラクションを処理しようとしています。
私のソリューションを簡略化して再現したものは次のとおりです。
- マウスを押すと楕円が作成され、キャンバスに追加されます
- マウスを移動すると、マウスに追従するように楕円の位置が変更されます。
マウスを上に置くと、キャンバスの色が変わるので、どれをドラッグしているのかが一目瞭然です。
var mouseDown = Observable.FromEvent<MouseButtonEventArgs>(canvas, "MouseLeftButtonDown"); var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(canvas, "MouseLeftButtonUp"); var mouseMove = Observable.FromEvent<MouseEventArgs>(canvas, "MouseMove"); Ellipse ellipse = null; var q = from start in mouseDown.Do(x => { // handle mousedown by creating a red ellipse, // adding it to the canvas at the right position ellipse = new Ellipse() { Width = 10, Height = 10, Fill = Brushes.Red }; Point position = x.EventArgs.GetPosition(canvas); Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); canvas.Children.Add(ellipse); }) from delta in mouseMove.Until(mouseUp.Do(x => { // handle mouse up by making the ellipse green ellipse.Fill = Brushes.Green; })) select delta; q.Subscribe(x => { // handle mouse move by repositioning ellipse Point position = x.EventArgs.GetPosition(canvas); Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); });
XAML は単純に
<Canvas x:Name="canvas"/>
このコードには気に入らない点がいくつかあるので、リファクタリングするのに助けが必要です:)
初めに:マウスダウンおよびマウスアップのコールバックは副作用として指定されます。2 つのサブスクリプションが行われた場合 q
, 、それらは2回起こります。
次に、mouseup コールバックが指定されています 前に マウス移動コールバック。これにより、少し読みにくくなります。
第三に、楕円への参照がばかげた場所にあるようです。サブスクリプションが 2 つある場合、その変数参照はすぐに上書きされます。を活用できる何らかの方法があるはずだと確信しています。 let
linq 式に変数を導入するためのキーワード。これは、マウス移動ハンドラーとマウス アップ ハンドラーの両方で正しい楕円参照が利用できることを意味します。
このコードはどのように書きますか?
解決
回避subscritionの副作用には、あなたの、観察を公開すべきです。私はこのようなものがOKだと思います:
public MainWindow()
{
InitializeComponent();
var mouseDown = Observable
.FromEvent<MouseButtonEventArgs>(this, "MouseLeftButtonDown");
var mouseUp = Observable
.FromEvent<MouseButtonEventArgs>(this, "MouseLeftButtonUp");
var mouseMove = Observable
.FromEvent<MouseEventArgs>(this, "MouseMove");
var ellipses = mouseDown
.Select(args => new {
a = args,
el = new Ellipse
{
Width = 10, Height = 10, Fill = Brushes.Red
}})
.Publish();
ellipses
.Subscribe(elargs =>
{
var position = elargs.a.EventArgs.GetPosition(canvas);
Canvas.SetLeft(elargs.el, position.X);
Canvas.SetTop(elargs.el, position.Y);
canvas.Children.Add(elargs.el);
});
var elmove = from elargs in ellipses
from mm in mouseMove.TakeUntil(mouseUp)
select new { a = mm, el = elargs.el };
elmove.
Subscribe(elargs =>
{
var position = elargs.a.EventArgs.GetPosition(canvas);
Canvas.SetLeft(elargs.el, position.X);
Canvas.SetTop(elargs.el, position.Y);
});
var elmup = from elargs in ellipses
from mup in mouseUp
select elargs.el;
elmup.Subscribe(el => el.Fill = Brushes.Green);
ellipses.Connect();
}
所属していません StackOverflow