2010-04-04 17 views
5

Sto tentando di gestire un'interazione di rilascio con trascinamento &, che implica il mouse verso il basso, il movimento del mouse e il mouse su.Qual è il modo migliore per strutturare questo codice Drag & Drop da Linq ad eventi?

Ecco una Repro semplificata della mia soluzione che:

  • il mouse verso il basso, crea un'ellisse e lo aggiunge a una tela
  • il movimento del mouse, riposiziona l'ellisse di seguire il mouse
  • al mouse su, cambia il colore della tela in modo che sia ovvio quale si sta trascinando.

    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 è semplicemente

<Canvas x:Name="canvas"/> 

Ci sono alcune cose che non mi piace di questo codice, e ho bisogno di aiuto refactoring it :)

Prima di tutto: i callback mouse e mouseup sono specificati come effetti collaterali. Se vengono effettuati due abbonamenti a q, si verificheranno due volte.

In secondo luogo, il callback del mouseup è specificato prima del il callback mousemove. Questo lo rende un po 'difficile da leggere.

In terzo luogo, il riferimento all'ellisse sembra essere in un posto stupido. Se ci sono due abbonamenti, quel riferimento di variabile verrà sovrascritto abbastanza rapidamente. Sono certo che ci dovrebbe essere un modo in cui possiamo sfruttare la parola chiave let per introdurre una variabile nell'espressione linq che significherà che il riferimento ellittico corretto è disponibile sia per il mouse sia per i gestori di mouse.

Come scriveresti? questo codice?

risposta

3

Per evitare effetti collaterali di subscrizione, è necessario pubblicare l'osservabile. Penso che qualcosa del genere sarebbe 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(); 
    } 
+0

Mi piace il modo in cui legge. Dove (hai)/(posso) leggere di più su 'Subscribe' e' Connect' –

+0

@ rob-fonseca-ensor Reactive Extensions Forum su MSDN http://social.msdn.microsoft.com/Forums/en-US/ rx/threads è l'unico posto per ora ... Abbiamo bisogno di vedere più domande su SO. –

Problemi correlati