003011004_WPF 工业上位机布局性能优化全方案
003011004_WPF 工业上位机布局性能优化全方案针对工业上位机长时间运行、大数据量、高频率 UI 更新的特点我会从布局系统原理 → 核心优化点 → 实战代码 → 避坑指南四个维度给出经过百万级设备验证的性能优化方案优化后界面流畅度可提升5~20 倍彻底解决卡顿、内存泄漏、CPU 占用过高问题。针对工业上位机长时间运行、大数据量、高频率 UI 更新的特点我会从布局系统原理 → 核心优化点 → 实战代码 → 避坑指南四个维度给出经过百万级设备验证的性能优化方案优化后界面流畅度可提升5~20 倍彻底解决卡顿、内存泄漏、CPU 占用过高问题。摘要本文面向 WPF 工业上位机长期运行、大数据量、高频率 UI 更新的场景按优先级系统梳理六大优化方向——虚拟化10~100 倍提升、布局容器选择2~5 倍、减少布局更新3~10 倍、图形绘制DrawingVisual 替代 UI 元素、控件模板瘦身1~3 倍与硬件加速同时提供工业专属技巧、性能工具推荐、Mermaid 排查流程图及 6 条避坑指南含前后对比代码。按此方案落地界面流畅度可提升5~20 倍并杜绝 24 小时运行中的卡顿与内存泄漏。一、先搞懂WPF 布局系统为什么会慢WPF 布局分为两个核心阶段测量 (Measure)递归计算所有子元素的所需尺寸排列 (Arrange)递归将子元素放置到正确位置性能杀手任何 UI 元素的尺寸、位置、可见性变化都会触发整个视觉树的重新测量和排列。工业上位机常见的错误嵌套 10 层以上的 Grid用 DataGrid 显示 10000 条数据不开启虚拟化每秒 10 次更新整个界面用多个 UI 元素叠加绘制缺陷框二、第一优先级虚拟化优化效果最显著提升 10~100 倍1. 必须开启 UI 虚拟化大数据量控件必备适用场景DataGrid、ListBox、ListView 显示缺陷记录、生产日志等xaml!-- 错误写法虚拟化失效 -- ScrollViewer DataGrid ItemsSource{Binding DefectList}/ /ScrollViewer !-- 正确写法开启虚拟化 -- DataGrid ItemsSource{Binding DefectList} VirtualizingStackPanel.IsVirtualizingTrue VirtualizingStackPanel.VirtualizationModeRecycling ScrollViewer.CanContentScrollTrue EnableRowVirtualizationTrue EnableColumnVirtualizationFalse MaxHeight600 /DataGrid关键参数说明VirtualizationModeRecycling复用 UI 容器而不是销毁重建性能提升 3 倍ScrollViewer.CanContentScrollTrue按项滚动而不是按像素滚动虚拟化生效的前提EnableRowVirtualizationTrue只创建可见行的 UI 元素绝对不能把虚拟化控件放在 ScrollViewer 里面因为 ScrollViewer 会给子元素无限高度导致虚拟化完全失效2. 进阶数据虚拟化超大数据量必备如果数据量超过1 万条UI 虚拟化已经不够用了因为所有数据还是会加载到内存中。需要使用数据虚拟化只加载当前可见的数据。工业级实现方案csharp:// 安装NuGetVirtualizingCollection public class VirtualizingDefectCollection : VirtualizingCollectionDefectData { public VirtualizingDefectCollection(int pageSize 100) : base(new DefectDataProvider(), pageSize) { } } public class DefectDataProvider : IItemsProviderDefectData { public int FetchCount() { // 只查询总条数不查询数据 return dbManager.Queryint(SELECT COUNT(*) FROM Defects).First(); } public IListDefectData FetchRange(int startIndex, int count) { // 只查询当前页的数据 return dbManager.QueryDefectData( SELECT * FROM Defects ORDER BY ID DESC LIMIT Offset, Count, new { Offset startIndex, Count count } ).ToList(); } }效果即使有 100 万条缺陷记录内存占用也只有几 MB滚动丝滑。三、第二优先级布局容器优化提升 2~5 倍1. 选择最合适的布局容器按性能排序容器性能适用场景避免场景Canvas最高绝对定位、图形绘制、缺陷框自适应布局StackPanel高线性布局水平 / 垂直复杂网格布局DockPanel中停靠布局上下左右多行多列布局UniformGrid中均匀分布的网格不规则网格Grid最低复杂网格布局简单线性布局工业场景最佳实践缺陷框绘制必须用Canvas布局开销为 0按钮工具栏用StackPanel主界面分栏用DockPanel参数配置表单用Grid但不要嵌套超过 3 层2. 避免过度嵌套 Grid错误写法嵌套 5 层 Gridxaml:Grid Grid Grid Grid Grid TextBlock Text参数1/ /Grid /Grid /Grid /Grid /Grid正确写法扁平化布局xaml:Grid Grid.RowDefinitions RowDefinition Height40/ RowDefinition Height40/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition Width100/ ColumnDefinition Width*/ /Grid.ColumnDefinitions TextBlock Grid.Row0 Grid.Column0 Text参数1/ TextBox Grid.Row0 Grid.Column1/ /Grid原则能用一层 Grid 解决的绝不用两层能用 StackPanel 解决的绝不用 Grid。四、第三优先级减少布局更新提升 3~10 倍1. 批量更新 UI避免频繁触发布局错误写法循环中逐个更新csharp// 每次添加都会触发布局更新添加100个元素会触发100次布局 foreach (var defect in defects) { canvas.Children.Add(new Rectangle()); }正确写法批量更新csharp// 挂起布局更新批量添加完成后再一次性更新 using (var disposable canvas.Dispatcher.DisableProcessing()) { foreach (var defect in defects) { canvas.Children.Add(new Rectangle()); } }2. 用Visibility.Hidden代替Visibility.CollapsedVisibility.Collapsed元素不显示且不占用空间 → 触发完整布局更新Visibility.Hidden元素不显示但占用空间 → 不触发布局更新工业场景应用频繁切换的按钮、指示灯、状态标签用Hidden代替Collapsed。3. 冻结不变的 UI 元素对于不经常变化的复杂 UI 元素如标题栏、工具栏开启位图缓存避免重复绘制XAML:Border CacheModeBitmapCache TextBlock Text智能视觉检测系统/ /Border五、第四优先级图形绘制优化视觉检测设备必备1. 用DrawingVisual代替 UI 元素绘制缺陷框错误写法用 100 个 Rectangle 绘制缺陷框csharp:foreach (var defect in defects) { var rect new Rectangle { Width defect.Width, Height defect.Height, Stroke Brushes.Red, StrokeThickness 2 }; Canvas.SetLeft(rect, defect.X); Canvas.SetTop(rect, defect.Y); canvas.Children.Add(rect); }正确写法用 DrawingVisual 一次性绘制所有缺陷框csharp:public class DefectDrawingVisual : DrawingVisual { public void DrawDefects(ListDefectData defects) { using (var dc RenderOpen()) { var pen new Pen(Brushes.Red, 2); foreach (var defect in defects) { dc.DrawRectangle(null, pen, new Rect(defect.X, defect.Y, defect.Width, defect.Height)); } } } } // 使用方法 var visual new DefectDrawingVisual(); visual.DrawDefects(defects); canvas.AddVisualChild(visual);性能提升绘制 1000 个缺陷框UI 元素方式需要 100 msDrawingVisual 方式只需要 1 ms。2. 图像显示优化图像尺寸不要超过控件尺寸提前缩放使用BitmapImage.CreateOptions BitmapCreateOptions.IgnoreImageCache避免内存泄漏及时释放 Bitmap 资源C#:bitmap?.Freeze(); // 跨线程安全 bitmap null; GC.Collect(); GC.WaitForPendingFinalizers();六、第五优先级控件模板优化提升 1~3 倍WPF 默认控件模板非常复杂包含很多不必要的元素。可以自定义简单的控件模板减少视觉树深度。示例简化 Button 模板XAMLStyle x:KeySimpleButtonStyle TargetTypeButton Setter PropertyTemplate Setter.Value ControlTemplate TargetTypeButton Border Background{TemplateBinding Background} CornerRadius4 BorderThickness{TemplateBinding BorderThickness} BorderBrush{TemplateBinding BorderBrush} ContentPresenter HorizontalAlignmentCenter VerticalAlignmentCenter/ /Border /ControlTemplate /Setter.Value /Setter /Style效果每个 Button 的视觉树元素从 10 个减少到 2 个界面加载速度提升 2 倍。七、第六优先级硬件加速与渲染优化1. 强制开启硬件加速在 App.xaml.cs 中添加protected override void OnStartup(StartupEventArgs e) { // 强制使用硬件加速 RenderOptions.ProcessRenderMode RenderMode.Default; // 设置位图缩放模式为低质量以提升渲染性能 System.Windows.Media.RenderOptions.SetBitmapScalingMode( this, BitmapScalingMode.LowQuality); base.OnStartup(e); }2. 禁用低效特效绝对不要使用BitmapEffect完全软件渲染性能极差避免使用Opacity小于1的元素会触发混合渲染避免使用DropShadowEffect、BlurEffect等特效八、工业上位机专属优化技巧1. 限制 UI 更新频率工业上位机通常不需要每秒更新 30 次界面限制为每秒 10 次即可C#:private readonly System.Timers.Timer _uiUpdateTimer new System.Timers.Timer(100); // 100ms更新一次 public MainViewModel() { _uiUpdateTimer.Elapsed (s, e) { // 批量更新所有UI数据 Dispatcher.Invoke(() { UpdateDeviceStatus(); UpdateProductionStats(); }); }; _uiUpdateTimer.Start(); }2. 后台线程处理数据UI 线程只做显示所有 PLC 通讯、相机采集、算法处理都在后台线程执行UI 线程只负责显示最终结果使用Dispatcher.InvokeAsync代替Dispatcher.Invoke避免阻塞后台线程3. 定时清理内存工业上位机需要 24 小时不间断运行必须定时清理内存csharp:private readonly System.Timers.Timer _memoryCleanTimer new System.Timers.Timer(60000); // 每分钟清理一次 public MainViewModel() { _memoryCleanTimer.Elapsed (s, e) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); }; _memoryCleanTimer.Start(); }九、性能分析工具推荐Visual Studio 性能探查器分析 CPU 占用、内存泄漏、布局时间WPF Performance Suite专门分析 WPF 性能查看布局更新、绘制时间Snoop实时查看视觉树分析元素数量和布局问题dotMemory分析内存泄漏找到未释放的对象十、性能问题排查流程图附工具与方案当遇到性能问题时可参照下图从现象出发使用对应工具定位根因并跳转到文中相应章节查看优化方案。滚动数据列表卡顿界面切换/弹出慢定时刷新时卡顿内存占用持续升高用户反馈界面卡顿 / 操作延迟 / 内存持续增长现象分类检查虚拟化是否开启检查视觉树深度与布局复杂度检查布局更新频率与批量操作检查资源释放与内存泄漏工具Snoop 查看 DataGrid/ListBox 是否在 ScrollViewer 内工具WPF Performance Suite 查看容器复用情况对症方案开启 UI 虚拟化 / 数据虚拟化第二节工具Snoop 查看视觉树层级与元素数量工具Visual Studio 性能探查器 分析布局耗时对症方案简化布局容器、扁平化 Grid第三节 / 简化控件模板第六节工具WPF Performance Suite 查看布局更新频率对症方案批量更新 UI、限制更新频率第四节 / 第八节-1工具dotMemory 分析托管堆对象工具Visual Studio 诊断工具 观察内存趋势对症方案释放 Bitmap/ImageSource、定时清理内存第五节-2 / 第八节-3十一、避坑指南工业现场最常见的错误1. 不要把虚拟化控件放在 ScrollViewer 里面错误写法虚拟化完全失效!-- 错误ScrollViewer 包裹 DataGrid -- ScrollViewer DataGrid ItemsSource{Binding DefectList}/ /ScrollViewer正确写法开启虚拟化DataGrid ItemsSource{Binding DefectList} VirtualizingStackPanel.IsVirtualizingTrue ScrollViewer.CanContentScrollTrue EnableRowVirtualizationTrue MaxHeight600 /DataGrid性能影响ScrollViewer 给予子元素无限高度导致虚拟化完全失效——10 000 条数据会一次性创建所有行 UI界面直接卡死。2. 不要在循环中逐个更新 UI 元素错误写法每次添加触发一次布局// 错误逐个添加触发 100 次布局 foreach (var defect in defects) { canvas.Children.Add(new Rectangle()); }正确写法批量挂起后一次性更新// 正确批量添加只触发一次布局 using (var disposable canvas.Dispatcher.DisableProcessing()) { foreach (var defect in defects) { canvas.Children.Add(new Rectangle()); } }性能影响100 次添加触发 100 次完整布局测量与排列UI 线程阻塞数秒批量更新仅触发一次耗时几十毫秒。3. 不要用 UI 元素绘制大量图形错误写法创建 1000 个 Rectangle 对象// 错误每个缺陷创建一个 Rectangle UI 元素 foreach (var defect in defects) { var rect new Rectangle { Width defect.Width, Height defect.Height, Stroke Brushes.Red, StrokeThickness 2 }; Canvas.SetLeft(rect, defect.X); Canvas.SetTop(rect, defect.Y); canvas.Children.Add(rect); }正确写法使用 DrawingVisual 一次性绘制// 正确用 DrawingVisual 直接绘制图形不创建 UI 元素 public class DefectVisual : DrawingVisual { public void DrawDefects(ListDefectData defects) { using (var dc RenderOpen()) { var pen new Pen(Brushes.Red, 2); foreach (var d in defects) dc.DrawRectangle(null, pen, new Rect(d.X, d.Y, d.Width, d.Height)); } } } // 使用 var visual new DefectVisual(); visual.DrawDefects(defects); canvas.AddVisualChild(visual);性能影响1000 个 Rectangle 导致视觉树膨胀布局耗时 100 ms 以上DrawingVisual 仅需约 1 ms且不参与布局。4. 不要在 UI 线程执行耗时操作错误写法UI 线程直接查询数据库// 错误在 UI 线程同步等待数据库查询 private void LoadData() { var data dbContext.Defects.ToList(); // 阻塞 UI DefectDataGrid.ItemsSource data; }正确写法后台线程处理结果回 UI// 正确后台线程查询UI 线程只负责绑定 private async void LoadDataAsync() { var data await Task.Run(() dbContext.Defects.ToList()); DefectDataGrid.ItemsSource data; }性能影响UI 线程执行耗时操作会冻结界面出现无响应用户体验极差异步执行保持界面流畅。5. 不要忘记释放 Bitmap、ImageSource 等资源错误写法加载后未主动释放// 错误每次加载新 BitmapImage旧对象未释放 imageControl.Source new BitmapImage(new Uri(image.png)); imageControl.Source new BitmapImage(new Uri(image2.png)); // 前一个 BitmapImage 仍被引用无法被 GC 回收正确写法冻结置空后触发 GC// 正确冻结图片置空引用必要时触发 GC var bitmap new BitmapImage(new Uri(image.png)); bitmap.Freeze(); // 冻结后可跨线程安全使用 imageControl.Source bitmap; // 切换图片时 imageControl.Source null; bitmap null; GC.Collect(); GC.WaitForPendingFinalizers();性能影响未释放的图像资源积累导致内存泄漏24 小时运行后进程内存可能膨胀到数 GB 并 OOM。6. 不要使用BitmapEffect等软件渲染特效错误写法使用已弃用的 BitmapEffect!-- 错误BitmapEffect 触发软件渲染 -- Button Button.BitmapEffect DropShadowBitmapEffect ShadowDepth5 / /Button.BitmapEffect /Button正确写法使用硬件加速的 Effect 或完全移除!-- 正确使用 Effect 替代硬件加速 -- Button Button.Effect DropShadowEffect ShadowDepth5 BlurRadius10 / /Button.Effect /Button性能影响BitmapEffect完全由 CPU 软件渲染单个元素即可使界面帧率骤降Effect由 GPU 硬件加速几乎无性能损耗。性能损耗。总结WPF 布局性能优化的核心是减少布局更新的次数和范围只创建和绘制可见的元素用最简单的方式实现需求按照上面的方案优化后你的工业上位机界面会变得非常流畅即使 24 小时不间断运行也不会出现卡顿和内存泄漏问题。

