构建此 Linq-to-Events 拖放代码的最佳方式是啥?

Posted

技术标签:

【中文标题】构建此 Linq-to-Events 拖放代码的最佳方式是啥?【英文标题】:What's the best way to structure this Linq-to-Events Drag & Drop code?构建此 Linq-to-Events 拖放代码的最佳方式是什么? 【发布时间】:2011-02-04 04:00:42 【问题描述】:

我正在尝试处理拖放交互,其中涉及鼠标向下、鼠标移动和鼠标向上。

这是我的解决方案的简化重现:

鼠标按下时,创建一个椭圆并将其添加到画布中 鼠标移动时,重新定位椭圆以跟随鼠标

鼠标抬起时,更改画布的颜色,以便您拖动哪个画布一目了然。

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 回调在 mousemove 回调之前指定。这使得它有点难以阅读。

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

你会如何编写这段代码?

【问题讨论】:

【参考方案1】:

为避免订阅副作用,您应该发布您的 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();
    

【讨论】:

我喜欢它的阅读方式。在哪里(你)/(我可以)阅读更多关于SubscribeConnect @rob-fonseca-ensor Reactive Extensions Forum on MSDN social.msdn.microsoft.com/Forums/en-US/rx/threads 是目前唯一的地方......我们需要查看更多关于 SO 的问题。

以上是关于构建此 Linq-to-Events 拖放代码的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

通过拖放项目制作类似列表的小部件的最简单方法是啥?

Spotify 清除播放列表拖放

使用 Dragula 在应用程序中拖放 WebDriver

如何使用以下代码在输入表单中自动选择当前日期

如何使用以下代码在输入表单中自动选择当前日期

iPhone拖放