代码之家  ›  专栏  ›  技术社区  ›  Rob Fonseca-Ensor

构造这个linqto事件拖放代码的最佳方法是什么?

  •  5
  • Rob Fonseca-Ensor  · 技术社区  · 14 年前

    我正在试着处理一个拖拉&拖放交互,包括鼠标下、鼠标移动和鼠标上。

    以下是我的解决方案的简化版本:

    • 按下鼠标,创建椭圆并将其添加到画布
    • 在鼠标移动时,重新定位椭圆以跟随鼠标
    • 鼠标向上移动时,更改画布的颜色,以便可以清楚地看到您正在拖动的画布。

      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 ,它们将发生两次。

    其次,指定mouseup回调 之前 鼠标移动回调。这使它有点难以阅读。

    第三,对椭圆的引用似乎是在一个愚蠢的地方。如果有两个订阅,那么该变量引用将很快被覆盖。我相信我们应该有办法利用 let 关键字将变量引入linq表达式,这意味着鼠标移动和鼠标向上处理程序都可以使用正确的椭圆引用

    1 回复  |  直到 14 年前
        1
  •  3
  •   Sergey Aldoukhov    14 年前

    为了避免订阅的副作用,您应该发布您的observate。我想这样的事情可以:

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