当我添加太多图形时,Oxyplot抛出异常

时间:2019-03-15 06:06:58

标签: c# wpf oxyplot

我想用OxyPlot库绘制很多图。

我现在正在测试,我可以添加多少个动态图(但我不会添加超过10000个图的图,因为这是实际应用中的最大图)。

但是,当我添加200多个图形时,Oxyplot抛出异常。

异常消息是“此PlotModel已被其他PlotView控件使用。”。

有我所有的代码。 (在代码中,我动态添加图形,并在其他线程中每5秒向所有图形添加值。)

// Xaml-MainView

<Window x:Class="OxyplotStressTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
    xmlns:local="clr-namespace:OxyplotStressTest"
    mc:Ignorable="d"
    Title="MainWindow" Height="550" Width="725">
<Grid>
    <Button Content="Add 100" HorizontalAlignment="Left" Height="32" Margin="20,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click100"/>
    <Button Content="Add 50" HorizontalAlignment="Left" Height="32" Margin="102,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click50"/>
    <Button Content="Add 10" HorizontalAlignment="Left" Height="32" Margin="189,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click10"/>
    <Button Content="Add 1" HorizontalAlignment="Left" Height="32" Margin="274,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click1"/>

    <Grid Margin="20,65,19,10">
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding List}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <Label Content="{Binding Tag}"/>
                            <oxy:PlotView HorizontalAlignment="Left" Height="130" Margin="20,23,0,0" VerticalAlignment="Top" Width="600" 
                      Model="{Binding Chart}" IsMouseWheelEnabled="False" IsManipulationEnabled="False" />
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
</Grid>

// C#-MainWindow.cs

public partial class MainWindow : Window
{
    private MainWindowViewModel mMainWindowViewModel = null;

    public MainWindow()
    {
        InitializeComponent();
        MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
        this.DataContext = mainWindowViewModel;
        mMainWindowViewModel = mainWindowViewModel;
        Thread thread = new Thread(new ParameterizedThreadStart(reloadGraph));
        thread.Start();
    }

    private void Button_Click100(object sender, RoutedEventArgs e)
    {
        AddGraph addGraph = new AddGraph(mMainWindowViewModel);
        addGraph.addGraph(100);
    }

    private void Button_Click50(object sender, RoutedEventArgs e)
    {
        AddGraph addGraph = new AddGraph(mMainWindowViewModel);
        addGraph.addGraph(50);
    }

    private void Button_Click10(object sender, RoutedEventArgs e)
    {
        AddGraph addGraph = new AddGraph(mMainWindowViewModel);
        addGraph.addGraph(10);
    }

    private void Button_Click1(object sender, RoutedEventArgs e)
    {
        AddGraph addGraph = new AddGraph(mMainWindowViewModel);
        addGraph.addGraph(1);
    }

    private void reloadGraph(object param)
    {
        while (true)
        {
            Thread.Sleep(5000);

            if (mMainWindowViewModel.List.Count > 0)
            {
                AddGraph addGraph = new AddGraph(mMainWindowViewModel);
                addGraph.reloadGraph();
            }

            Console.WriteLine(Environment.WorkingSet.ToString());
        }
    }
}

// C#-MainViewModel

    public MainWindowViewModel()
    {
        listVal = new ObservableCollection<Items>();
        BindingOperations.EnableCollectionSynchronization(this.listVal, new object());
    }


    private ObservableCollection<Items> listVal = new ObservableCollection<Items>();
    public ObservableCollection<Items> List
    {
        get
        {
            return listVal;
        }
        set
        {
            listVal = value;
            NotifyPropertyChanged("List");
        }
    }


public class Items
{
    public string Tag { get; set; }
    private PlotModel chartVal = new PlotModel();
    public PlotModel Chart
    {
        get
        {
            return chartVal;
        }
        set
        {
            chartVal = value;
        }
    }
}


public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
} 

// C#-模型类

class AddGraph
{
    private MainWindowViewModel mMainWindowViewModel = null;

    public AddGraph(MainWindowViewModel pMainWindowViewModel)
    {
        mMainWindowViewModel = pMainWindowViewModel;
    }

    public void addGraph(int pCount)
    {
        try
        {
            for (int i = 0; i < pCount; i++)
            {
                Random random = new Random();
                long data = random.Next(100);

                ColumnSeries column = new ColumnSeries();
                column.FillColor = OxyColors.SkyBlue;
                column.Items.Add(new ColumnItem() { Value = data });
                data *= random.Next(50);
                column.Items.Add(new ColumnItem() { Value = data });

                Items items = new Items();
                items.Tag = mMainWindowViewModel.List.Count.ToString();
                items.Chart.Series.Add(column);
                items.Chart.InvalidatePlot(true);

                mMainWindowViewModel.List.Add(items);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }



    public void reloadGraph()
    {
        try
        {
            List<Items> newList = new List<Items>();

            foreach (Items listItem in mMainWindowViewModel.List)
            {
                string tag = listItem.Tag;
                PlotModel plotModel = listItem.Chart;

                ColumnSeries oldGraph = (ColumnSeries)plotModel.Series[0];

                ColumnSeries newGraph = new ColumnSeries();
                newGraph.FillColor = OxyColors.SkyBlue;

                for (int i = 0; i < oldGraph.Items.Count; i++)
                {
                    if (oldGraph.Items.Count == 30 && i == 0)
                    {
                        continue;
                    }

                    newGraph.Items.Add(new ColumnItem() { Value = oldGraph.Items[i].Value });
                }

                Random random = new Random();
                long val = random.Next(500);
                val *= random.Next(50);

                newGraph.Items.Add(new ColumnItem() { Value = val });

                Items items = new Items();
                items.Tag = tag;
                items.Chart.Series.Add(newGraph);
                items.Chart.InvalidatePlot(true);

                newList.Add(items);
            }
#region   //there are my solution and it shows good performance
            int index = 0;

            foreach (var addItem in newList)
            {
                mMainWindowViewModel.List[index] = addItem;
                index++;
            }
#endregion

#region  //there are my first code and it has problem
            mMainWindowViewModel.List.Clear();

            foreach (var addItem in newList)
            {
                mMainWindowViewModel.List.Add(addItem);
            }
#endregion
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

也许我的代码很糟糕,但是我不知道坏代码在哪里,因为它不会在BreakPoint上停止。

如果您给我建议,我很高兴。

1 个答案:

答案 0 :(得分:0)

我认为您可能需要使用OxyPlot示例https://github.com/oxyplot/oxyplot/tree/develop/Source/Examples/WPF/WpfExamples

中的想法对其进行一些重建。

当我上个月与oxyplots一起工作时,我发现此官方示例在他们的想法上做得很好,他们使用Performance Virtualization的Performance Demo解决方案可能对性能有所帮助:

            <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsVirtualizing="True" IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

该问题可能导致将NotifyPropertyChange用作刷新UI以及添加新图表的方式,也许您应该以某种方式取消绑定列表>通知>绑定新列表。

在链接中查看更多信息,然后尝试将其解决方案混搭起来以制作自己的:) 我很高兴我曾经帮助过一些人:)