Quelle est la meilleure façon de structurer ce Linq-à-événements glisser et déposer le code?

StackOverflow https://stackoverflow.com/questions/2574046

Question

Je suis en train de gérer une interaction glisser-déposer, ce qui implique vers le bas la souris, déplacer la souris, et jusqu'à la souris.

Voici une repro simplifiée de ma solution:

  • sur la souris vers le bas, crée une ellipse et l'ajoute à une toile
  • sur le mouvement de la souris, repositionne l'ellipse pour suivre la souris
  • sur place de la souris, change la couleur de la toile de sorte qu'il est évident que l'on vous glisser.

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

le XAML est simplement

    <Canvas x:Name="canvas"/>

Il y a quelques choses que je n'aime pas ce code, et je besoin d'aide refactorisation il:)

D'abord: le callbacks mousedown et mouseUp sont spécifiés comme des effets secondaires. Si deux abonnements sont faits à q, ils se produiront deux fois.

En second lieu, le rappel mouseup est spécifié avant le rappel mousemove. Cela en fait un peu difficile à lire.

En troisième lieu, la référence à l'ellipse semble être dans un endroit stupide. S'il y a deux abonnements, cette référence variable assez rapidement être écrasé. Je suis sûr qu'il devrait y avoir une certaine façon nous pouvons tirer parti du mot-clé let d'introduire une variable à l'expression LINQ qui signifie la référence ellipse correcte est disponible à la fois le déplacement de la souris et les gestionnaires de la souris sont

Comment voulez-vous écrire ce code?

Était-ce utile?

La solution

Pour éviter les effets secondaires subscrition, vous devez publier votre observable. Je pense que quelque chose comme ça serait 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();
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top