Was ist der beste Weg, um diesen Linq-to-Event Drag & Drop-Code zu strukturieren?
-
24-09-2019 - |
Frage
Ich versuche, eine Drag & Drop-Interaktion zu handhaben, die Maus nach unten geht, Maus verschieben und Maus nach oben.
Hier ist eine Repro meiner Lösung vereinfacht, dass:
- auf der Maus nach unten, schafft eine Ellipse und fügt sie zu einer Leinwand
- auf Maus bewegen, positioniert die Ellipse mit der Maus folgen
-
auf Maus nach oben, ändert sich die Farbe der Leinwand, so dass es offensichtlich ist, welches Sie verschieben.
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); });
die XAML ist einfach
<Canvas x:Name="canvas"/>
Es gibt ein paar Dinge, die ich nicht mag diesen Code, und ich brauche Hilfe Refactoring es:)
Zu allererst: MouseDown- und mouseup Rückrufe werden als Nebenwirkungen angegeben. Wenn zwei Abonnements q
gemacht werden, werden sie zweimal passieren.
Zweitens wird der mouseup Rückruf angegeben vor den mousemove- Rückruf. Dies macht es ein bisschen schwer zu lesen.
Drittens wird der Verweis auf die Ellipse scheint in einem dummen Ort zu sein. Wenn es zwei Abonnements ist, wird diese variable Referenz recht schnell erhalten überschrieben. Ich bin sicher, dass es einen Weg geben wir die let
Schlüsselwort nutzen können, um eine Variable zu dem Linq Ausdruck einzuführen, die die richtige Ellipse Referenz bedeuten ist sowohl auf die Maus bewegen und die Maus nach oben Handler
Wie würden Sie diesen Code schreiben?
Lösung
Um zu vermeiden, subscrition Nebenwirkungen, sollten Sie Ihre beobachtbare veröffentlichen. Ich denke, so etwas wie dies wäre 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();
}