[{"content":"最近带了两个实习生，都是老板朋友家的小孩，因此我就教他们使用两个软件 OpenCode 和 Obsidian。我的本意是希望他们可以拥抱 AI 时代，并养成记笔记的习惯。在带他们的过程中，我反复提到了要「自己思考」。这是因为一旦使用了 AI，就会产生一种我已经会了的错觉。\n我让他们分别做了一个三维模型的显示软件和一个少数派的爬虫软件，他们使用 OpenCode 很快就完成了，并把作品给我看。随即我问了他们一些关于项目的细节问题，结果他们一个也没有回答上来。我意识到他们只是学会了使用 OpenCode，而不是真的做了这个项目，即在这整个过程中，他们没有沉淀出自己的经验。\n为什么我认为「思考」是很重要的？ 在学校里，我们面对的都是具体的事务，过程和目标都在老师的教案上写着。但是到了社会，我发现很多时候目标是模糊的，过程是模糊的。在工作中，有时候或许连你的领导都不知道要做什么，又或许今天定下的方案明天就废弃了，所有人都要从头来过。很多人会无法适应这种环境，觉得非常迷茫，不知道自己在做什么。\n我对这类事情的看法是，他们没有学会自己思考。他们仍然是按照学校的那一套规矩在做事情，期望有人给他们布置具体的目标和正确的方向，而他们只是听从安排。之前我看「大秦帝国」的时候，张仪有这么一句话：秦人不畏死却不知活。这句话放在他们身上也很适用，他们知道如何为别人做事，而不知道如何为自己做事。他们只盯着公司安排的任务干活，但是没有思考任务本身的意义，没有思考这个任务可以给自己带来什么，只盯着工作中需要使用到的技术栈，而对市场内的其他技术栈一无所知。\n人人都知道思考很重要，这是车轱辘话，正确但是没有营养。实际上，我们会碰到两个问题：\n很少有人会复盘自己做的事情，思考和沉淀经验教训 很多人不知道如何思考，从哪些方向思考 这两个问题其实和这篇文章是相悖的。如果我现在提出一套通用的思考框架，那看到这篇文章的人就再次陷入了我告诉他们答案的误区，而不会自己思考。首先我并没有能力提出通用的思考框架，更多的是具体问题具体分析；其次我的思考方式和考虑的问题并不适合其他人，每个人都有各自偏爱的方向。去思考如何思考也是一种思考。\n除了思考在工作中也需要许多其他的能力，如主观能动性、沟通技巧等。而我认为只要你有了思考的习惯，其他的能力都会慢慢培养起来的。没有人能永远告诉你要学什么、要做什么，你必须学会自己思考这些内容，思考自己学习的目的，思考自己未来想做什么，思考怎么让自己思考。\n","date":"2026-08-11T16:26:52+08:00","image":"https://zeroszhang.github.io/p/%E5%85%B3%E4%BA%8E%E6%80%9D%E8%80%83%E7%9A%84%E5%BF%85%E8%A6%81%E6%80%A7/Title.jpg","permalink":"https://zeroszhang.github.io/p/%E5%85%B3%E4%BA%8E%E6%80%9D%E8%80%83%E7%9A%84%E5%BF%85%E8%A6%81%E6%80%A7/","title":"关于思考的必要性"},{"content":"这篇文章记录是，是最近我使用 AI 编程实现的几个软件，用于解决我平时遇到的问题。\n或许你也有过，做一件事情的时候脑子里会思考，有些地方不对，太繁琐了。但是又因为学习成本太高或者精力不足，使得自己很难改变什么。\n在 AI 时代下，我开始意识到 AI 的价值正是帮助实现心里的想法。\n博客发布 近期由于本地 AI Agent 的爆火，我将我的笔记系统从 wolai 导出到了 Obsidian 中了。粗略的算了一下，自从我 2018 年开始养成记录的习惯后，前后写了 4000 多篇笔记了。\n我的博客是去年才搭建的，但是更新频率并不多。其中一条原因是我将博客视作一个发布界面，并非每条笔记我都要发布出来。另一个很现实的原因是，我使用 hugo 编译静态网站，但是太难用了。\n基于这个原因，我使用 KimiCode 做了一个辅助博客发布的软件。\n这个软件有三个功能：\n新建文章 本地预览文章 构建并发布博客 希望我能使用这个工具，帮助我增加更新博客的频率。\n每日阅读 过去我一直使用 Folo 这个软件，订阅我常看的网站、博客，并且我会在笔记系统中记录我认为有价值的文章，并反复阅读。这就导致了一个问题：有一些过去我没有记录的内容，之后就如泥牛入海，再也找不到了。\n受到最近爆火的卡帕西的知识库的启发，以及最近 Folo 发布了自己 cli，我做了一个脚本，用于将我在 Folo 下的未读文章以 Markdown 的格式保存到本地。\n简单来说，首先使用 Folo 的 cli 获取未读文章的原始网络地址，然后根据原始网络地址对应的网站保存为本地的 html，最后根据 html 的来源使用不同的策略解析成对应的 markdown 文件。这些步骤我都使用 KimiCode 实现了一个 Python 脚本来运行。\n我会使用 KimiCode 去总结当天的 markdown 文件，告诉这些文章大概讲了什么内容，遇到我感兴趣的内容，再去读原文。最重要的是，做完这些后，我会按天将整个文件夹放在 Obsidian 中进行存档。这样在我后面想起来一篇文章但是找不到时，我就可以让 AI 去这个文件夹下寻找。\n文档翻译 Halcon 我在工作中经常会使用到的软件，功能十分强大，唯一的缺点是，文档和手册都是英文的，看起来太痛苦了。\n之前学习的时候，搭配翻译软件也能看个七七八八，但是过了一段时间之后，记忆会逐渐淡忘。为此我在 wolai 中曾经做过一个汉化的库。\n很遗憾的是，后来我意识到这件事太困难，并且效率太低了。\n现在 AI 的大环境下，我使用 ClaudeCode + DeepSeek 实现了 Halcon 本地算子的翻译，并将其放在了 Obsidian 中。\n这样做有两点好处：\n所有的内容都是基于本地的 html 文档翻译过来的，真实性有了保证 转换成 markdown 之后，对于文档里我认为不足的地方可以直接修改 除此以外，为了让我的同事们都可以用上中文的 Halcon 手册，我又回过头来将其编译成了 html。因为我的同事们并不使用 Obsidian，因此直接将 markdown 发给他们，还得下载 Obsidian 并且要保持和我的配置类似。为了简单一点，直接编译成 html，使用浏览器打开更简单一点。\nObsidian 插件 正如我上面所说，我将笔记系统从 wolai 迁移到了 Obsidian 中。\n我好多年前就知道了 Obsidian 这个软件，但是因为其个性化能力太强，需要频繁的折腾和学习，我担心会影响我记笔记的积极性，最终还是选择了开箱即用的 wolai。\n但是在 AI 时代下，wolai 出现了致命缺陷——数据存在服务器上，我没法喂给 AI 使用。在经过了几天的纠结之后，我还是选择了放弃 wolai，使用 Obsidian。\nObsidian 最强大的地方在于他的插件社区，虽然这也是我当初放弃的原因，因为插件太多了，每一个插件都要去学习，尤其是 Templater、DataView、Button 这几个插件，不但配置复杂，还要去学习 JS 语法。\n但是现在有了 AI，完全不需要去学了。我直接将这些插件的官方文档喂给 AI 做成了 Skill，然后使用这个 Skill 去实现我想要的功能，简单易用，并且自由度很高。\n工作上的小软件 AI 在我工作上的帮助就更多了，也正是由于很多，所以这几只能挑几个进行说明。\n我使用 AI 优化了 ZerosSVN 软件，现在这个软件使用更简单了，一键即可实现同步、提交、冲突解决等所有步骤。\n我用 AI 做了一个线扫描的仿真软件，加载对应的产品模型，就可以获得线扫描数据。这可以帮助我在测试软件时，提供一些数据。\n总结 这几个软件没有一个是需要大量的学习才能做出来的，全都是我遇到了实际问题，然后去思考该如何解决问题，最后使用 AI 大约几个小时就能做出来。\n我一直认为自己不是一个顶尖的程序员，但我始终认为自己是一个很好的产品经理。\nAI 使得我的 90% 技能，价值变为 0，但使得剩下的 10% 技能，价值增长了 1000 倍。每个人在 AI 面前，都需要重新调整自己的技能。\n","date":"2026-05-19T15:26:23+08:00","image":"https://zeroszhang.github.io/p/ai%E7%BC%96%E7%A8%8B%E4%B8%8B%E7%9A%84%E4%BA%A7%E7%89%A92026%E5%B9%B45%E6%9C%88/Title.jpg","permalink":"https://zeroszhang.github.io/p/ai%E7%BC%96%E7%A8%8B%E4%B8%8B%E7%9A%84%E4%BA%A7%E7%89%A92026%E5%B9%B45%E6%9C%88/","title":"AI编程下的产物2026年5月"},{"content":" 🩰我于2016年参加工作，至今2026年已有10年，这期间我积累的最大的财富就是我的笔记系统。\n工作遇到的困难 十年的工作中，我感受最深的就是「时间碎片化」——碎片化的时间给我带来的是似曾相识的无力感。我明明解决过这个问题，但是却一遍遍的重新踩坑。我的工作经验没有积累成资产，而是像沙子一样，每次努力抓一把，但是随着时间的流逝，最后都从指缝溜走。\n我曾经看着代码抛出一个我清晰记得碰到过的异常，但是死活想不起来之前是如何解决的 我曾经被老板问到这个版本的软件有哪些改进，而我却没法给出在调试时的对比 我曾经看着自己上周自己没写完的代码，但是完全不知道自己接下来要做什么 那一刻我深刻的意识到：我需要一套系统，让我的经验可以保存、可以检索、可以迭代。\n笔记系统的功能 那么我到底需要一套什么样的系统来帮助自己？首先我需要明确自己的需求：\n记录自己做过的工作 记录学习过的知识 记录自己曾经犯过的错误和解决方案 这些需求总的来说就是「记录和总结」。高中时期经常听老师念叨一句话——“好记性不如烂笔头”，那时候抄写老师上课的板书，会将自己的理解当作评价写在边上，这就是一种笔记系统。\n建立笔记系统的原则 笔记系统必须同时包含「输入和输出」，输入是你记录的内容，输出是你对内容的总结。\n一个好的笔记系统，必须遵循这三个原则——存得住、找得着、用得上。\n存得住：确保有价值的的信息不会丢失；否则会依赖记忆力，非常容易出错 找得到：当你需要的时候可以快速定位；否则会有信息黑洞，越记录越焦虑 用得上：去掉没用的内容，只保留核心；否则需要花时间重新学习总结 笔记系统的误区 🍡 笔记系统不是收藏夹、素材库\n这种错误表现为使用剪藏插件疯狂收藏，但是从来不打开。会导致需要的时候找不到，找到了不过是把曾经看过的东西再看一遍。保存≠学会，收藏是输入，学会是输出。\n🌝 笔记系统不是复制粘贴\n这种错误表现为笔记里大段的原文，没有自己的思考，复制别人的模板，但是从未具体问题具体分析。这是一种拿来主义，所有的经验必须自己去实践才可以获得。近期这种错误表现为使用AI总结内容。\n🎞️ 笔记系统不是博客\n这种错误表现为花了大量的时间美化排版、配色。博客热衷于表达，而非使用。\n📄 不要陷入完美主义\n这种错误表现为对一篇笔记反复修改，每个笔记都要标签齐全，链接完善，记录的内容也要尽善尽美。记笔记不是编写一本书，笔记本身就是零碎的。\n🩺 不要陷入工具主义\n这种错误表现为频繁更换笔记软件，经常比较不同软件的高级技巧，但是却使用不好基础功能。不要把搭建系统本身当作目标，搭建系统只是服务工作的手段。\n如何用好笔记系统 🦚 养成随时记录的习惯\n灵感一闪而过，如果不能立马记录，可能转头就忘。我想表达的重点是「养成记录的习惯」，而不是去追求一键记录。这种记录方式可以只写一句话，一个关键字，不用追求完美记录，等后续再进行整理。\n🔔 要对笔记进行分类\n笔记分类是为了可预测的定位路径，在需要的时候知道去哪里找。分类只需要分几个大类就行，没必要非常细化。虽然搜索功能可以很方便的定位，但是你仍然需要知道笔记大概在哪里。\n🍊 经常翻看自己的笔记\n笔记的价值在于复用，定期回顾才能持续迭代。所谓温故而知新，在不同的时间看同一篇笔记会产生不同的感悟。审视过去的自己，也是一种成长。\n我的实践 接下来我将基于上面的原则，讲述我的笔记系统实践。\n🥘 我使用的软件——wolai 我使用wolai来记录笔记，有以下几个理由：\n支持斜杠命令、Markdown标记 笔记之间相互链接的功能做的比较方便 支持Latex数学公式截图识别 笔记存在云端，不用折腾同步功能，支持导出 被阿里巴巴收购了，不太可能随时暴毙 当然这个软件也有一些缺点：\n2021年曾经出过一件事，软件团队检测用户笔记内容，对敏感或擦边的内容进行和谐处理。这也是所有云笔记的缺点，但是我个人没有类似的烦恼。 几乎没有可以自定义的功能，作为一个笔记软件竟然没法修改字体！ 2025年下半年开始更新频率显著降低，几乎没有新功能出来了。 绘图功能做的不好，只提供了思维导图，绘制流程图要么使用Mermaid要么在draw.io画完之后截图粘贴——Mermaid不好调整，draw.io截图不好修改。绘图方面做的最好的是飞书文档。 市面上的一些其他软件我也有试用过，这里就讲讲我不选他们的理由：\nnotion：可以说wolai是仿照notion实现的软件，notion在功能上比wolai强大很多。我最终没有选择notion主要有两个原因——网络问题和本地化问题。网络问题不多说，网上很多人讲。本地化问题是我认为wolai做的比较好的方面，比如/dmpd输入代码片段，/hngs输入行内公式，实际上输入/dm和/hn就可以了，我还是更习惯使用拼音首字母。 obsidian：社区插件丰富，个性化程度高。笔记本地化存储，数据安全。我没有选择obsidian的原因也正是由于这两个特点：第一是个性化程度太高了，太折腾了，会引诱我不断去折腾插件。第二是手机端的问题，obsidian手机端做的没有wolai好用 飞书：飞书文档是作为一个功能模块放在飞书里面的，除了文档功能飞书的其他功能也很好用，我们公司就使用飞书办公。飞书的文档不能导出为markdown格式，只能导出为word格式，有浏览器插件提供导出markdown的功能。最核心的一点是如果我要更换笔记软件，我必须一篇一篇的导出，不能做到全部导出，而wolai提供了这个功能，虽然这功能做的一般。 语雀：语雀也是阿里系的笔记软件，我也不知道为什么阿里要整这么多笔记软件。语雀更适合用来作为博客，而不是用来做笔记。语雀的文档系统和飞书一样都是知识库，也不能全部导出。另外语雀和飞书的笔记链接的功能做的都没有wolai好，可能知识库的定位就是用来展示的。 我还使用过印象笔记，思源笔记，有道云文档，logseq，Typora，VSCode，OneNote，为知笔记，trilium等，太多了也没法全部点评。总之，正如我上面提过的，记笔记的目的是服务于生活，而不是建立系统。各位读者可以自行试用或者看网上一些笔记软件的评测，选择合适自己的笔记软件。千万千万千万要记得不要陷入工具主义陷阱。\n🍠 我如何实践「存得住」？ 一般来说我都会在「临时缓存」中进行记录零碎的想法和整理笔记，整理完后放到「主题记录」中对应的页面中。所以「临时缓存」对我来说就是笔记的入口，所以在这个页面，我做了以下工作：\n创建一个「待办事项」页面，任何笔记中我认为没有完成的部分都会引用这个页面，这样我进入到这个页面，就能看到自己给自己留下的任务 创建一个「反复阅读」页面，任何我认为近期需要复习的内容，都会在这个页面添加引用。 创建一个「自动按钮」用于快速的添加页面，简化我的记录操作。 创建一个以月份命名的页面，用于写日志。这个页面会以流水账的形式记录工作事项，主要是为了记录自己过去一段时间做了什么，这样可以督促自己思考。 wolai还提供一个微信小程序，给微信小程序发送链接或者文字，就会转存到固定的页面中，我设置了「临时缓存」。\n我习惯使用单一入口记笔记，而不是在对应的页面记笔记。一方面是为了更快速的记录，另一方面也是为了可以看到自己有哪些还没有整理过的笔记。所有的一切都是为了「记得住」。\n🍉 我如何实践「找得到」？ 我并没有采用常见的如PARA、卡片、数字编码、标签等分类方法，我是完全按照我自己的使用习惯进行分类的，这也是我说的一定要自己去实践，不要直接使用别人的模板，模板只是作为一个参考。\n我的笔记主要分了四个大类：\n临时缓存：这个页面提供的是收集箱的功能，我平时在网上看到的好的文档，临时的想法，随手的记录都会丢到这个里面去，然后有时间就整理。 时光记录：这个页面提供日记的功能，里面的文档以日期为标题，仅用来记录我生活中的一些经历，感悟等。我希望等我老了的时候回看自己的日记，会发出当初我竟然还这样想过的感叹。 主题记录：这个页面是笔记的核心页面，可以说这个才是笔记系统的核心内容。 「备忘录」：记录我自己和我爸妈的账号密码，记录家里的宽带账号密码，记录房屋租赁的收入与花销，记录汽车保险信息，医疗保险信息等生活信息 「零碎知识」：记录我在互联网上学到的一些知识，内部包含三个模块——what、how、why。这个页面里的内容使用频率不高，只是为了增加自己的知识面。 「阅读记录」：包含书籍阅读笔记、博客阅读笔记和其他文章阅读笔记 「电子数码」：比如机械硬盘的原理、固态硬盘的原理、路由器和交换机的区别、常用的CPU 「软件」：我是一个很喜欢尝试新软件的人，所以我单独给了一个页面用于记录自己曾经用过的软件，比如这个软件是做什么的，有什么优点，什么缺点。 「游戏」：我会记录一些游戏的攻略，比如泰拉瑞亚的流程，星露谷mod的安装等内容 「教育相关」：去年年底有了自己的孩子，于是平时看到的一些教育相关的内容，都会放到这个里面 「自动化」：我本人从事自动化设备行业，这个页面记录的是工作中的内容，比如相机如何选型，某某品牌的运动控制卡如何操作，GRR的计算方式，半导体先进封装工艺等 「编程知识」：记录和编程有关的知识，比如Python开发，Vue开发，Andriod开发，OpenCV的使用，红黑树和二叉树的区别等 「CSharp语言」：我的工作主要是使用C#语言，因此单独给了一个页面，记录Winform和WPF相关的知识，功能案例，优化技巧、异常处理等 「数学推导」：包含编程中使用到的数学知识，比如直线拟合、三维旋转、射线与包围盒相交检测等 「AI」：最近AI很火，所以单独开了一个页面记录相关的内容 「公司管理」：包含如何跟同事沟通、如何解决团队分歧、招聘时关心的问题等内容 「成长」：会记录可以提升自己思维的内容，比如工具祛媚，创作还是消费，效率成瘾等，我希望自己可以成为更好的人。 笔记分类其实没有统一的格式，我没有模板分类的原因是因为，我认为他们都太全面的，而我不可能做到那么全面。我只需要把我生活工作中的重要内容单独提取出来即可。\n「归档」：这个页面会存放剪藏的文章，我正在考虑是不是要将其删除，因为在阅读后我已经将内容总结到我的笔记中了。这些原来的剪藏内容，我不但再也没有看过，反而会增加我搜索的难度。 🥑 我如何实践「用得上」？ 在笔记的编写上，我也一些习惯可以分享。\n明确的命名。比如我在一些页面明确what-why-how，以让我快速知道这个笔记里的内容。 尽量少的标题层级，我一般只会使用二级标题和三级标题。标题层级如果太复杂，会让笔记显得很乱。 持续迭代笔记，相同主题的笔记合并为一个，相关主题的笔记相互链接。 在保证内容清晰的前提下，使内容尽可能简短。你的笔记不需要给别人看，因此你要记录关键信息，让自己看得懂就行。 尽量自己手动记笔记，AI只提供辅助。只有自己记录的内容才会记忆深刻，AI总结然后复制粘贴后的内容很容易忘记。 总结 这篇文章写到这里，还是有很多细节没有提到。我原本应该添加更多的截图，以展示我是如何做的，但是转念一想，又觉得似乎我给出的经验，也是一种模板。我的模板对别人可能并没有什么用，只要保持上文提到的三个原则——存得住、找得到、用得上，都是适合自己的笔记系统。\n","date":"2026-03-30T16:17:46+08:00","image":"https://zeroszhang.github.io/p/%E5%BB%BA%E7%AB%8B%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F/title.jpg","permalink":"https://zeroszhang.github.io/p/%E5%BB%BA%E7%AB%8B%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F/","title":"建立笔记系统"},{"content":" 🧋官方地址：https://github.com/wmjordan/Codist\n对C#语法提供高亮显示 对于该功能，我最喜欢的是在「工具-配置Codist高级语法样式」提供的界面，简化了对高亮方案的调整。\n对注释的高亮显示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // +++ Head 01 // ++ Head 01 // + Head 01 // - head 02 // -- head 02 // --- head 02 // # Notice // ! Important // ? Question // x Remove // todo 测试 // undone 测试 // note 测试 // hack 测试 对xaml语言的高亮 快速信息增强 「快速信息」指的是鼠标悬停在C#代码时显示的工具提示。\n此处对该界面的配置功能进行解释：\n「选择信息」：勾选后显示所选区域的字符数和行数（如果跨行）。 「颜色信息」：勾选后可以预览颜色值 C#强化代码提示 该功能是对快速信息增强功能的详细设置，在显示C#的快速信息时，提供更多的信息。\n可以在选项界面对需要显示的内容进行配置。\n导航栏增强 导航栏位于代码编辑器窗口顶部，它会覆盖原有的导航栏。导航栏同时适用于C# 代码文档和Markdown文档。\n如果搜索框中的第一个字符是大写字母，则搜索区分大小写 ；否则，搜索不区分大小写。\n导航栏可以在选项页面进行配置：\n「语法细节」：勾选后还会额外显示函数调用的层级，如FindAll在ConvertAll中被调用 「符号代码提示」：勾选后鼠标悬停在导航栏的节点上时，会显示额外信息 「突出显示语法范围」：勾选后鼠标悬停在导航栏的节点上时，编辑器会高亮显示该节点的范围 「区域」：勾选后导航栏将显示#region名称。如果在region名称中添加了非字母的字符，比如#region [====== private methods ======]可以勾选「不显示#region名称的非字母字符」这样就只会显示字母部分private methods 智能工具条 智能工具条是一个跟随鼠标的上下文感知工具栏。当你选择文本或者双击shift键时会出现。\n智能工具条通常有两行。第一行包含是通用的文本编辑命令，第二行会根据内容的类型变化。\n智能工具条上的每个按钮通常都有多种功能。「左键单击」「右键单击」「Ctrl+单击」和「Shift+单击」会触发不同的命令，参考按钮的提示。\n该功能可以在选项界面进行配置。\n转到定义 和F12功能相同，我习惯使用F12，所以用不太上。\n分析 使用「分析-列出成员」可以快速查看颜色类中的定义，比如SystemColors、Colors、Brushes。\n标记 对代码中的变量进行标记。不能标记整行，智能标记某个词。可以在对C#语法提供高亮显示中进行配置。\n滚动条标记 滚动条标记会在垂直滚动条上为一些语法元素绘制额外的形状，如下图中的右侧所示。可以在选项页面更改配置。\n自动更改版本号 Codist可以在生成项目之前自动更改输出程序集的版本号，选中项目-右键-自动生成版本号设置。\n显示增强 可以对Visual Studio的界面显示进行优化处理。\n自动配对标点符号 Codist可以在输入时，自动为选定内容配对标点符号。\n这个功能指的是，选中文本后，输入\u0026quot;可以使用\u0026quot;包围文本，转化成字符串。\n如果关闭这个功能，输入字符会替换所选的内容，而不是使用符号包围内容。\n额外功能 在「生成」菜单中添加了额外的菜单命令：\n","date":"2026-03-26T10:05:10+08:00","image":"https://zeroszhang.github.io/p/codist%E6%8F%92%E4%BB%B6%E5%8A%9F%E8%83%BD/Title.jpg","permalink":"https://zeroszhang.github.io/p/codist%E6%8F%92%E4%BB%B6%E5%8A%9F%E8%83%BD/","title":"Codist插件功能"},{"content":"碰到的问题 随着公司项目越来越多，在项目的维护方面，我们碰到了如下问题：\n多人参与同一个项目，文件相互不同步，需要频繁的使用公共盘共享文件 每个人都有各自对于项目文件的命名方式和存放方式，在员工离职后找不到对应的项目文件 同一个项目在每个电脑上存在不同的版本，想找到对应的版本存在困难 员工的电脑不存在备份机制，如果硬盘坏了，则项目文件会丢失 解决方案 基于上面的问题点，需要实现如下的功能：\n同一项目的命名方式和文档结构 合并不同员工之间的文件，统一管理，支持同步 项目文件的版本管理和备份 我大概的思路是使用 SubVersion 软件进行管理。SubVersion(SVN) 是一款开源的版本控制系统，用于管理文件和目录的变更历史。和 Git 不同，SVN 使用集中式的文件管理，依赖于服务器。\n在服务端，我在公司的服务器上安装了 VirsualSVN，作为 SVN 的服务器。社区版，白嫖的。\n在客户端，我首先尝试了 TortoiseSVN，功能确实可以满足，但是相对来说，操作有点复杂，非程序员学习起来还是需要成本。最严重的一个问题点在于，在 Windows 11 下，TortoiseSVN 的右键菜单项，在子菜单里，使用起来很不方便。\n虽然我使用 Nilesoft Shell 解决了。\n于是我考虑自己实现一个没有学习成本，操作比较简单的项目助手软件。SVN 相关的操作我使用开源的 SharpSVN 库，这个库没有文档，只有代码内的 xml 助手。\n实现思路 我和公司的小伙伴们一起整理了目前所有的项目资料，合并到一个文件夹中。并且在 SVN 中创建一个共同的仓库来管理这些文件夹。\n之所以不是每一个项目一个 SVN 仓库，是为了上传的时候简单点。\n每个项目修改为 “年份_客户_项目名” 的方式进行命名。如下所示：\n软件的界面大致如下所示：\n提供了 SVN 的 Update，Commit 等主要功能，支持项目子文件夹的同步 提供了登录账号，可以在 VirsualSVN 中设置不同账号的权限 提供软件在局域网内的检查更新的功能 提供搜索和排序的功能 ","date":"2025-06-18T17:17:04+08:00","image":"https://zeroszhang.github.io/p/zerossvn%E9%A1%B9%E7%9B%AE%E5%8A%A9%E6%89%8B/title.jpg","permalink":"https://zeroszhang.github.io/p/zerossvn%E9%A1%B9%E7%9B%AE%E5%8A%A9%E6%89%8B/","title":"ZerosSVN项目助手"},{"content":"先进封装 🦪https://www.bilibili.com/video/BV1Yu411c7ic\n所谓封装，就是给芯片加壳后再连接电路。\n传统的封装 半导体的后道工艺通常包含以下内容：\n而本文会着重解释键合和封装的工艺。传统的键合是先进行芯片键合，再进行引线键合，然后套一层壳。\n芯片键合——Die Bonding 引线键合——Wire Bonding 倒装芯片键合——Filp Chip Bonding 🦪 传统封装的缺点：\n引线框架比较大——芯片体积大 金属引线比较长——信号传输耗时长 封装的发展 裸片贴装——引线键合 倒片封装——焊球/凸点 晶圆级封装——RDL 重布线层 2.5D/3D 封装——TSV 硅通孔技术，chiplet 封装技术 🦪 每一代技术之间的本质区别，就是芯片和电路之间连接方式的区别\n倒片封装 芯片电路层朝下，通过金属球将芯片与电路连接，有效减少了芯片的体积，提升了传输速率。\n需要用到曝光，刻蚀，沉积等工艺。\n晶圆级封装 这种叫做扇入型封装。该封装方式的缺点在于芯片的保护性不强，且可能会导致后续发生变形。\n这种方式叫做扇出型封装，在扇入的基础上增加一层保护壳。\n2.5D/3D 封装 将两个芯片放在同一块硅中介层上，再将其放在 PCB 板上，作为一个完整的芯片。\n这种方式的做法是可以有效的增加两块芯片之间的通信效率。\n3D 封装去除了硅中介层，将芯片与芯片直接相连。\n3D 封装依赖于 TSV 硅通孔技术，即在硅上打通孔，然后在通孔上填充金属材料，这样就可以把芯片一层一层的串联起来。\nChiplet 芯粒：一种按照功能对现有逻辑芯片进行拆分并使用硅通孔堆叠实现互联的技术。\n","date":"2025-05-24T19:50:14+08:00","image":"https://zeroszhang.github.io/p/%E5%85%88%E8%BF%9B%E5%B0%81%E8%A3%85/Title.jpg","permalink":"https://zeroszhang.github.io/p/%E5%85%88%E8%BF%9B%E5%B0%81%E8%A3%85/","title":"先进封装"},{"content":"芯片键合（Die Bond） 参考：https://blog.csdn.net/qq_46675545/article/details/128050411?spm=1001.2014.3001.5502\n🦪芯片键合工艺在划片工艺之后将从晶圆上切割的芯片黏贴在封装基板（引线框架或印刷电路板）上，来实现芯片与外部之间的电连接。\n键合工艺可分为传统方法和先进方法两种类型。传统方法采用芯片键合Die Bonding和引线键合Wire Bonding，而先进方法则采用 IBM 于 60 年代后期开发的倒装芯片键合Flip Chip Bonding技术。倒装芯片键合技术将芯片键合与引线键合相结合，并通过在芯片焊盘上形成凸块Bump的方式将芯片和基板连接起来。\n芯片拾取与放置Pick \u0026amp; Place 逐个移除附着在切割胶带上数百个芯片的过程称为“拾取Pick”。使用柱塞从晶圆上拾取合格芯片并将其放置在封装基板表面的过程称为“放置Place”。这两项任务合称为“拾取与放置Pick\u0026amp;Place”，均在固晶机（用于芯片键合的装置）上完成。完成对所有合格芯片的芯片键合之后，未移除的不合格芯片将留在切割胶带上，并在框架回收时全部丢弃。在这个过程中，将通过在映射表（Mapping图）中输入晶圆测试结果（合格/不合格）的方式对合格芯片进行分类。\n","date":"2025-05-24T19:39:45+08:00","image":"https://zeroszhang.github.io/p/%E8%8A%AF%E7%89%87%E9%94%AE%E5%90%88/Title.jpg","permalink":"https://zeroszhang.github.io/p/%E8%8A%AF%E7%89%87%E9%94%AE%E5%90%88/","title":"芯片键合"},{"content":"红黑树诞生的背景 普通的二叉搜索树在添加有序数据（递增或者递减）的时候，所有的节点都会在根节点的右侧或者左侧，此时普通的二叉树就退化成链表，操作的时间复杂组退化成了$O(N)$。\n于是就有了平衡二叉树（AVL 树）。平衡二叉树通过平衡因子来限制树的解构——任意节点的子树的高度差都小于等于 1。将查询效率优化为了$\\log _{2} n$。\nAVL 树作为严格平衡的二叉树，就需要频繁的通过旋转操作来保持平衡，而旋转操作是比较耗时的，导致了维护这种高度平衡所付出的代价比从中获得的收益还大，因此只适用于插入删除次数较少，但是查找多的情况。\n在上面的大背景下，诞生了红黑树，即使在最坏的情况下，也可以在$ \\log _{2} n$时间内实现插入/删除/查找操作。\n红黑树是一个弱平衡二叉树，相比于严格平衡的 AVL 树，每次树的结构发生改变需要调整时，所需要的转换次数更少，因此对于插入和删除操作的效率更高。\n红黑属性的意义 为了确保红黑树的弱平衡属性，要求没有任何一条路径比其他路径长出两倍。因此在每个节点上增加了颜色属性——红或者黑。\n红黑属性通过颜色规则来保持树的平衡，减少旋转操作。每次改变了树的结构（插入/删除操作）之后，最多只需要两次旋转操作即可完成树的平衡。\n红黑树的性质 红黑树有五条性质，记住后面两条就行：\n每个节点非红即黑 根节点是黑的 每个叶节点（树尾端 NULL 节点）都是黑的 如果一个节点是红的,那么它的两儿子都是黑的1 任意节点到每个叶子节点的所有路径都包含相同数目的黑节点 节点的定义 红黑树的着色和旋转 在插入/删除节点的时候，会破坏红黑树的性质，因此需要调整红黑树的结构，以满足上述性质。总共包含三种调整的操作——着色/左旋/右旋。\n着色指的是将红色节点变为黑色节点，或者黑色节点变为红色节点。\n左旋操作如下所示：\n右旋操作如下所示：\n红黑树中的红黑属性并非唯一 红黑树的颜色属性情况并非只有唯一解，只要保证满足红黑树性质即可。如下所示，在插入 101 后删除 101，红黑树还是原来的红黑树，但是颜色属性变化了。\n红黑树的插入操作 这里有一个规则，新插入的节点一定是红色的。因为红色节点可能不会影响平衡2，但是黑色节点一定会影响树的平衡3。默认插入红色节点可以减少后续操作。\n红黑树的插入操作分为四种情况：\n🦪以下的「父节点」「叔叔节点」「祖父节点」都是插入新节点后，调整树结构前的状态（图 2 中）\n父节点为黑 🧋 直接插入新元素，不需要调整树的结构。\n父节点为红色，叔叔节点为红色 🧋「父节点」和「叔叔节点」变黑，「祖父节点」变红，递归检查祖父节点是否引发新的冲突。\n如图 1，插入节点 120。父节点是 110，叔叔节点是 90，符合该情况。因此将父节点 110 和叔叔节点 90 变黑，祖父节点 100 变红。引发性质 2 冲突，因此将祖父节点 100 变黑。\n父节点为红色，叔叔节点为黑色，且父子同侧（LL/RR 型） 🧋左左型（LL）：右旋「祖父节点」。「父节点」变黑，「祖父节点」变红。\n🧋右右型（RR）：左旋「祖父节点」。「父节点」变黑，「祖父节点」变红。\n例1：插入节点 70。父节点 80 为红色，叔叔节点 null 为黑色，且父节点 80 和目标节点 70 都是左子节点，为 LL 型。因此对祖父节点 90 进行右旋。父节点 80 变黑，祖父节点 90 变红。\n例2：插入节点 97。父节点 95 为红色，叔叔节点 null 为黑色，且父节点 95 和目标节点 97 都是右子节点，为 RR 型。因此对祖父节点 90 进行右旋。父节点 95 变黑，祖父节点 90 变红。\n父节点为红色，叔叔节点为黑色，且父子异侧（LR/RL 型） 🧋左右型（LR）：先左旋「父节点」，再右旋「祖父节点」。「目标节点」变黑，「祖父节点」变红4。\n🧋右左型（RL）：先右旋「父节点」，再左旋「祖父节点」。「目标节点」变黑，「祖父节点」变红5。\n例1：插入节点 85。父节点 80 为红色，叔叔节点 null 为黑色，且父节点 80 是左子节点，目标节点 85 是右子节点，为 LR 型。因此先对父节点 80 进行左旋，再对祖父节点 90 进行右旋。目标节点 85 变黑，祖父节点 90 变红。\n例2：插入节点 92。父节点 95 为红色，叔叔节点 null 为黑色，且父节点 95 是右子节点，目标节点 92 是左子节点，为 RL 型。因此先对父节点 95 进行右旋，再对祖父节点 90 进行左旋。目标节点 92 变黑，祖父节点 90 变红。\n红黑树的删除操作 🧋「当前节点」指的是删除了「目标节点」后，替换了「目标节点」位置的节点。\n删除单个红节点 🧋 单个红节点指的是左右子节点都是 null 的节点。不会影响红黑树的性质，因此可以直接删除。\n删除单个黑节点 🧋 单个黑节点指得是左右子节点都是 null 的节点。\n兄弟节点是黑色，且远侄节点为红：旋转父节点，兄弟节点颜色变为父节点的颜色，父节点和远侄节点变黑。 兄弟节点是黑色，近侄节点为红，远侄节点为黑：旋转兄弟节点，近侄节点变黑，兄弟节点变红。转换为兄弟节点为黑，远侄节点为红。 兄弟节点为黑，且侄节点全黑：兄弟节点变红，将问题上移至父节点，递归处理。 兄弟节点为红：旋转父节点，兄弟节点变黑，父节点变红，转换成兄弟节点为黑的情况。 例1：删除节点 70。兄弟节点 100 是黑色，近侄节点 90 是红色，远侄节点 null 是黑色，为情况 2。删除节点 70 后，使用 null 节点代替，作为当前节点。\n兄弟节点 100 右旋，近侄节点 90 变黑，兄弟节点 100 变红。\n此时并没有调整完成，以 null 节点为目标节点，转换成兄弟节点 90 为黑，远侄节点 100 为红的情况。左旋父节点 80，兄弟节点 90 颜色变为父节点 80 的颜色（此处为黑色），父节点 80 和远侄节点 100 变黑。\n例2：删除节点 120。兄弟节点是红色，为情况 4。删除节点 120 后，使用 null 节点代替，作为当前节点。\n右旋父节点 100，兄弟节点 80 变黑，父节点 100 变红。\n此时并没有调整完成，以 null 节点为目标节点，转换成兄弟节点 90 为黑，侄节点全黑的情况。兄弟节点 90 变红，并递归检查。\n删除只包含一个子节点的黑色节点，该节点只可能是红色节点 只包含一个子节点时，这是唯一情况。目标节点为红色或者子节点为黑色，都会破坏红黑树的性质。\n🧋 目标节点替换为红色子节点，且子节点变为黑色。\n删除包含两个子节点的节点（不论红黑） 🧋 使用「左子树的最右节点6」代替该节点，颜色保持一致，仅替换内容。然后删除最右节点（跳转其他情况）。\n红黑树的原理 (插入+ 删除) 案例分析\n红黑树可视化网站\n红色节点不会连续出现\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n可能违反违反性质 4\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n可能违反性质 4，一定违反性质 5\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n左旋「父节点」之后，已经转化成了 LL 型的情况。\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n右旋「父节点」之后，已经转化成了 RR 型的情况。\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n也可以右子树的最左节点\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2025-05-24T00:00:00Z","image":"https://zeroszhang.github.io/p/%E7%BA%A2%E9%BB%91%E6%A0%91/Title.jpg","permalink":"https://zeroszhang.github.io/p/%E7%BA%A2%E9%BB%91%E6%A0%91/","title":"红黑树"},{"content":"最近发现 Halcon 的官方手册写得很好，于是详细阅读并做笔记。\n在我的笔记系统中包含以下文档的中文翻译：\nSolution Guide I.pdf Solution Guide II-A.pdf Solution Guide II-B.pdf Solution Guide II-C.pdf Solution Guide II-D.pdf Solution Guide III-A.pdf Solution Guide III-B.pdf Solution Guide III-C.pdf 文档中的案例都做了详细的笔记：\n部分例程学习后整理上传到此处：Halcon 例程\n","date":"2025-02-20T15:55:19+08:00","image":"https://zeroszhang.github.io/p/halcon%E4%BE%8B%E7%A8%8B%E7%AC%94%E8%AE%B0/Title.jpg","permalink":"https://zeroszhang.github.io/p/halcon%E4%BE%8B%E7%A8%8B%E7%AC%94%E8%AE%B0/","title":"Halcon例程笔记"},{"content":"关于 Microsoft Rewards Microsoft Rewards 是微软出品的一款软件，可以通过搜索 Bing 来获取奖励，奖励的种类有很多，包括现金、积分、礼品等。但是我老是忘记搜索 Bing，因此就实现了一个软件，帮助我每天自动搜索 Bing。\n我并没有将该功能添加到 ZerosTodo 中，因为我并不希望该功能影响我正常使用电脑，所以我拿了一个老笔记本安装了 Windows Server 2016，当作我的服务器。\n另外，Rewards 也有手机端的搜索任务，但是手机我是随身带着，所以我并没有实现安卓端的软件，直接使用油猴脚本进行替代。\n关于 RewardsAutoMate 自动搜索功能 该软件用于在 PC 端获取随机的搜索关键词，自动搜索 Bing，每天搜索 40 次，每隔 12 个小时执行一次任务。如果当天已经完成了任务，则不会继续执行。\n热力图功能 为了记录每天的搜索情况，该软件会生成如 Github 的热力图，用于记录每天的搜索情况。\n自动登录功能 Rewards 和微软账号相关，所以在打开 EdgeDriver 时，要调用本地的账户信息进行登录。\n项目代码上传到此处：RewardsAutoMate\n更新记录 2025年4月18日 更新：通过 UserAgent 伪装成移动设备，这样可以在 PC 端实现移动端的搜索。 ","date":"2025-02-06T15:44:39+08:00","image":"https://zeroszhang.github.io/p/microsoft-rewards-%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E5%8A%A9%E6%89%8B/Title.jpg","permalink":"https://zeroszhang.github.io/p/microsoft-rewards-%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E5%8A%A9%E6%89%8B/","title":"Microsoft Rewards 自动获取助手"},{"content":"3D设计软件 FreeCAD https://github.com/FreeCAD/FreeCAD\n日常工作需要审核机械设计师在 Solidworks 中绘制的 3D 图纸，于是就下了这个开源软件。该软件还支持 3D 设计，但是我没有这种需求。\n让我同事在 Solidworks 中导出 Step 文件，再在 FreeCAD 中打开即可。第一次打开 step 时要设置文本编码方式，选择 GBK，否则 step 文件中的中文会乱码。\n远程桌面 1Remote https://github.com/1Remote/1Remote\n开源软件，该软件可以记录多个远程桌面的配置（IP地址+用户+密码），下次使用双击打开即可。\nRSS阅读 Follow https://github.com/RSSNext/follow\n开源软件，可以使用RSS订阅很多网站，这样每天只要打开 Follow 就可以看到很多网站的更新。另外还有一点好处是可以看到其他用户订阅的内容，这样可以扩展自己的知识面。\n这个软件的功能是受限的，想解锁需要激活码，我是问别人要的。\n笔记软件 Wolai https://www.wolai.com/\n国内仿 Notion 比较好的软件，挺好用，需要按年开会员，否则功能受限。\n输入法中英文提示软件 InputTip https://github.com/abgox/InputTip\n写代码的时候需要频繁切换中英文，老是忘记看右下角，有了这个软件之后在输入的地方就会有一个悬浮图标指示大写/中文/英文。\n截图软件 PixPin https://pixpin.cn/\n贼好用的截图软件，完全覆盖了 Snipaste 的功能，除此以外可以离线OCR，长截图，录制Gif，功能很多。\n文件同步软件 坚果云 https://www.jianguoyun.com/\n可以无感同步文件，在不同的电脑上访问，我用的是免费的 1G 空间，同步一些日常用的文件。\n数据库管理软件 Heidi SQL https://www.heidisql.com/\n开源的数据库管理软件，支持很多类型的连接。\n视频播放器 PotPlayer http://www.potplayercn.com/\n贼好用的视频播放器，功能很多，比如倍速播放，看直播源等等。\nMarkdown编辑器 Typora 好用的 Markdown 编辑器，比其他的编辑器都好用，主要是很方便预览。\nhttps://typora.io/\n简易CSharp编辑器 LinqPad 8 https://www.linqpad.net/\n很方便的 C# 编辑器，使用 BenchMark 特别方便，跟写 Python 一样。\n多功能编辑器 VSCode https://code.visualstudio.com/\n支持的文件很多，比如装插件可以看 SQL.db 文件，可以看 Excel 文件，算是高级文本编辑器。\n还可以使用 Polyglot NoteBook 写 C#，跟 Jupyter NoteBook 类似，但是会有一些限制，而且代码提示没有 LinqPad 8 好用。\n文本编辑器 Notpad\u0026ndash; https://gitee.com/cxasm/notepad--\n选择这个文本编辑器有几点原因：\n操作逻辑和VS2022相同 不用折腾 支持多标签 多功能启动器 uTools https://www.u.tools/\n神。\n右键菜单美化 NileSoft Shell https://nilesoft.org/\n升级 Windows 11 后右键菜单不是很好用，所以下了这个软件，给右键菜单新增了额外的功能，并且颜值很高。\n这个软件有个问题，发送到这个菜单显示空白，我两台电脑都有这个问题，但是我在网上没搜到相同的问题。\n快速预览 QuickLook https://github.com/QL-Win/QuickLook\n跟 MacOS 一样的按空格预览文件的功能。需要额外下载插件，我下载了DrawIO，Office预览。\n","date":"2025-01-17T16:41:10+08:00","image":"https://zeroszhang.github.io/p/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/Title.jpg","permalink":"https://zeroszhang.github.io/p/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/","title":"软件推荐"},{"content":"碰到的问题 在日常的工作中，碰到几个问题：\n经常忘记个别要做的事情 某个事情做完几天后，忘记了当时的情况 因此就实现了一个软件 ZerosTodo ，帮助我日常更方便的工作。\n这个软件目前（2025 年 2 月 6 日）包含两个功能：\n从 wolai 的特定页面中获取最近要做的几个事情 每隔 5 秒截图屏幕并保存 对于需求 1，为了区别于正常的待办软件，我的软件里并没有待办的概念，而是直接把最近要做的几个事情显示在软件的界面上，并置顶悬浮于所有软件上面。我在屏幕专门留了一个角落给他。\n对于需求 2，我遍历当前所有的屏幕，并对每个屏幕截图，按照日期保存到指定的文件夹中。同时，为了避免硬盘占用太多，额外新增了一个配置项，超过 90 天的文件夹将会被删除。\n项目代码上传到此处：ZerosTodo\n更新记录 2025 年 3 月 18 日更新：新增文字朗读的功能，优化 UI 界面。这个功能可以上传 TxT 文件，并调用 Windows 的语音包朗读内容。\n2025 年 5 月 26 日更新：新增朗读剪贴板文字的功能。在常驻窗口中增加了一个小按钮，让我可以方便的使用该功能。\n2025 年 6 月 9 日更新：新增了一个临时记事本功能。可以拖拽内容到悬浮窗口会自动添加内容到临时记事本，也可以直接在临时记事本界面按下 Ctrl+V 添加剪贴板功能。临时记事本会在鼠标离开后的 3 秒自动关闭。\n","date":"2025-01-17T16:39:45+08:00","image":"https://zeroszhang.github.io/p/zerostodo-%E4%B8%AA%E4%BA%BA%E5%8A%A9%E6%89%8B/Title.jpg","permalink":"https://zeroszhang.github.io/p/zerostodo-%E4%B8%AA%E4%BA%BA%E5%8A%A9%E6%89%8B/","title":"ZerosTodo 个人助手"},{"content":"关于笔记软件 迄今为止，我使用过一些笔记软件，比如 AnyType，Notion，语雀，思源，Obsidian，Logseq，TiddlyWiki，Trilium，Joplin，飞书，wolai 等软件，最终我的选择是 wolai，原因是「中文」和「不用折腾插件/同步等问题」。\n另外其他几个软件都或多或少有一些不是很符合我需求的问题：\nTiddlyWiki：用法比较奇怪，会把所有的笔记记录到一个 HTML 文件中，我不太习惯。 飞书：「画布」功能是所有软件里做的最好的，能够把「流程图」和「思维导图」合并在一起，但是飞书软件太大了，而且得安装插件才可以导出 Markdown 格式。 Obsidian：网上特别多人使用的笔记软件，有插件系统，可以说是一个笔记版本的 VSCode，但是太折腾了。 语雀：之前使用的笔记软件，并且在该平台上创建了我第一版博客，后来语雀必须冲会员才能公开博客，所以我就放弃了。 wolai 是国内仿 Notion 很成功的一款软件，最近还被阿里巴巴收购了，合并到钉钉个人版中。由于免费版能使用的功能较少，所以我买了 6 年的会员。\n在此推荐：https://www.wolai.com/signup?invitation=7VKA7NI\n笔记结构 我大致将我的笔记分为以下几个部分：\n临时缓存：用于存储网页分享，微信助手，临时记录等内容 时光记录：个人日记 读书笔记：包含看过的书/论坛/网页等的总结和注释 文档：技术性的一些文档，如 C#/自动化/视觉/OpenCV/OpenGL 等 折腾记录：一些零碎的知识点 标签：都是空白的页面，给其他页面引用，以实现 wolai 中没有的标签系统 归档：草稿内容 博客更新笔记内容 由于我的笔记中内容太多，并且有很多内容不适合公开，因此该博客内，仅更新部分我觉得比较好的内容，可以点击 笔记 标签查找这部分内容。\n","date":"2025-01-17T16:38:10+08:00","image":"https://zeroszhang.github.io/p/%E6%88%91%E7%9A%84%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F/title.jpg","permalink":"https://zeroszhang.github.io/p/%E6%88%91%E7%9A%84%E7%AC%94%E8%AE%B0%E7%B3%BB%E7%BB%9F/","title":"我的笔记系统"},{"content":"简介 BaseWPFControl 是一个 dll，基于 .net 8.0 和 WPF 框架实现，用于提供控件样式（包含基础控件和额外控件）。\n基础控件 Button 重写了基础控件 Button 的样式。\n新增 BaseWPFControl:ButtonProperty.Icon 附加属性用于提供按钮图标 提供圆角 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;Button Content=\u0026#34;纯文字按钮\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;图标\u0026#34; Margin=\u0026#34;10\u0026#34; BaseWPFControl:ButtonProperty.Icon=\u0026#34;{StaticResource HomePage}\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;圆形按钮\u0026#34; Margin=\u0026#34;10\u0026#34; Style=\u0026#34;{StaticResource CircleButtonStyle}\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;带图标的圆形按钮\u0026#34; Margin=\u0026#34;10\u0026#34; Style=\u0026#34;{StaticResource CircleButtonStyle}\u0026#34; BaseWPFControl:ButtonProperty.Icon=\u0026#34;{StaticResource HomePage}\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;跑道形按钮\u0026#34; Margin=\u0026#34;10\u0026#34; Style=\u0026#34;{StaticResource RoundButtonStyle}\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;图标\u0026#34; Margin=\u0026#34;10\u0026#34; Style=\u0026#34;{StaticResource RoundButtonStyle}\u0026#34; BaseWPFControl:ButtonProperty.Icon=\u0026#34;{StaticResource HomePage}\u0026#34; /\u0026gt; 针对不启用和不可点击的按钮，做出了区分，分别对应 IsEnabled 和 IsHitTestVisible 属性。\n1 2 \u0026lt;Button Content=\u0026#34;不启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; \u0026lt;Button Content=\u0026#34;不可点击\u0026#34; IsHitTestVisible=\u0026#34;False\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; 之所以这样去做目的是为了 GPIO 的控制，GPI 不可点击，GPO 可点击。\n提供了两种相似的样式 BooleanStateButtonStyle 和 BooleanToggleButtonStyle。前者对应于 GPI，不可点击，仅用于展示 GPI 状态，后者对应于 GPO，既可以展示 GPO 状态，又可以通过点击切换状态。\n1 2 3 4 \u0026lt;Button Style=\u0026#34;{StaticResource BooleanStateButtonStyle}\u0026#34; Margin=\u0026#34;10\u0026#34; Tag=\u0026#34;{Binding State}\u0026#34; /\u0026gt; \u0026lt;Button Style=\u0026#34;{StaticResource BooleanToggleButtonStyle}\u0026#34; Margin=\u0026#34;10\u0026#34; Tag=\u0026#34;{Binding State}\u0026#34; Command=\u0026#34;{Binding ChangeStateCommand}\u0026#34; /\u0026gt; ToggleButton 基于 ToggleButton 重写样式，该控件的本意是用于 GPIO 的控制\n1 2 3 \u0026lt;ToggleButton IsChecked=\u0026#34;{Binding State}\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; \u0026lt;ToggleButton IsChecked=\u0026#34;{Binding State}\u0026#34; Margin=\u0026#34;10\u0026#34; IsEnabled=\u0026#34;False\u0026#34; /\u0026gt; 最终方案如下：\nGPI 使用 Button 的 BooleanStateButtonStyle 样式 GPO 使用 ToggleButton 的默认样式。 RadioButton 重写 RadioButton 的样式，主要优化如下：\n勾选后样式变化 勾选框尺寸跟随字体尺寸变化 1 2 3 4 5 \u0026lt;RadioButton Content=\u0026#34;未勾选\u0026#34; /\u0026gt; \u0026lt;RadioButton Content=\u0026#34;勾选\u0026#34; IsChecked=\u0026#34;True\u0026#34; /\u0026gt; \u0026lt;RadioButton Content=\u0026#34;未勾选未启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; IsChecked=\u0026#34;False\u0026#34; /\u0026gt; \u0026lt;RadioButton Content=\u0026#34;勾选未启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; IsChecked=\u0026#34;True\u0026#34; /\u0026gt; \u0026lt;RadioButton Content=\u0026#34;大字体\u0026#34; FontSize=\u0026#34;30\u0026#34; /\u0026gt; CheckBox 重写 CheckBox 的样式，主要优化如下：\n勾选后样式变化 勾选框圆角 勾选框尺寸跟随字体尺寸变化 1 2 3 4 5 \u0026lt;CheckBox Content=\u0026#34;未勾选\u0026#34; /\u0026gt; \u0026lt;CheckBox Content=\u0026#34;勾选\u0026#34; IsChecked=\u0026#34;True\u0026#34; /\u0026gt; \u0026lt;CheckBox Content=\u0026#34;未勾选未启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; IsChecked=\u0026#34;False\u0026#34; /\u0026gt; \u0026lt;CheckBox Content=\u0026#34;勾选未启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; IsChecked=\u0026#34;True\u0026#34; /\u0026gt; \u0026lt;CheckBox Content=\u0026#34;大字体\u0026#34; FontSize=\u0026#34;30\u0026#34; /\u0026gt; ComboBox 重写 ComboBox 样式，主要优化如下：\n圆角属性 提供 ComboBox 绑定枚举值的扩展语法 EnumBindingSource 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 \u0026lt;!--示例1：ComboBox绑定枚举值--\u0026gt; \u0026lt;ComboBox Margin=\u0026#34;10\u0026#34; Width=\u0026#34;120\u0026#34; ItemsSource=\u0026#34;{BaseWPFControl:EnumBindingSource EnumType=BaseTest:EnumDayOfWeek}\u0026#34; SelectedItem=\u0026#34;{Binding SelectedEnumDayOfWeek}\u0026#34; \u0026gt; \u0026lt;ComboBox.ItemTemplate\u0026gt; \u0026lt;DataTemplate\u0026gt; \u0026lt;TextBlock Text=\u0026#34;{Binding Converter={StaticResource EnumToDescriptionConverter}, Mode=OneWay}\u0026#34; /\u0026gt; \u0026lt;/DataTemplate\u0026gt; \u0026lt;/ComboBox.ItemTemplate\u0026gt; \u0026lt;/ComboBox\u0026gt; \u0026lt;!--示例2：不启用ComboBox--\u0026gt; \u0026lt;ComboBox Margin=\u0026#34;10\u0026#34; Width=\u0026#34;120\u0026#34; IsEnabled=\u0026#34;False\u0026#34; \u0026gt; \u0026lt;ComboBoxItem Content=\u0026#34;1\u0026#34; IsSelected=\u0026#34;True\u0026#34; /\u0026gt; \u0026lt;/ComboBox\u0026gt; \u0026lt;!--示例3：ComboBox绑定字典--\u0026gt; \u0026lt;!--note：需要设置 DisplayMemberPath 和 SelectedValuePath，--\u0026gt; \u0026lt;!--note：并只能使用 SelectedValue 进行访问--\u0026gt; \u0026lt;ComboBox Margin=\u0026#34;10\u0026#34; Width=\u0026#34;120\u0026#34; ItemsSource=\u0026#34;{Binding DictionaryDayOfWeek}\u0026#34; DisplayMemberPath=\u0026#34;Value\u0026#34; SelectedValuePath=\u0026#34;Key\u0026#34; SelectedValue=\u0026#34;{Binding SelectedDictionaryDayOfWeek}\u0026#34; /\u0026gt; \u0026lt;!--示例4：ComboBox绑定列表--\u0026gt; \u0026lt;!--note：使用 SelectedItem 或者 SelectedValue 都可以获得正确结果--\u0026gt; \u0026lt;!--note: 前提是绑定的值在列表中，也可以通过 SelectedIndex 进行访问--\u0026gt; \u0026lt;ComboBox Margin=\u0026#34;10\u0026#34; Width=\u0026#34;120\u0026#34; ItemsSource=\u0026#34;{Binding ListDayOfWeek}\u0026#34; SelectedItem=\u0026#34;{Binding SelectedListDayOfWeek}\u0026#34; /\u0026gt; TextBlock 重写 TextBlock 的样式，主要优化如下：\n中英文使用不同的字体显示，中文使用微软雅黑，英文使用Consolas 1 2 \u0026lt;TextBlock Text=\u0026#34;显示中文\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; \u0026lt;TextBlock Text=\u0026#34;Show English\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; MemoryBlock 该控件为自定义控件，主要实现以下功能：\n获取当前软件已使用内存，以 MB 为单位 可以通过控件的 Interval 属性设置更新频率，单位为 ms，默认为 1000 ms 可以通过控件的 Header 属性设置前缀文字 可以通过控件的 UsedMemory 只读属性获取内存 1 \u0026lt;BaseWPFControl:MemoryBlock Margin=\u0026#34;10\u0026#34; /\u0026gt; LogBlock 该控件为自定义控件，配合 BaseLogManager 一起使用，主要实现以下功能：\n显示日志 提供日志详情页 1 2 3 4 \u0026lt;BaseWPFControl:LogBlock x:Name=\u0026#34;LogBlock_Test\u0026#34; /\u0026gt; \u0026lt;ContentControl Height=\u0026#34;400\u0026#34; Margin=\u0026#34;10\u0026#34; Content=\u0026#34;{Binding ElementName=LogBlock_Test, Path=LogView}\u0026#34; /\u0026gt; TextBox 重写 TextBox 的样式，主要实现以下功能：\n可以通过 TextBoxProperty.Prefix 属性设置前缀文字 可以通过 TextBoxProperty.WaterMask 属性设置水印文字 可以通过 TextBoxProperty.Suffix 属性设置后缀文字 输入时边框高亮显示 大文本输入框可以通过滚动条上下滚动 1 2 3 4 5 6 7 8 9 10 11 \u0026lt;TextBox Width=\u0026#34;200\u0026#34; Margin=\u0026#34;10\u0026#34; BaseWPFControl:TextBoxProperty.Prefix=\u0026#34;www.\u0026#34; BaseWPFControl:TextBoxProperty.Suffix=\u0026#34;.com\u0026#34; BaseWPFControl:TextBoxProperty.WaterMask=\u0026#34;输入网址\u0026#34; /\u0026gt; \u0026lt;TextBox Width=\u0026#34;160\u0026#34; Margin=\u0026#34;10\u0026#34; Text=\u0026#34;默认文本框\u0026#34; /\u0026gt; \u0026lt;TextBox Width=\u0026#34;100\u0026#34; Margin=\u0026#34;10\u0026#34; BaseWPFControl:TextBoxProperty.WaterMask=\u0026#34;绑定Decimal类型\u0026#34; Text=\u0026#34;{Binding DecimalNumber, StringFormat=0.#}\u0026#34; /\u0026gt; \u0026lt;TextBox Style=\u0026#34;{StaticResource BigTextBox}\u0026#34; Width=\u0026#34;400\u0026#34; Height=\u0026#34;100\u0026#34; Margin=\u0026#34;10\u0026#34; Text=\u0026#34;{Binding Poetry1}\u0026#34; /\u0026gt; NumericBox NumericBox 为自定义控件，主要实现以下功能：\n更方便的绑定数字，并提供限制 可以通过 Value 属性获取/设置值 可以通过 TextFormat 属性设置文本格式 可以通过 MinValue 属性设置最小值 可以通过 MaxValue 属性设置最大值 可以通过 Interval 属性设置点击增减按钮时的变化量 可以通过 ValueChanged 事件获取值改变事件 1 2 3 4 5 \u0026lt;BaseWPFControl:NumericBox Value=\u0026#34;{Binding DecimalNumber}\u0026#34; TextFormat=\u0026#34;0.#\u0026#34; MinValue = \u0026#34;0\u0026#34; MaxValue = \u0026#34;100\u0026#34; Interval = \u0026#34;1\u0026#34; ValueChanged=\u0026#34;NumericBox_ValueChanged\u0026#34; /\u0026gt; \u0026lt;BaseWPFControl:NumericBox Value=\u0026#34;{Binding DecimalNumber}\u0026#34; TextFormat=\u0026#34;0.#\u0026#34; IsEnabled=\u0026#34;False\u0026#34; /\u0026gt; PasswordBox 重写 PasswordBox 样式，主要实现以下功能：\n可以通过 PasswordBoxProperty.CanShowPassword 属性设置是否显示密码的功能 1 2 3 \u0026lt;PasswordBox Width=\u0026#34;200\u0026#34; Margin=\u0026#34;10\u0026#34; Password=\u0026#34;123456\u0026#34; /\u0026gt; \u0026lt;PasswordBox Width=\u0026#34;200\u0026#34; Margin=\u0026#34;10\u0026#34; Password=\u0026#34;123456\u0026#34; BaseWPFControl:PasswordBoxProperty.CanShowPassword=\u0026#34;False\u0026#34; /\u0026gt; DatePicker \u0026amp; DateTimePicker DatePicker 和 DateTimePicker 都是自定义控件，主要实现以下功能：\n选择时间和日期，这两个控件的区别在于一个前者只有日期，后者包含时间 可以通过 SelectedDateTime 获取选中的日期时间 可以通过 SelectedDateTimeFormat 设置日期时间的格式 可以通过 SelectedDateTimeChanged 获取时间改变的事件 1 2 \u0026lt;BaseWPFControl:DatePicker Margin=\u0026#34;10\u0026#34; /\u0026gt; \u0026lt;BaseWPFControl:DateTimePicker Margin=\u0026#34;10\u0026#34; /\u0026gt; SelectFileBlock \u0026amp; SelectFolderBlock SelectFileBlock 和 SelectFolderBlock 都是自定义控件，主要实现以下功能：\n点击按钮通过对话框选择文件或者文件夹 可以通过 SelectedPath 属性获取/设置路径 可以通过 SelectedPathChanged 获取选中路径改变的事件 SelectFileBlock 可以通过 ExtensionFilter 属性设置文件过滤 鼠标移动到文字上方出现 ToolTip 显示路径的全文 鼠标双击文字直接跳转到路径所在的文件夹 Image 提供一些内置的 SVG，可以直接通过 Source 绑定 StaticResource 值进行设置\n1 \u0026lt;Image Source=\u0026#34;{StaticResource DirectoryConfig}\u0026#34; Height=\u0026#34;50\u0026#34; Margin=\u0026#34;10\u0026#34; /\u0026gt; ProgressBar \u0026amp; Loading 重写 ProgressBar 样式，提供圆角 可以通过 ProgressBarProperty.ShowValue 属性设置进度条显示当前值 提供扩展函数 SetAnimateValue 设置进度条的值，通过该函数设置可以显示动画 提供自定义控件圆形进度条 Loading，仅用于等待功能 1 2 3 4 \u0026lt;ProgressBar Height=\u0026#34;40\u0026#34; Width=\u0026#34;400\u0026#34; d:Value=\u0026#34;20\u0026#34;/\u0026gt; \u0026lt;ProgressBar Height=\u0026#34;40\u0026#34; Width=\u0026#34;400\u0026#34; IsIndeterminate=\u0026#34;True\u0026#34;/\u0026gt; \u0026lt;BaseWPFControl:Loading Diameter=\u0026#34;150\u0026#34; StrokeThickness=\u0026#34;30\u0026#34; Content=\u0026#34;加载中，请等待...\u0026#34; /\u0026gt; Clock \u0026amp; Calendar 重写 Calender 样式 提供 自定义控件 Clock，用于选择时间 1 2 3 \u0026lt;Calendar x:Name = \u0026#34;Calendar\u0026#34; /\u0026gt; \u0026lt;BaseWPFControl:Clock Height=\u0026#34;{Binding ActualHeight, ElementName=Calender}\u0026#34;/\u0026gt; TabControl 重写 TabControl 的样式\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026lt;TabControl TabStripPlacement=\u0026#34;Left\u0026#34;\u0026gt; \u0026lt;TabItem Header=\u0026#34;水调歌头\u0026#34; \u0026gt; \u0026lt;TextBlock Text=\u0026#34;{Binding Poetry1}\u0026#34; FontSize=\u0026#34;14\u0026#34; /\u0026gt; \u0026lt;/TabItem\u0026gt; \u0026lt;TabItem Header=\u0026#34;如梦令\u0026#34; \u0026gt; \u0026lt;TextBlock Text=\u0026#34;{Binding Poetry2}\u0026#34; FontSize=\u0026#34;14\u0026#34; /\u0026gt; \u0026lt;/TabItem\u0026gt; \u0026lt;TabItem Header=\u0026#34;破阵子\u0026#34; \u0026gt; \u0026lt;TextBlock Text=\u0026#34;{Binding Poetry3}\u0026#34; FontSize=\u0026#34;14\u0026#34; /\u0026gt; \u0026lt;/TabItem\u0026gt; \u0026lt;TabItem Header=\u0026#34;未启用\u0026#34; IsEnabled=\u0026#34;False\u0026#34; /\u0026gt; \u0026lt;/TabControl\u0026gt; 复杂控件 ConfigControl 提供自定义控件 ConfigControl，用于方便的实现配置界面\n1 2 3 4 5 6 7 \u0026lt;BaseWPFControl:ConfigControl ConfigName=\u0026#34;日期时间\u0026#34;\u0026gt; \u0026lt;BaseWPFControl:DateTimePicker /\u0026gt; \u0026lt;/BaseWPFControl:ConfigControl\u0026gt; \u0026lt;BaseWPFControl:ConfigControl ConfigName=\u0026#34;选择文件\u0026#34;\u0026gt; \u0026lt;BaseWPFControl:SelectFileBlock Width=\u0026#34;280\u0026#34; /\u0026gt; \u0026lt;/BaseWPFControl:ConfigControl\u0026gt; LisBox 重写 ListBox 的样式，可以绑定 Enum/List/Dictionary\nListView 重写 ListView 的样式 DataGrid 重写 DataGrid 的样式，这里包含两种样式，一种是选择单元格，另一种是鼠标经过选中整行\n更新记录 更新了部分 BaseWPFControl 中的控件，实现了更多的功能。\n优化ListBox 实际使用了一下ListBox之后发现还是有很多问题，尤其是关于调整属性之后，并且给出了更多的示例\n新增BaseClipBorder 实现了新的控件BaseClipBorder来解决边框溢出和边框圆角缝隙的问题 最终实现如右图所示 优化ProgressBar 在上面BaseClipBorder的基础上优化了ProgressBar的实现 给出了垂直ProgressBar例程实现 新增DefaultControlStyle和DefaultWindowStyle 这样设计的原因其实是为了移除掉TextBlock的FontSize属性和FontFamily属性，改为直接从Window或者UserControl中继承字体属性。\n而DefaultControlStyle中定义了基础的FontSize和FontFamily样式，并且任何控件都可以使用。\n优化Button 删除了关于ButtonShape属性的内容 新增了一些无边框按钮的样式 统一了BorderBrush和BorderThickness的风格 优化ComboBox 重写了ComboBox的样式 新增ComboBoxItem的样式 新增InnerSeparator属性 新增BaseWPFControl:ControlProperty.InnerSeparator属性，一般用于内部存在间隙属性调整 1 2 3 \u0026lt;Button Content=\u0026#34;图标\u0026#34; Margin=\u0026#34;10\u0026#34; BaseWPFControl:ButtonProperty.Icon=\u0026#34;{StaticResource HomePage}\u0026#34; BaseWPFControl:ControlProperty.InnerSeparator=\u0026#34;20\u0026#34; /\u0026gt; 优化DataGrid 在使用DataGrid的时候，我发现有些属性没有效果，或者不尽如人意。\n所以我就重新整理了一下DataGrid的实现，并且给出了详细的案例。\n优化Calendar和Clock 优化FlipBox 新增Dialog显示成Window 可以调用ShowDialogAsWindow函数，将Dialog显示成独立的Window，就算没有DialogContainer也能显示。使用体验和WPF原生的ShowDialog函数类似。\n优化ListBox 和之前的显示一致，只是使用BaseClipBorder简化了内部实现。\n优化ListView 优化SmoothProgress 这里省事，直接让SmoothProgressBar使用ProgressBar的样式\n新增SimpleScrollViewer样式 该样式没有滚动条，只有箭头按钮，并且增加了滚动动画 主要用于TabControl的Header部分 优化TabControl 优化了微软原生样式下，TabItem溢出的问题 ","date":"2025-01-17T11:25:07+08:00","image":"https://zeroszhang.github.io/p/wpf%E6%8E%A7%E4%BB%B6%E5%BA%93-basewpfcontrol/Title.jpg","permalink":"https://zeroszhang.github.io/p/wpf%E6%8E%A7%E4%BB%B6%E5%BA%93-basewpfcontrol/","title":"WPF控件库 BaseWPFControl"}]