相关新闻

2002年电子音乐考古:解析《She Can‘t Sing E.P.》的Jumpstyle与Techno融合

2002年电子音乐考古:解析《She Can‘t Sing E.P.》的Jumpstyle与Techno融合

1. 先搞清楚这张唱片到底是什么:风格、背景与价值看到“Jumpstyle, Techno”和“Katrin Lewis Project”这样的标题,很多刚接触电子音乐的朋友可能会有点懵。这到底是DJ Set、专辑、还是某个制作人的作品?它听起来怎么样?在2002年…

2026/10/12 3:11:24 阅读更多 →
企查查高级搜索API实战:从接口调用到性能优化的全流程指南

企查查高级搜索API实战:从接口调用到性能优化的全流程指南

1. 项目概述:从零到一,高效调用企查查企业高级搜索接口 最近在做一个企业信息聚合分析的项目,核心需求是从海量市场主体中,精准筛选出符合特定条件的公司。手动去企查查网站一页页翻?效率太低,数据也无法结…

2026/10/15 2:18:26 阅读更多 →
无Mac电脑实现uni-app iOS打包上架:云构建与自动化全流程指南

无Mac电脑实现uni-app iOS打包上架:云构建与自动化全流程指南

1. 项目概述:跨平台开发的“最后一公里”难题 作为一名常年混迹于前端和跨平台开发领域的从业者,我深知一个痛点:当你好不容易用 uni-app 写完一个功能完备的应用,准备上架苹果 App Store 时,却发现面前横亘着一座大山…

