Обновите OxyPlots быстро (без задержки ползунка) - PullRequest
0 голосов
/ 20 марта 2020

У меня есть ползунок, который меняет положение аннотаций в OxyPlot.

slider and oxyplot

Как видите, он довольно медленный. Мои вопросы как сделать это быстрее или хотя бы позволить слайдеру плавно скользить и изменить положение синей линии на фоне?

Вот полный код, который я использовал. Обратите внимание, что частота шагов установлена ​​на .001, и на самом деле есть несколько графиков, чтобы сделать эту «проблему» более очевидной.

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

}

EDIT - Частичное решение

С помощью ответа @Faywang - MSFT мне удалось реализовать таймер и «спрятать» недействительные сюжеты там. Это не решает медлительность самого оксиплота, но, по крайней мере, слайдер не тянет его вниз:

not so slow annotation

Полный демонстрационный проект на 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();
}

1 Ответ

1 голос
/ 23 марта 2020

Поскольку несколько визуализаций за короткое время вызовут задержку, ползунок не может ответить вовремя. Вы можете попытаться использовать таймер и принудительно перерисовать его с фиксированным интервалом времени (например, здесь я установил интервал в 80 мс) при перетаскивании ползунка, это уменьшит количество рендеров и сделает их более плавными. Например:

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( ), чтобы создать задачу и поместить в нее трудоемкие операции, а затем использовать await для выполнения асинхронных операций. Если вы хотите обновить пользовательский интерфейс в этом методе, вам нужно использовать метод Dispatcher.RunAsync для возврата в поток пользовательского интерфейса.

...