Home > Software engineering >  WPF Mousemove is a noticeable lag
WPF Mousemove is a noticeable lag

Time:01-29

I am making a UserControl called VolumeScrollBar to control the volume a video player I am working on. Now the problem I am having is when I slide my SwitchPath it moves noticeable slower than my mouse. How can I fix this ?

note: everything is working but the speed.

Also, I am not using the built in sliding bar because I do not like how it looks. So I designed my own Volume scroll bar in Adobe Illustrator.

here is my XAML code:

<Canvas x:Name="VolumeScrollBarCanvas"  Height="21" Width="160" >
    <Path x:Name="Path_7" Width="15" Height="13" Canvas.Left="0.777" Canvas.Top="3.556" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 67.6183,648C 67.5503,648 67.4809,648.019 67.4156,648.061L 62.6556,651.173L 61.3916,652L 55.9996,652C 54.5276,652 53.3329,653.193 53.3329,654.667C 53.3329,656.14 54.5276,657.333 55.9996,657.333L 61.3916,657.333L 62.6556,658.16L 67.4156,661.272C 67.4809,661.315 67.5503,661.333 67.6183,661.333C 67.8169,661.333 67.9996,661.169 67.9996,660.937L 67.9996,654.667L 67.9996,648.395C 67.9996,648.164 67.8169,648 67.6183,648 Z M 66.6663,650.144L 66.6663,654.667L 66.6663,659.189L 63.3863,657.044L 62.1209,656.217L 61.7889,656L 61.3916,656L 55.9996,656C 55.2649,656 54.6663,655.401 54.6663,654.667C 54.6663,653.932 55.2649,653.333 55.9996,653.333L 61.3916,653.333L 61.7889,653.333L 62.1209,653.116L 63.3849,652.289L 66.6663,650.144 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="WhiteBarPath" Width="81" Height="7" Canvas.Left="46.111" Canvas.Top="6.223" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 176.667,657.333L 102,657.333C 100.167,657.333 98.6667,655.833 98.6667,654L 98.6667,654C 98.6667,652.167 100.167,650.667 102,650.667L 176.667,650.667C 178.5,650.667 180,652.167 180,654L 180,654C 180,655.833 178.5,657.333 176.667,657.333 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="Path_8" Width="13" Height="20" Canvas.Left="24.151" Canvas.Top="0.639" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 78.6667,645.333C 77.9893,645.333 77.3347,645.451 76.7067,645.648C 81.5307,646.025 85.3333,650.212 85.3333,655.333C 85.3333,660.455 81.5293,664.641 76.7067,665.019C 77.3347,665.216 77.9893,665.333 78.6667,665.333C 83.0853,665.333 89.3333,660.856 89.3333,655.333C 89.3333,649.811 83.0853,645.333 78.6667,645.333 Z " HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <Path x:Name="Path_9" Width="9.26" Height="15" Canvas.Left="19.168" Canvas.Top="3.556" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 73.1609,648C 72.6636,648 72.1849,648.085 71.7236,648.231C 75.2609,648.508 78.0503,651.579 78.0503,655.333C 78.0503,659.088 75.2609,662.159 71.7236,662.436C 72.1849,662.581 72.6636,662.667 73.1609,662.667C 76.4009,662.667 80.9836,659.384 80.9836,655.333C 80.9836,651.283 76.4009,648 73.1609,648 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="Path_10" Width="4" Height="5" Canvas.Left="18.11" Canvas.Top="8.266" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 72.4039,652.71C 72.2399,652.71 70.9452,652.756 70.6665,652.81L 70.6665,657.311C 71.0052,657.364 72.3412,657.306 72.4039,657.306C 73.6732,657.306 74.7012,656.276 74.7012,655.007C 74.7012,653.739 73.6732,652.71 72.4039,652.71 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="ColorBarPath" Width="81" Height="7" Canvas.Left="46.111" Canvas.Top="6.223" Stretch="Fill" Fill="#FF6557FF" Data="F1 M 176.667,657.333L 102,657.333C 100.167,657.333 98.6667,655.833 98.6667,654L 98.6667,654C 98.6667,652.167 100.167,650.667 102,650.667L 176.667,650.667C 178.5,650.667 180,652.167 180,654L 180,654C 180,655.833 178.5,657.333 176.667,657.333 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Ellipse x:Name="SwitchPath"    MouseDown="SwitchPath_MouseDown"  MouseMove="SwitchPath_MouseMove"  Mouse.MouseUp="SwitchPath_MouseUp"  Width="19" Height="19" Canvas.Left="115.444" Canvas.Top="0.889" Stretch="Fill" Fill="#FFFFFFFF" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="Path_7_Copy" Width="15" Height="13" Canvas.Left="0.777" Canvas.Top="3.556" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 67.6183,648C 67.5503,648 67.4809,648.019 67.4156,648.061L 62.6556,651.173L 61.3916,652L 55.9996,652C 54.5276,652 53.3329,653.193 53.3329,654.667C 53.3329,656.14 54.5276,657.333 55.9996,657.333L 61.3916,657.333L 62.6556,658.16L 67.4156,661.272C 67.4809,661.315 67.5503,661.333 67.6183,661.333C 67.8169,661.333 67.9996,661.169 67.9996,660.937L 67.9996,654.667L 67.9996,648.395C 67.9996,648.164 67.8169,648 67.6183,648 Z M 66.6663,650.144L 66.6663,654.667L 66.6663,659.189L 63.3863,657.044L 62.1209,656.217L 61.7889,656L 61.3916,656L 55.9996,656C 55.2649,656 54.6663,655.401 54.6663,654.667C 54.6663,653.932 55.2649,653.333 55.9996,653.333L 61.3916,653.333L 61.7889,653.333L 62.1209,653.116L 63.3849,652.289L 66.6663,650.144 Z " HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Path x:Name="Path_6" Width="13" Height="12" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 61.5899,656.667L 56.0005,656.667C 54.8965,656.667 54.0005,655.769 54.0005,654.667C 54.0005,653.564 54.8965,652.667 56.0005,652.667L 61.5899,652.667L 67.3339,648.912L 67.3339,660.421L 61.5899,656.667 Z " HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="1.777" Canvas.Top="4.056"/>
    <TextBlock  x:Name="Displaytxb"  Height="18" Canvas.Left="136.069" TextWrapping="Wrap" Text="100" Canvas.Top="1.917" Width="23" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="White"/>

