WPF富文本编辑器开发实战:从RichTextBox到仿Word的架构与避坑指南
简介这是一份面向WPF开发者的开源富文本编辑器代码示例功能对标Microsoft Word适合希望在.NET桌面应用中嵌入格式化文本编辑能力的初中级开发者学习与二次开发。资源包共289个文件约753KB以76个cs源码文件为核心配合10个xaml界面文件与15个baml编译资源另有57个gif、54个png用于演示与图标素材以及dll、csproj、sln等工程配置结构完整可直接编译运行。编辑器实现了基本文本编辑、查看与编辑HTML源码、打印、导出纯文本、插入图片和插入表格等功能并附带图片、表格、超链接、颜色与字体选择等对话框组件便于理解WPF图形模型与文本图像数据的处理方式。目前已有2873人学习下载开发者可据此快速搭建类似Word的编辑环境并按需扩展格式化选项或集成第三方库。1. 从零拆解 WPF 富文本编辑器一个仿 Word 的开源代码 demo 到底能跑多远打开 Visual Studio新建一个 WPF 项目拖一个 RichTextBox 上去你立刻就有了一个能加粗、能改字号、能粘贴图片的输入框。但离“仿 Word”还差得远——工具栏按钮状态不同步、撤销栈一塌糊涂、粘贴进来的 HTML 样式全丢、文档保存后重新打开格式错位。这些不是玄学是 WPF 富文本模型和 Word 文档模型之间的结构性差异。这个标题指向的东西很具体用 WPF 做一个富文本编辑器参考开源代码 demo目标形态对标 Word 的核心编辑体验。它适合两类人一是需要在桌面端嵌入文档编辑能力的 C# 开发者比如做合同模板、报告生成、工单批注二是想通过一个完整项目吃透 WPF 文档模型、命令系统和 MVVM 的进阶学习者。热搜里频繁出现的 wpf mvvm、wpf 数据绑定、wpf 界面设计在这个项目里全都会正面撞上。我不会假装见过某个具体的仓库或源码包。下面讲的是如果今天从零搭一个仿 Word 的 WPF 富文本编辑器业界最常见的架构选型是什么、每一步怎么落地、参数怎么调、哪些地方最容易翻车。你可以把它当成一份可复现的施工图而不是某份代码的逐行解读。2. 选型与架构RichTextBox 够不够用什么时候必须上 FlowDocument2.1 先搞清楚 WPF 里三套文档模型的边界WPF 处理文档有三层TextBlock只能显示不可编辑的简单文本RichTextBox承载FlowDocument支持段落、加粗、列表、图片、超链接可编辑FixedDocument面向打印和分页预览编辑能力极弱。仿 Word 的编辑器起点必然是RichTextBox FlowDocument。但FlowDocument不是 Word 的.docx模型。它没有真正的“节”概念没有页眉页脚没有分页符的精确控制表格列宽拖动也比 Word 粗糙。所以选型时要先问自己你要的是“富文本编辑”还是“所见即所得的排版”前者RichTextBox足够后者需要引入第三方排版引擎或自己写分页逻辑。常见做法是编辑态用RichTextBox展示态用FlowDocumentScrollViewer或FlowDocumentPageViewer保存时序列化为 XAML 或自定义 XML。热搜里的“wpf 数据绑定”在这里体现为文档内容本身不适合直接双向绑定但工具栏状态、字体列表、段落对齐方式必须通过 MVVM 绑定到 ViewModel。2.2 最小可运行骨架一个带工具栏的编辑器窗口先搭一个能跑的最小结构。XAML 里放工具栏和RichTextBox工具栏按钮绑定到命令命令操作RichTextBox的EditingCommands或直接操作FlowDocument。!-- MainWindow.xaml -- Window x:ClassWpfRichEditor.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml Title仿Word编辑器 Height600 Width900 DockPanel !-- 工具栏按钮命令绑定到 ApplicationCommands -- ToolBar DockPanel.DockTop Button CommandApplicationCommands.Undo Content撤销/ Button CommandApplicationCommands.Redo Content重做/ Separator/ Button CommandEditingCommands.ToggleBold ContentB/ Button CommandEditingCommands.ToggleItalic ContentI/ Button CommandEditingCommands.ToggleUnderline ContentU/ Separator/ ComboBox x:NameFontSizeBox Width60 SelectionChangedFontSizeBox_SelectionChanged ComboBoxItem12/ComboBoxItem ComboBoxItem14/ComboBoxItem ComboBoxItem16/ComboBoxItem ComboBoxItem18/ComboBoxItem ComboBoxItem24/ComboBoxItem /ComboBox /ToolBar !-- 编辑区 -- RichTextBox x:NameEditor AcceptsTabTrue SpellCheck.IsEnabledTrue VerticalScrollBarVisibilityAuto HorizontalScrollBarVisibilityAuto FlowDocument Paragraph在这里输入内容.../Paragraph /FlowDocument /RichTextBox /DockPanel /Window这段 XAML 的关键点ApplicationCommands.Undo/Redo是 WPF 内置命令RichTextBox自动支持撤销栈不需要自己维护。EditingCommands.ToggleBold等命令也是内置的按钮按下后会自动作用于当前选区。AcceptsTabTrue让 Tab 键插入制表符而不是切换焦点这是编辑器类应用的必备设置。字号下拉框需要手动处理因为EditingCommands没有内置的字号切换命令// MainWindow.xaml.cs private void FontSizeBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (FontSizeBox.SelectedItem is ComboBoxItem item double.TryParse(item.Content.ToString(), out double size)) { // 对当前选区应用字号 var selection Editor.Selection; if (!selection.IsEmpty) { selection.ApplyPropertyValue(TextElement.FontSizeProperty, size); } else { // 无选区时设置插入点的默认字号 Editor.Document.FontSize size; } } }ApplyPropertyValue是TextRange的方法只影响选区。无选区时改Document.FontSize会影响整个文档更合理的做法是记录插入点的TextElement.FontSizeProperty并作为后续输入的默认值。这里先跑通后面在避坑章节细说。2.3 MVVM 改造把工具栏状态和文档操作从代码后置里抽出来上面的写法能跑但按钮的启用/禁用状态、加粗按钮的高亮状态都没同步。选中一段加粗文字时B 按钮应该显示按下状态。这需要监听Editor.SelectionChanged读取选区属性更新 ViewModel。// EditorViewModel.cs public class EditorViewModel : INotifyPropertyChanged { private bool _isBold; public bool IsBold { get _isBold; set { _isBold value; OnPropertyChanged(); } } // 由 View 的 SelectionChanged 事件调用 public void UpdateSelectionState(TextSelection selection) { if (selection.IsEmpty) return; var weight selection.GetPropertyValue(TextElement.FontWeightProperty); IsBold weight is FontWeight w w FontWeights.Bold; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name null) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }XAML 里把按钮的IsChecked绑定到IsBold用ToggleButton替代Button。注意EditingCommands.ToggleBold执行后选区属性会变但SelectionChanged不一定触发所以还需要在命令执行后手动调用UpdateSelectionState。这是 MVVM 和 WPF 文档模型结合时的一个典型摩擦点后面避坑章节会展开。架构选型到这里可以定下来RichTextBox FlowDocument做编辑核心MVVM 管工具栏状态和文件操作文档序列化用 XAML 包或自定义 XML。如果要做多文档标签页外层套TabControl每个 Tab 一个RichTextBox实例。热搜里的“wpf 界面设计”在这个项目里不是锦上添花而是决定工具栏、标尺、状态栏能否协同工作的关键。3. 核心功能落地格式化、撤销栈、剪贴板和文档序列化3.1 段落级格式化对齐、缩进、列表怎么用代码控制行内格式化靠EditingCommands就够了段落级格式化需要操作Paragraph元素。对齐方式用EditingCommands.AlignLeft/AlignCenter/AlignRight/AlignJustify这些也是内置命令。缩进没有内置命令需要手动改Paragraph.TextIndent或Paragraph.Margin。// 增加段落左缩进 private void IncreaseIndent() { var paragraph Editor.Selection.Start.Paragraph; if (paragraph ! null) { // TextIndent 控制首行缩进Margin 控制整体左缩进 paragraph.Margin new Thickness( paragraph.Margin.Left 20, paragraph.Margin.Top, paragraph.Margin.Right, paragraph.Margin.Bottom); } }列表用EditingCommands.ToggleBullets和EditingCommands.ToggleNumbering但 WPF 的列表实现比较弱编号不会自动重排嵌套列表的缩进层级需要手动设置List.MarkerOffset和ListItem.Margin。如果仿 Word 的列表是刚需建议自己封装一个列表管理器监听段落增删并重新计算编号。表格插入需要构造Table元素private void InsertTable(int rows, int cols) { var table new Table(); for (int c 0; c cols; c) table.Columns.Add(new TableColumn { Width new GridLength(100) }); var rowGroup new TableRowGroup(); for (int r 0; r rows; r) { var row new TableRow(); for (int c 0; c cols; c) { var cell new TableCell(new Paragraph(new Run($单元格{r},{c}))); cell.BorderBrush Brushes.Gray; cell.BorderThickness new Thickness(1); row.Cells.Add(cell); } rowGroup.Rows.Add(row); } table.RowGroups.Add(rowGroup); // 插入到当前段落之后 var insertPosition Editor.Selection.Start.Paragraph; if (insertPosition ! null) { Editor.Document.Blocks.InsertAfter(insertPosition, table); } else { Editor.Document.Blocks.Add(table); } }TableColumn.Width设成GridLength(100)是固定列宽Word 的列宽拖动需要监听鼠标事件并动态改这个值。热搜里“word 表格列宽无法拖动”在 WPF 里同样存在因为TableColumn没有内置的拖动交互必须自己实现Thumb拖拽逻辑。3.2 撤销栈为什么你的 CtrlZ 会失效怎么修RichTextBox自带撤销栈但只对通过EditingCommands或用户直接输入的操作生效。如果你用代码直接改FlowDocument的结构比如上面的InsertTable撤销栈不会记录CtrlZ 会跳过这一步。这是血泪经验用户插入表格后按 CtrlZ表格没消失反而把更早的文字输入撤销了。修复方式有两种。一是用Editor.BeginChange()和Editor.EndChange()包裹自定义操作private void InsertTableWithUndo(int rows, int cols) { Editor.BeginChange(); try { // 构造并插入表格的代码 var table BuildTable(rows, cols); Editor.Document.Blocks.Add(table); } finally { Editor.EndChange(); } }BeginChange/EndChange会把中间的所有修改合并成一个撤销单元。注意这两个方法必须成对出现且不能在EndChange之前抛异常否则撤销栈会损坏。二是自己维护一个命令栈每个操作实现Undo/Redo接口但这等于重写 WPF 的撤销系统除非有特殊需求否则不推荐。还有一个坑RichTextBox的撤销栈默认深度是有限的大约 100 步。如果用户长时间编辑早期操作会被丢弃。Document.UndoManager没有公开的深度设置常见做法是定期序列化文档快照自己做一层粗粒度的历史记录。3.3 剪贴板粘贴 HTML、图片和纯文本的差异化处理WPF 的RichTextBox默认粘贴行为很“耿直”从 Word 复制一段带格式的文字粘贴进来会带上大量冗余的FlowDocument属性甚至嵌套表格。从网页复制样式可能全丢或全乱。热搜里“word 宏安全问题”和“typora 转 word”都涉及跨应用粘贴的格式兼容。控制粘贴行为需要监听DataObject.Pasting事件// 在构造函数中挂载 DataObject.AddPastingHandler(Editor, OnPaste); private void OnPaste(object sender, DataObjectPastingEventArgs e) { // 优先处理图片 if (e.SourceDataObject.GetDataPresent(DataFormats.Bitmap)) { var bitmap e.SourceDataObject.GetData(DataFormats.Bitmap) as BitmapSource; if (bitmap ! null) { var image new Image { Source bitmap, Width bitmap.PixelWidth / 2.0 }; var container new InlineUIContainer(image); Editor.Selection.Insert(container); e.CancelCommand(); // 阻止默认粘贴 } return; } // 处理 HTML提取纯文本或做样式清洗 if (e.SourceDataObject.GetDataPresent(DataFormats.Html)) { var html e.SourceDataObject.GetData(DataFormats.Html) as string; // 简单清洗去掉 script/style 标签保留基本格式 var cleaned Regex.Replace(html, (script|style)[^]*.*?/\1, , RegexOptions.Singleline | RegexOptions.IgnoreCase); // 这里可以进一步用 HtmlAgilityPack 解析并转换为 FlowDocument // 简化处理直接粘贴纯文本 var plainText Regex.Replace(cleaned, [^], ); Editor.Selection.Text plainText; e.CancelCommand(); return; } // 纯文本直接放行 }这段代码的逻辑图片粘贴时把BitmapSource包成InlineUIContainer插入避免默认粘贴把图片放到剪贴板缓存里导致文档体积膨胀。HTML 粘贴时先清洗再转纯文本实际项目中可以用HtmlAgilityPack把 HTML 节点映射为Paragraph/Run/Bold等元素但工作量不小。如果只需要“粘贴后格式不乱”直接转纯文本是最稳的方案。3.4 文档序列化XAML 包、自定义 XML 和 RTF 的取舍保存和加载是编辑器的命门。WPF 原生支持TextRange.Save到DataFormats.XamlPackage能把文档和图片一起打包成二进制流// 保存 private void SaveDocument(string path) { var range new TextRange(Editor.Document.ContentStart, Editor.Document.ContentEnd); using (var stream File.Create(path)) { range.Save(stream, DataFormats.XamlPackage); } } // 加载 private void LoadDocument(string path) { var range new TextRange(Editor.Document.ContentStart, Editor.Document.ContentEnd); using (var stream File.OpenRead(path)) { range.Load(stream, DataFormats.XamlPackage); } }XamlPackage的优点是保真度高图片、表格、列表都能完整还原。缺点是文件体积大且只有 WPF 能读其他编辑器打不开。如果要做“导出为 Word”需要走DataFormats.Rtf或引入OpenXML SDK生成.docx。热搜里“c# 生成 word 文档插入变量”和“java 批注 word”都是另一个技术栈的事在 WPF 编辑器里常见做法是编辑态用XamlPackage导出时用RTF或调用Microsoft.Office.Interop.Word做格式转换。RTF 的兼容性最好但 WPF 的 RTF 支持不完整复杂表格和图片可能丢失。如果项目要求“保存后能用 Word 打开且格式基本一致”建议直接上OpenXML SDK把FlowDocument遍历一遍映射为WordprocessingML元素。这条路工作量大但可控性最强。4. 避坑与排查仿 Word 编辑器最容易翻车的 5 个地方4.1 现象加粗按钮状态和实际选区不同步原因EditingCommands.ToggleBold执行后RichTextBox的Selection属性没有触发SelectionChanged事件因为选区范围没变只是属性变了。ViewModel 里的IsBold还是旧值。解决在命令执行后手动调用状态更新。如果用的是ApplicationCommands可以监听CommandManager.Executed事件如果是自定义命令直接在命令的Execute方法末尾调用UpdateSelectionState。更稳妥的做法是监听Editor.TextChanged但TextChanged触发频率太高需要加防抖。4.2 现象插入表格后 CtrlZ 撤销的是文字而不是表格原因代码直接操作Document.Blocks没有走BeginChange/EndChange撤销栈不记录结构变更。解决所有修改FlowDocument结构的代码都必须用BeginChange/EndChange包裹。注意EndChange必须执行建议放在finally块里。另外BeginChange可以嵌套但EndChange次数必须匹配否则撤销栈会错乱。4.3 现象粘贴大图片后文档保存体积暴涨加载变慢原因RichTextBox默认把图片以原始分辨率嵌入XamlPackage一张 4000x3000 的照片可能占十几 MB。多次粘贴后文档轻松上百 MB。解决在Pasting事件里拦截图片先缩放再插入。缩放比例根据显示宽度计算一般编辑器显示宽度不超过 800px按这个宽度等比缩放即可。同时设置BitmapImage.DecodePixelWidth减少内存占用var bitmap e.SourceDataObject.GetData(DataFormats.Bitmap) as BitmapSource; if (bitmap ! null) { var scaled new TransformedBitmap(bitmap, new ScaleTransform(800.0 / bitmap.PixelWidth, 800.0 / bitmap.PixelWidth)); var image new Image { Source scaled }; Editor.Selection.Insert(new InlineUIContainer(image)); e.CancelCommand(); }4.4 现象从 Word 复制的列表粘贴后编号全变成 1原因WPF 的List元素不自动维护编号连续性。从 Word 复制过来的列表每个ListItem的MarkerStyle可能都是Decimal但MarkerOffset和起始编号没有正确映射导致全部显示为 1。解决粘贴后遍历List元素手动重排编号。或者更干脆在Pasting事件里检测到 HTML 列表时不直接粘贴FlowDocument结构而是解析 HTML 的ol/ul标签自己构造List并设置正确的MarkerStyle和StartIndex。WPF 的List有StartIndex属性但只在MarkerStyle为Decimal时生效。4.5 现象编辑器在触摸屏上滚动卡顿笔迹输入延迟原因RichTextBox默认开启SpellCheck触摸滚动时拼写检查线程和 UI 线程争抢资源。另外FlowDocument的布局计算在触摸惯性滚动时频繁触发。解决触摸设备上关闭实时拼写检查改为手动触发设置ScrollViewer.PanningMode为VerticalOnly减少手势识别开销如果笔迹输入是刚需考虑用InkCanvas叠加在RichTextBox上而不是依赖 WPF 的触摸事件。热搜里“wpf 实现 3d 动画看板”和这个场景无关但“wpf 应用程序和 wpf 应用”的区分在这里有体现桌面版 WPF 和 UWP 的触摸栈不同不要混用 API。5. 进阶技巧用附加属性把 RichTextBox 改造成可绑定的编辑器控件5.1 为什么需要附加属性RichTextBox.Document不是依赖属性不能直接绑定。MVVM 模式下ViewModel 想控制文档内容只能通过代码后置或消息机制很别扭。常见做法是写一个附加属性BindableDocument把FlowDocument的变更同步到 ViewModel 的一个字符串或自定义文档对象。public static class RichTextBoxHelper { // 附加属性绑定文档内容 public static readonly DependencyProperty BindableDocumentProperty DependencyProperty.RegisterAttached( BindableDocument, typeof(FlowDocument), typeof(RichTextBoxHelper), new PropertyMetadata(null, OnBindableDocumentChanged)); public static FlowDocument GetBindableDocument(DependencyObject obj) (FlowDocument)obj.GetValue(BindableDocumentProperty); public static void SetBindableDocument(DependencyObject obj, FlowDocument value) obj.SetValue(BindableDocumentProperty, value); private static void OnBindableDocumentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is RichTextBox rtb e.NewValue is FlowDocument doc) { rtb.Document doc; } } }XAML 里这样用RichTextBox local:RichTextBoxHelper.BindableDocument{Binding CurrentDocument} /CurrentDocument是 ViewModel 里的FlowDocument属性。注意FlowDocument本身不是线程安全的且一个实例只能属于一个RichTextBox。如果 ViewModel 里持有FlowDocument切换文档时需要创建新实例不能复用。5.2 文档变更的防抖与脏标记直接监听TextChanged会导致每次按键都触发保存逻辑。需要加防抖private DispatcherTimer _dirtyTimer; private void Editor_TextChanged(object sender, TextChangedEventArgs e) { _dirtyTimer?.Stop(); _dirtyTimer new DispatcherTimer { Interval TimeSpan.FromSeconds(2) }; _dirtyTimer.Tick (s, args) { _dirtyTimer.Stop(); ViewModel.IsDirty true; // 这里可以触发自动保存或更新预览 }; _dirtyTimer.Start(); }防抖间隔设 2 秒是经验值太短会频繁触发太长用户可能来不及保存就崩溃。如果要做自动保存建议再加一层文件锁避免多实例同时写同一个文件。5.3 性能边界多少内容会让 RichTextBox 开始卡实测经验纯文本 5 万字以内RichTextBox输入延迟在可接受范围超过 10 万字光标移动开始掉帧超过 50 万字滚动和输入都有明显卡顿。表格和图片会显著降低这个阈值一个 100 行 10 列的表格就能让布局计算变慢。如果文档规模必然超过这个量级考虑分页加载把文档拆成多个FlowDocument用TabControl或自定义分页控件切换。或者换用第三方的虚拟化编辑器控件但那就偏离“开源代码 demo”的范畴了。5.4 一个具体技巧用TextPointer做精确的插入点定位RichTextBox的CaretPosition返回TextPointer但直接用它插入元素容易出错因为TextPointer在文档结构变化后会失效。正确做法是先判断插入点的上下文private void InsertHyperlink(string url, string text) { var caret Editor.CaretPosition; // 确保插入点在 Paragraph 内 var paragraph caret.Paragraph; if (paragraph null) { // 如果不在段落内先创建一个 paragraph new Paragraph(); Editor.Document.Blocks.Add(paragraph); caret paragraph.ContentStart; } var hyperlink new Hyperlink(new Run(text)) { NavigateUri new Uri(url) }; // 用 TextPointer 插入 caret.InsertTextInRun(); // 确保有 Run 存在 var run caret.Parent as Run; if (run ! null) { run.ContentStart.InsertBefore(hyperlink); } else { paragraph.Inlines.Add(hyperlink); } }这段代码的坑在于TextPointer.InsertBefore要求插入点和目标在同一Run内否则会抛异常。更稳的方式是直接操作Paragraph.Inlines用CaretPosition找到当前Run的索引然后InsertAfter/InsertBefore。如果文档结构复杂建议先序列化当前段落在 XML 层面做插入再反序列化回去。我自己的习惯是任何涉及TextPointer的操作先写一个try-catch包住捕获InvalidOperationException后回退到“在段落末尾插入”。这个后悔药救过我好几次尤其是在用户快速输入时触发自定义命令的场景下。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

