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?

War es hilfreich?

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();
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top