WPF .NET6中OxyPlot报错:PlotModel已被其他PlotView使用求助
问题描述
我基于Josh Smith的MVVM Demo,使用WPF和.NET 6.0开发应用,绘图代码放在独立的.NET 6.0项目中。应用通过标签页实现多工作区,可打开多个包含或不包含绘图的标签页,但切换回含绘图的标签页时,会抛出异常:OxyPlot - This PlotModel is already in use by some other PlotView control。切换标签时能观察到视图被重新实例化,且相同代码在.NET Framework 4.7.2环境下可正常运行。
相关代码
BasicTrackView的XAML:
<UserControl x:Class="DataPlot.Views.BasicTrackView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DataPlot.Views" xmlns:oxy="http://oxyplot.org/wpf" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <oxy:PlotView x:Name="Plot" Model="{Binding PlotModel}" Grid.Column="1" MinHeight="{Binding MinimumPlotHeight}"> <oxy:PlotView.DefaultTrackerTemplate> <ControlTemplate> <oxy:TrackerControl Position="{Binding Position}" LineExtents="{Binding PlotModel.PlotArea}"> <oxy:TrackerControl.Background> <LinearGradientBrush EndPoint="0,1"> <GradientStop Color="#f0e0e0ff" /> <GradientStop Offset="1" Color="#f0ffffff" /> </LinearGradientBrush> </oxy:TrackerControl.Background> <oxy:TrackerControl.Content> <TextBlock Text="{Binding}" Margin="7" /> </oxy:TrackerControl.Content> </oxy:TrackerControl> </ControlTemplate> </oxy:PlotView.DefaultTrackerTemplate> </oxy:PlotView> </Grid> </UserControl>
BasicTrackView后台代码:
public partial class BasicTrackView : UserControl { public BasicTrackView() { InitializeComponent(); } }
TrackContainerView的XAML:
<UserControl x:Class="DataPlot.Views.TrackContainerView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DataPlot.Views" xmlns:vm="clr-namespace:DataPlot.ViewModels" xmlns:helpers="clr-namespace:DataPlot.Helpers" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.Resources> <DataTemplate DataType="{x:Type vm:BasicTrackViewModel}"> <local:BasicTrackView/> </DataTemplate> <DataTemplate DataType="{x:Type vm:GenericTrackViewModel}"> <local:GenericTrackView IsActive="{Binding IsActive}"/> </DataTemplate> <DataTemplate DataType="{x:Type vm:CollapsableTrackViewModel}"> <local:CollapsableTrackView IsActive="{Binding IsActive}"/> </DataTemplate> </UserControl.Resources> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label Grid.Row="0" Content="Controls?" Width="60" Height="25" HorizontalAlignment="Right" Margin="0,2,20,2" Grid.Column="4" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Background="LightGray"> <Label.ToolTip> <ToolTip> <DockPanel Width="200" Height="75"> <TextBox Text="Zoom: Ctrl + Right Mouse, or
Zoom with mouse wheel
Pan: Right Mouse" AcceptsReturn="True"/> </DockPanel> </ToolTip> </Label.ToolTip> </Label> <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> <ItemsControl Grid.Row="1" ItemsSource="{Binding TrackViewModels}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Grid helpers:GridHelpers.RowCount="{Binding TrackViewModels.Count}" helpers:GridHelpers.StarRows="All"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Grid.Row" Value="{Binding RowIndex}" /> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> </ScrollViewer> </Grid> </UserControl>
解决方案
1. 视图卸载时解绑PlotModel
问题根源是TabControl切换时销毁旧视图、重新创建新视图,导致同一个PlotModel被多个PlotView绑定。可以在视图的Unloaded事件中解绑模型,Loaded事件中重新绑定:
修改BasicTrackView的后台代码:
public partial class BasicTrackView : UserControl { public BasicTrackView() { InitializeComponent(); Unloaded += BasicTrackView_Unloaded; Loaded += BasicTrackView_Loaded; } private void BasicTrackView_Unloaded(object sender, RoutedEventArgs e) { // 解绑PlotModel,避免被多个PlotView实例绑定 Plot.Model = null; } private void BasicTrackView_Loaded(object sender, RoutedEventArgs e) { // 视图加载时重新绑定PlotModel if (DataContext is BasicTrackViewModel vm) { Plot.Model = vm.PlotModel; } } }
2. 让TabControl保留已创建的视图
TabControl默认会卸载非选中标签的内容,可通过修改TabItem的样式,让内容视图保持存活:
<TabControl> <TabControl.ItemContainerStyle> <Style TargetType="TabItem"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <ContentPresenter Content="{Binding}" KeepAlive="True"/> </DataTemplate> </Setter.Value> </Setter> </Style> </TabControl.ItemContainerStyle> <!-- 你的TabItem定义 --> </TabControl>
KeepAlive="True"会让ContentPresenter保留视图实例,切换标签时不会销毁,也就不会重复创建视图导致模型冲突。
3. 为每个视图生成独立的PlotModel(可选)
如果业务场景允许,可以在ViewModel中为每个视图实例创建独立的PlotModel,确保每个PlotView绑定唯一的模型。这种方法需要调整ViewModel的逻辑,比如在视图创建时初始化新的PlotModel实例。
内容的提问来源于stack exchange,提问作者spainchaud
相关产品推荐
相关产品推荐

