WPF DataGrid2D绑定后Canvas绘图变慢及内存泄漏问题解决
问题:切换矩阵项后Canvas绘图卡顿、内存飙升的解决办法
我开发的程序包含图形项和矩阵项:
- 图形项:用于绘制椭圆和线条的Canvas
- 矩阵项:使用DataGrid2DLibrary(命名空间
xmlns:dg2d="clr-namespace:DataGrid2DLibrary;assembly=DataGrid2DLibrary")将二维矩阵绑定至DataGrid2D
程序启动后操作图形时Canvas绘图流畅,但点击矩阵项让ItemsSource生效后,切回图形项时Canvas绘图变得缓慢,内存占用大幅增加。
我尝试过以下代码清空ItemsSource并清理内存,但效果不佳:
尝试的代码
MainWindow.xaml.cs
private void MatrixData(object sender, RoutedEventArgs e) { if (MatrixMenu.IsChecked) { if (DrawingCanvas_Undirected.Visibility == Visibility.Visible || DrawingCanvas_Directed.Visibility == Visibility.Visible) { GraphItem.Visibility = Visibility.Visible; } MatrixItem.Visibility = Visibility.Collapsed; MatrixAdj.ItemsSource2D = null; MatrixInc.ItemsSource2D = null; MatrixMenu.IsChecked = false; GC.Collect(); } }
MainWindow.xaml相关代码
<Grid x:Name="MatrixItem" Visibility ="Collapsed"> <Grid.RowDefinitions> <RowDefinition Height="149*"/> <RowDefinition Height="285*"/> </Grid.RowDefinitions> <Canvas> <dg2d:DataGrid2D x:FieldModifier="public" x:Name="MatrixAdj" VirtualizingPanel.IsVirtualizingWhenGrouping="True" Canvas.Left="411" Canvas.Top="20" Width="350" Height="289" AlternationCount="2" UseModifiedDataGridStyle="True" ItemsSource2D="{Binding Int2DList}" RowBackground="White" AlternatingRowBackground="#ebebeb" Background="Transparent" HorizontalAlignment="Left" VerticalAlignment="Center" /> </Canvas> <Canvas Margin="4,2,-4,265" Grid.RowSpan="2"> <dg2d:DataGrid2D x:FieldModifier="public" x:Name="MatrixInc" Canvas.Left="19" Canvas.Top="20" Width="350" Height="289" AlternationCount="2" UseModifiedDataGridStyle="True" ItemsSource2D="{Binding Int2DList}" RowBackground="White" VirtualizingPanel.IsVirtualizingWhenGrouping="True" AlternatingRowBackground="#ebebeb" Background="Transparent" Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Center"/> </Canvas> </Grid>
解决办法
1. 彻底清理DataGrid2D的绑定与资源
仅设置ItemsSource2D = null无法完全释放DataGrid2D内部的UI元素和绑定引用,需进一步清理:
private void MatrixData(object sender, RoutedEventArgs e) { if (MatrixMenu.IsChecked) { if (DrawingCanvas_Undirected.Visibility == Visibility.Visible || DrawingCanvas_Directed.Visibility == Visibility.Visible) { GraphItem.Visibility = Visibility.Visible; } MatrixItem.Visibility = Visibility.Collapsed; // 彻底清理DataGrid2D资源 ClearDataGrid2D(MatrixAdj); ClearDataGrid2D(MatrixInc); MatrixMenu.IsChecked = false; // 后台触发GC,不阻塞UI Task.Run(() => { GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, true); GC.WaitForPendingFinalizers(); }); } } // 封装清理逻辑 private void ClearDataGrid2D(dg2d.DataGrid2D dataGrid) { dataGrid.ItemsSource2D = null; dataGrid.Columns.Clear(); dataGrid.Rows.Clear(); dataGrid.DataContext = null; // 移除所有子元素 while (dataGrid.HasItems) { dataGrid.Items.RemoveAt(0); } }
2. 优化DataGrid2D的虚拟化配置
当前用Canvas作为DataGrid2D的容器,而Canvas不支持UI虚拟化,会一次性渲染所有单元格导致内存暴涨。将容器替换为Grid,并启用完整虚拟化:
<Grid x:Name="MatrixItem" Visibility="Collapsed"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- 邻接矩阵 --> <dg2d:DataGrid2D x:Name="MatrixInc" Width="350" Height="289" AlternationCount="2" UseModifiedDataGridStyle="True" ItemsSource2D="{Binding Int2DList}" RowBackground="White" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizingWhenGrouping="True" AlternatingRowBackground="#ebebeb" Background="Transparent" HorizontalAlignment="Left" VerticalAlignment="Center"/> <!-- 关联矩阵 --> <dg2d:DataGrid2D x:Name="MatrixAdj" Grid.Column="1" Width="350" Height="289" AlternationCount="2" UseModifiedDataGridStyle="True" ItemsSource2D="{Binding Int2DList}" RowBackground="White" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizingWhenGrouping="True" AlternatingRowBackground="#ebebeb" Background="Transparent" HorizontalAlignment="Left" VerticalAlignment="Center"/> </Grid>
3. 优化Canvas绘图逻辑
检查Canvas的绘图代码,避免重复创建绘图对象或残留未清理的元素:
// 切换回图形项前,清空Canvas旧元素 private void SwitchToGraphItem() { DrawingCanvas_Undirected.Children.Clear(); DrawingCanvas_Directed.Children.Clear(); // 重新初始化绘图资源(比如复用已创建的Ellipse/Line对象) InitializeGraphDrawing(); }
4. 彻底移除矩阵项的UI树(可选)
如果Visibility="Collapsed"仍无法释放足够资源,可在切换时将MatrixItem从父容器中移除,需要显示时再添加:
// 切换到图形项时移除矩阵项 MainGrid.Children.Remove(MatrixItem); // 切换回矩阵项时重新添加 // MainGrid.Children.Add(MatrixItem);
内容的提问来源于stack exchange,提问作者Bird
相关产品推荐
相关产品推荐

