2010-04-04 79 views
5

我正在嘗試處理拖放交互,其中包括鼠標放下,鼠標移動和鼠標移動。構建這個Linq-to-Events拖放代碼的最佳方式是什麼?

這裏是我的解決方案的簡化的攝製是:

  • 上按下鼠標,創建一個橢圓並將其添加到畫布
  • 上移動鼠標,重新定位橢圓跟隨鼠標
  • 在鼠標上,改變畫布的顏色,以便顯而易見你拖動的是哪一個。

    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僅僅是

<Canvas x:Name="canvas"/> 

有幾件事情,我不喜歡這個代碼,我需要幫助重構吧:)

首先: mousedown和mouseup回調被指定爲副作用。如果兩個訂閱都是q,它們會發生兩次。

二,鼠標移動回調在之前指定。這使得閱讀有點困難。

第三,對橢圓的引用似乎是在一個愚蠢的地方。如果有兩個訂閱,那麼該變量引用將很快被覆蓋。我相信應該有一些方法可以利用關鍵字let向linq表達式引入變量,這意味着鼠標移動和鼠標移動處理程序都可以使用正確的橢圓參考。

您會如何編寫這個代碼?

回答

3

爲避免發生副作用副作用,您應該發佈您的observable。我認爲這樣的事情會好的:

 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

我喜歡它的讀法。您在哪裏(您)/(我能)詳細瞭解'Subscribe'和'Connect' – 2010-04-05 19:04:09

+0

@ rob-fonseca-ensor MSDN上的無功擴展論壇http://social.msdn.microsoft.com/Forums/en-US/ rx/threads是目前唯一的地方...我們需要在SO上看到更多的問題。 – 2010-04-05 19:19:37

相關問題