Pregunta

Estoy tratando de manejar una interacción de arrastrar y soltar, lo que implica abajo del ratón, mover el ratón y el ratón hacia arriba.

Aquí está una simplificado repro de mi solución que:

  • abajo del ratón, crea una elipse y lo añade a un lienzo
  • al mover el ratón, reposiciona la elipse para seguir al ratón
  • en ratón hacia arriba, cambia el color de la tela de manera que es obvio que uno que está arrastrando.

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

el XAML es simplemente

    <Canvas x:Name="canvas"/>

Hay algunas cosas que no me gusta de este código, y necesito ayuda refactorización:)

En primer lugar: la mousedown y devoluciones de llamada mouseup se especifican como efectos secundarios. Si dos suscripciones se hacen para q, pasarán dos veces.

En segundo lugar, se especifica la devolución de llamada mouseup antes mousemove la devolución de llamada. Esto hace que sea un poco difícil de leer.

En tercer lugar, la referencia a la elipse parece estar en un lugar tonto. Si hay dos suscripciones, que la referencia variable se sobrescribirá con bastante rapidez. Estoy seguro de que debe haber alguna manera podemos aprovechar la palabra clave let para introducir una variable a la expresión LINQ que significará la referencia correcta elipse está disponible tanto para el movimiento del ratón y ratón hacia arriba manipuladores

¿Cómo escribir el código?

¿Fue útil?

Solución

Para evitar subscripción efectos secundarios, debe publicar su observable. Creo que algo como esto estaría bien:

        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();
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top