ntpwedit 0.7 源码解析:C++ 离线修改 Windows SAM 密码哈希实战

ntpwedit 0.7 源码解析:C++ 离线修改 Windows SAM 密码哈希实战

简介:NTPWEdit 0.7 是一款通过直接修改 SAM 文件来重置或删除本地系统账户密码的开机密码更改工具,本资源为其完整 C 源码包,面向需要研究 Windows 密码机制、二次开发或定制 PE 维护工具的开发者与系统运维人员。压缩包共 85 个文件&#xf…

2026/10/8 23:51:42 阅读更多 →
Java微服务在线教育源码实战:SpringCloud+Vue前后端分离项目拆解

Java微服务在线教育源码实战:SpringCloud+Vue前后端分离项目拆解

简介:这是一套面向Java开发者与在线教育产品研发人员的微服务实战项目源码,聚焦课程、问答、文章三大前台业务与后台运营平台,适合希望掌握SpringCloud分布式架构、前后端分离开发的中高级学习者参考。项目后端采用SpringBoot SpringCloud …

2026/10/8 23:51:42 阅读更多 →
OpenCore 0.6.3 黑苹果引导配置实战:EFI 结构、config.plist 与避坑指南

OpenCore 0.6.3 黑苹果引导配置实战:EFI 结构、config.plist 与避坑指南

