快速更新 OxyPlots(无滑块延迟)

Update OxyPlots quickly (without slider delay)

我有滑块,它可以改变 OxyPlot 中注释的位置。

如您所见,它相当慢。我的问题是如何让它更快或者至少让滑块平滑滑动并改变背景上的蓝线位置?

这是我使用的完整代码。请注意,步进频率设置为 .001,实际上有多个图可以使这个 "issue" 更明显。

XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ScrollViewer>
        <StackPanel Orientation="Vertical" x:Name="stack">
            <!--Here comes the plot from code behind-->
        </StackPanel>
    </ScrollViewer>
    <StackPanel Grid.Row="1" Orientation="Horizontal">
        <Slider Width="200" StepFrequency="0.001" ValueChanged="Slider_ValueChanged" Minimum="-1" Maximum="1"/>
    </StackPanel>
</Grid>

代码隐藏:

List<PlotModel> models = new List<PlotModel>();
public MainPage()
{
    this.InitializeComponent();
    for (int i = 0; i < 10; i++)
    {

        PlotView Plot = new PlotView();
        Plot.Height = 200;
        PlotModel model = new PlotModel();
        models.Add(model);
        model.Series.Add(new FunctionSeries(System.Math.Sin, 0, 10, 0.1, "sin(x)"));
        Plot.Model = model;

        var annotation = new LineAnnotation()
        {
            Type = LineAnnotationType.Horizontal,
            ClipByXAxis = false,
            Y = 0,
        };
        Plot.Model.Annotations.Add(annotation);
        stack.Children.Add(Plot);
    }
}
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    foreach (var mo in models)
    {
        (mo.Annotations.First() as LineAnnotation).Y = e.NewValue;
        mo.InvalidatePlot(true);
    }

}

编辑 - 部分解决方案

在@Faywang - MSFT 的回答的帮助下,我设法实现了定时器并 "hide" 在那里绘制了失效图。并没有解决oxyplot本身的慢,但至少滑块没有被它拖下去:

The full demo project on GitHub.

private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    foreach (var annotation in annotations)
    {
        annotation.X = e.NewValue;
    }
    StartTimer();
}

private DispatcherTimer _annotationTimer;

private void StartTimer()
{
    if (_annotationTimer is null)
    {
        _annotationTimer = new DispatcherTimer();
        _annotationTimer.Interval = TimeSpan.FromSeconds(0.01);
        _annotationTimer.Tick += _timer_Tick;

    }
    _annotationTimer?.Start();
}

private void _timer_Tick(object sender, object e)
{
    foreach (var annotation in annotations)
    {
        annotation.PlotModel.InvalidatePlot(false);
    }
    _annotationTimer.Stop();
}

由于短时间内多次渲染会造成延迟,导致Slider无法及时响应。您可以尝试使用Timer并在拖动Slider时以固定的时间间隔(例如,这里我将间隔设置为80ms)强制重绘,这将减少渲染次数并更平滑。例如:

private DispatcherTimer dispatcherTimer;
public void DispatcherTimerSetup()
{
    dispatcherTimer = new DispatcherTimer();
    dispatcherTimer.Tick += DispatcherTimer_Tick; ;
    dispatcherTimer.Interval = TimeSpan.FromMilliseconds(80);
    dispatcherTimer.Start();
}

private void DispatcherTimer_Tick(object sender, object e)
{
    foreach (var mo in models)
    {
        (mo.Annotations.First() as LineAnnotation).Y = MySlider.Value;
        mo.InvalidatePlot(true);
    }
}

private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    if (dispatcherTimer == null)
    {
        DispatcherTimerSetup();
    }
}

或者你可以调用Task.Run( )方法创建一个task,把耗时的操作放在里面,然后用await进行异步操作。当你想在这个方法中更新UI时,你需要使用Dispatcher.RunAsync方法回到UI线程。