2010-04-04 5 views
5

Estoy tratando de manejar un arrastre & soltar la interacción, que implica el mouse hacia abajo, el movimiento del mouse y el mouse hacia arriba.¿Cuál es la mejor manera de estructurar este código de arrastrar y soltar de Linq-to-Events?

Aquí es una repro simplificada de mi solución que:

  • el ratón hacia abajo, crea una elipse y lo añade a un lienzo
  • al mover el ratón, reposiciona la elipse para seguir al ratón
  • en el mouse hacia arriba, cambia el color del lienzo para que sea obvio cuál arrastras.

    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 gustan de este código, y necesito ayuda refactorización :)

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

En segundo lugar, la devolución de llamada del mouse se especifica antes de la devolución de llamada del mousemove. 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, esa referencia de variable se sobrescribirá rápidamente. Estoy seguro de que debería haber alguna forma de aprovechar la palabra clave let para introducir una variable a la expresión linq que significará que la referencia de elipse correcta está disponible para los manejadores de movimiento y ratón del mouse

¿Cómo escribirías? este código?

Respuesta

3

Para evitar los efectos secundarios de la subscrición, 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(); 
    } 
+0

Me gusta cómo se lee. Dónde (lo hizo)/(puedo) leer más acerca de 'Suscribirse' y' Conectar' –

+0

@ rob-fonseca-ensor Reactive Extensions Forum en MSDN http://social.msdn.microsoft.com/Forums/en-US/ rx/threads es el único lugar por ahora ... Necesitamos ver más preguntas sobre SO. –

Cuestiones relacionadas