简介:OpenCore-0.6.3-RELEASE.zip 面向黑苹果爱好者与需要在非苹果硬件上运行 macOS 的进阶用户,提供一套开源引导加载器的完整发行文件,用于安装、配置并实现 macOS 与 Windows、Linux 的多系统引导。压缩包共 100 个文件,约 3.8…

2026/10/8 23:51:42 阅读更多 →

最新新闻

如何打造无可挑剔的代码品质:从命名到文档的完整检查清单

如何打造无可挑剔的代码品质:从命名到文档的完整检查清单

1. 一个词撬动的品质革命:为什么“impeccable”值得单独拿出来讲第一次看到“impeccable”这个词被单独拎出来当作项目标题,我的反应是:这要么是个极简主义的个人品牌实验,要么是一个对“品质”有执念的人在做一件很较真的事。后来…

2026/10/9 8:00:27 阅读更多 →
深度学习期货交易入门:从CTP接口到数据落库的完整实战

深度学习期货交易入门:从CTP接口到数据落库的完整实战

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

2026/10/9 8:00:27 阅读更多 →
SpringBoot与Android电子书阅读系统全栈项目实战解析

SpringBoot与Android电子书阅读系统全栈项目实战解析

如果你的简历上还缺一个能拿得出手的Java全栈项目,这套基于Java SpringBoot和Android的电子书阅读系统,是一个值得花两周时间认真啃下来的选择。它不是一个PPT项目,而是包含了Android客户端、SpringBoot后端、MySQL数据库的完整可运行系统&am…

