我想用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上停止。
如果您给我建议,我很高兴。
答案 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以及添加新图表的方式,也许您应该以某种方式取消绑定列表>通知>绑定新列表。
在链接中查看更多信息,然后尝试将其解决方案混搭起来以制作自己的:) 我很高兴我曾经帮助过一些人:)