</Canvas>

and here is my code behind:

    private void ChangeTheVolume(double newVolume)
    {
        if (newVolume < 0 || newVolume > 100) return;

        newVolume = Math.Round(newVolume);
        double tempVolume = (ValumeMaxHigh * newVolume);
        ColorBarPath.Width = tempVolume;

        double pointX = (LocationMaxHigh * newVolume)   46.11;
        Canvas.SetLeft(SwitchPath, pointX); // set the left position of rectangle to mouse X
        Displaytxb.Text = Convert.ToString(newVolume);

        VolumeOut = Volume;
    }
private void SwitchPath_MouseDown(object sender, MouseButtonEventArgs e)
    {
        Cursor = Cursors.Hand;
        _handToolMove = true;
        SwitchPath.CaptureMouse();
        _startPoint = e.GetPosition(VolumeScrollBarCanvas);
        double mouseCurrentLocation =  Canvas.GetLeft(SwitchPath);
        _mouseDownForHandToolOffSetX = _startPoint.X - mouseCurrentLocation;
    }

    private void SwitchPath_MouseMove(object sender, MouseEventArgs e)
    {
        if (_handToolMove)
        {
            Point v = e.GetPosition(VolumeScrollBarCanvas);
            Volume = 0.6933 * v.X   1.24946035807;
        }

    }

    private void SwitchPath_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (_handToolMove)
        {
            Point v = e.GetPosition(VolumeScrollBarCanvas);
            Volume = 0.6933 * v.X   1.25;
            SwitchPath.ReleaseMouseCapture();
            _handToolMove = false;
            Cursor = Cursors.Hand;
        }
       
       
    }
}
    public VolumeScrollBar()
    {
        RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
        InitializeComponent();
      
    }

CodePudding user response:

The issue here isn't the speed of the render but just in your geometry calculations. The volume is not scaling 1:1 with the mouse movement. (That is, in terms of y=mx b, m needs to be 1).

So, this line in SwitchPath_MouseMove -

  Volume = 0.6933 * v.X   1.24946035807;

Would be better written as

  Volume = (v.X - 46.11) / ValumeMaxHigh;

That markedly improves things after trying it out with your code.

In English, what we want is the position of the mouse X relative to the left edge of the slider, normalized by the total width of the track. So that means mouse X minus the left offset divided by the total available width - which you hard code in VolumeMaxHigh (which seems to be the actual width / 100, so this guarantees volume will always be out of 100).

If you had a much more complex graphic, you would want to use a RenderTransform during the mouse move, and set Canvas.Left only on the mouse up, but this is simple enough where performance is not the issue.

Anyway, if you were to consider redoing this I might suggest writing a general purpose slider of your own that is not dependent on any particular dimensions but rather learns its dimensions at runtime through ActualWidth and the like. The source code for WPF is online, specifically for Slider, which will show you how that would be done. Reproducing existing controls in your own coding style is one of the best ways to learn WPF IMO so I'd encourage it as a learning exercise.

You can almost certainly re-template Slider to get what you want too, and if all you want to do is solve the problem at hand and go home that's perfectly fine. But since you put in all this effort already it's worth learning how to do right, as sooner or later you'll come up with a genuine need to write a complex custom control.

Also whether you decide to re-template Slider or make your own, studying the default template for Slider will help too.

CodePudding user response:

This slow response can happen also with a regular Slider. If this was the case I would recommend using the "Delay" to the binding of the Slider. In your case we should do something similar : all mouse events should just keep the mouse point somewhere with no logic and no rendering. Parallelly , create a timer event to occur every 10 milliseconds (or so.. ) , and make the changes there. This way you can improve the system responsiveness. The code behind may look as following:

        Point _lastPoint;
        Point _lastPointHandled;
        public MainWindow()
        {
            InitializeComponent();
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(10);
            timer.Tick  = Timer_Tick; ;
            timer.Start();
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (_lastPoint != _lastPointHandled)
            {
                // do your things
                _lastPointHandled = _lastPoint;
            }
        }
        private void SwitchPath_MouseMove(object sender, MouseEventArgs e)
        {
            _lastPoint = e.GetPosition(VolumeScrollBarCanvas);
        }

        private void SwitchPath_MouseUp(object sender, MouseButtonEventArgs e)
        {

            _lastPoint = e.GetPosition(VolumeScrollBarCanvas);

        }
  • Related