Search code examples
c#wpfuser-interfaceonmousemove

Performance issue of DrawingVisual following cursor while using onMouseMove event


I'm busy with a small application in which I want to display information at the location of the cursor when it hoovers over a Canvas. The Canvas in question is a custom one (inherited from Canvas) which provides functionality to add DrawingVisuals (as shown in basically every tutorial on displaying large amounts of geometric shapes on a canvas).

I would like to display a vertical line and horizontal line as well as the local coordinates (p in the code below) which are directly derived from the canvas coordinates (v). At the moment I'm rendering these objects at position (0,0) and use offset during the OnMouseMove event to update their location.

The horizontal and vertical lines are rendered in the DrawingVisual _cursor and the location in local y,z-coordinates in _info.

private void oCanvas_MouseMove(object sender, MouseEventArgs e)
    {
        #region 1. Get location data

        System.Windows.Vector v = (System.Windows.Vector)e.GetPosition(oCanvas);
        // point in YZ coordinates
        BSMath.DoubleXY p = new BSMath.DoubleXY();
        p.X = (oCanvas.OriginY - v.Y) / oCanvas.ZoomFactor;
        p.Y = (oCanvas.OriginX - v.X) / oCanvas.ZoomFactor;

        #endregion

        #region 2. Update cursor and info

        if (oSettings.ShowInformation)
        {
            _info.Info = p.X.ToString("0.0") + "  |  " + p.Y.ToString("0.0");
            _info.Render(0, 0);
            _info.Visual.Offset = v;
        }            

        // move cursor
        _cursor.Visual.Offset = v;
    }

Using the mousemove event seems to be creating a lot of overhead and I can see that there are issues tracking the mouse movements when I move the mouse quickly.

Can anyone recommend a better way of creating the same effect?

example http://www.iccg.be/test/images/canvas.jpg

Edit: I investigated it a bit further and the problem seems to occur when the resolution of the canvas is bigger. If it is a 600x400 canvas then there is no delay, but when it is around 1000x800 I get the problem with delays when hoovering. The performance also improves if I use user drawn crosshairs instead of the lines that have the full width/ height of the canvas.


Solution

  • I recently have built something similar and haven't had any performance issues. Did it the very simple way by adding the stuff directly on the canvas. The drawn items are in a second canvas behind the mouse position canvas. Both reside in a Grid. This is for sure not the most sophisticated way to solve this, but it works quite well for me.

    Here's the code:

    private Point _previous;
    private Point _current;
    
    private Line _xLine;
    private Line _yLine;
    private TextBlock _displayTextBlock;
    
    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
      _current = e.GetPosition(myCanvas);
    
      if (_previous != _current)
      {
        if (_xLine == null)
        {
          _xLine = new Line() {X1 = 0, X2 = myCanvas.ActualWidth, Stroke = new SolidColorBrush(Colors.Black)};
          _yLine = new Line() {Y1 = 0, Y2 = myCanvas.ActualHeight, Stroke = new SolidColorBrush(Colors.Black)};
          _displayTextBlock = new TextBlock();
    
          myCanvas.Children.Add(_xLine);
          myCanvas.Children.Add(_yLine);
          myCanvas.Children.Add(_displayTextBlock);
        }
    
        _displayTextBlock.SetValue(Canvas.TopProperty, _current.Y);
        _displayTextBlock.SetValue(Canvas.LeftProperty, _current.X);
        _displayTextBlock.Text = _current.X.ToString() + " | " + _current.Y.ToString();
        _xLine.Y1 = _current.Y;
        _xLine.Y2 = _current.Y;
        _yLine.X1 = _current.X;
        _yLine.X2 = _current.X;
    
        _previous = _current;
      }
    }