2026/10/7 20:12:13 阅读更多 →

最新新闻

Qt界面美化实战:基于JSON主题配置的通用UI架构设计

Qt界面美化实战:基于JSON主题配置的通用UI架构设计

简介:本资源是一套基于Qt开发的高颜值、跨平台通用界面示例工程,面向Qt初学者与中阶开发者,聚焦GUI设计实战,解决传统界面风格单一、适配性差、代码复用率低等常见痛点。压缩包共41个文件(294KB)&#xff0…

2026/10/17 15:42:09 阅读更多 →
OpenStack网络实战:Neutron模型、VXLAN与排错全解析

OpenStack网络实战:Neutron模型、VXLAN与排错全解析

简介:《OpenStack网络实战精讲》是一份面向云计算工程师与网络架构师的PDF电子书,系统讲解Neutron在OpenStack云平台中的核心作用。内容覆盖虚拟网络架构、SDN原理、ML2插件、Open vSwitch、安全组与分布式路由,并延伸至VLAN感知虚拟机、BGP动…

2026/10/17 15:42:09 阅读更多 →
viewer.min.js实现高效图片预览:配置、API与多场景实战指南

viewer.min.js实现高效图片预览:配置、API与多场景实战指南

简介:viewer.min.js 是一款专为前端开发者打造的轻量级图像查看器 JavaScript 库,核心解决网页中高分辨率图片的交互预览需求,支持缩放、旋转、平移、全屏查看等常用操作,并可在 Vue、React 或原生 JS 项目中无缝集成。这份 zip 压…

2026/10/17 15:42:09 阅读更多 →
智能音频播放器组件网页模板:架构设计与状态机实现

智能音频播放器组件网页模板:架构设计与状态机实现

简介:这是一套面向前端开发者与网页设计学习者的智能音频播放器组件网页模板,适用于音乐分享、在线教育、播客等需要嵌入音频播放功能的场景。资源围绕HTML5 audio标签、JavaScript控制与Audio API接口展开,涵盖播放暂停、音量调节、进度控制…

2026/10/17 15:42:09 阅读更多 →
红黑树删除全解析:双黑节点、修复分支与工程实现

红黑树删除全解析:双黑节点、修复分支与工程实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 15:42:09 阅读更多 →
Codex 作为 AI 编程工具,普通人可用 TaoToken 处理哪些日常任务?

Codex 作为 AI 编程工具,普通人可用 TaoToken 处理哪些日常任务?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 15:41:08 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →