0

I want to drow so many graphs with OxyPlot Library.

And I'm testing now that I can add how many graphs with dynamic (but I'll not add graphs over 10000 graphs because it's max graphs in real application).

However when I'll add over 200 graphs, the Oxyplot throw exception.

Exception message is "This PlotModel is already in use by some other PlotView control.".

There are all of my code. (In code, I add graph with dynamic and I add values to the all graphs each 5 second in other thread.)

//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# -- Model Class

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

Maybe my code is bad, but I don't know where is the bad code because it dosen't stop on BreakPoint.

If you give me a advice, I'm so glad.

siksmtt
  • 91
  • 9

1 Answers1

0

I think you may need to rebuild it a little using idea from OxyPlot Example: https://github.com/oxyplot/oxyplot/tree/develop/Source/Examples/WPF/WpfExamples

When i were working last months with oxyplots i found out that this official examples are well done with they ideas, they solution with Performance Demo using this virtualization may helps with performance:

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

The problem may cause using NotifyPropertyChange as refreshing UI as adding new chart maybe you should somehow Unbind List > Notify > Bind New List.

Check more in the link and try to mash-ups they solution to make your own :) I glad if i have helped some :)

Marecz
  • 11
  • 1
  • 4
  • Thanks for advice! I don't know the virtualization so I'll check now with OxyPlot Example. Then, I'm trying solve this problem and I found that performance is good when I change code in reloadGraph Method (in the Model). I edit my first question so would you check and give me more advice? – siksmtt Mar 25 '19 at 00:47