2026/10/9 8:00:27 阅读更多 →
image 组件用法

image 组件用法

一、image 组件基础image 是小程序的图片组件,负责把一张图片按指定方式显示在页面里。它支持 JPG、PNG、SVG、WEBP、GIF 等格式,从基础库 2.3.0 起也支持直接使用云文件 ID。它的用法非常简单,只有一个必须关心的属性 src 和一个真正决定效果…

2026/10/9 8:00:27 阅读更多 →
基于3893张图像的手套与徒手检测:YOLO训练调参及产线落地实战

基于3893张图像的手套与徒手检测:YOLO训练调参及产线落地实战

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

2026/10/9 8:00:27 阅读更多 →
『项目管理精要』第 7 章 团队演进与冲突解决:从单打独斗到带队攻坚

『项目管理精要』第 7 章 团队演进与冲突解决:从单打独斗到带队攻坚

从一名卓越的个人贡献者(Individual Contributor, IC)成长为优秀的技术主管(TL),最大挑战在于“如何带出一支高效能的自组织团队”。在平衡矩阵或弱矩阵组织中,成员往往来自不同的职能部门,兼顾多个项目,团队容易陷入推诿扯皮或效率低下的泥潭。TL 需要理解塔克曼团队演…

2026/10/9 7:59:27 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 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/8 21:13:17 阅读更多 →
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/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练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/9 6:17:20 阅读更多 →