lindexi

林德熙 - 微软最具价值专家和 .NET 基金会成员

林德熙

dotnet 读 WPF 源代码笔记 WPF 是如何做到一套代码兼容多个 .NET Framework 版本

在 .NET Framework 时代里面,有一组有趣的概念,那就是 SDK 和 Runtime 这两个概念。开发模式十分有趣,在开发者设备上,可以指定 .NET Framework 的 SDK 版本,例如指定 .NET Framework 4.5 版本。开发完成之后,分发给到用户,用户的电脑上所安装的 .NET Framework 基本都是 Runtime 版本。应用程序要求运行的 Runtime 版本一定要大于等于 SDK 的指定版本号 这就有一个非常有趣的问题了,我开发环境使用的 SDK 是低版本,例如 .NET Framework 4.5 版本。但用户的电脑上所安装的 .NET Framework 的 Runtime 版本是高版本,例如是 .NET Framework 4.7 版本,中间距离过了几年的版本。那行为如何保证相同?如果行为不能保证相同,那将会出现行为差异,在我的开发设备上跑得好好的,在一些用户电脑上,将会因为运行时基础库的版本差异从而变更行为,应用程序就不能符合预期跑起来了。事实上,咱没有碰到过这个问题,这是因为在 .NET Framework 层做了很多兼容处理逻辑,其中就包括本文要和大家聊的 WPF 框架的兼容行为

dotnet 修复在 Linux 上使用 SkiaSharp 提示找不到 libSkiaSharp 库

本文告诉大家如何简单修复在 Linux 上使用 SkiaSharp 提示找不到 libSkiaSharp 库

dotnet 谨慎在静态构造函数里使用锁

在 dotnet 的最佳实践里面,不推荐在静态构造函数里面包含复杂的逻辑,其中也就包含了本文聊的和多线程相关的锁的使用。最佳做法是尽量不要在静态构造函数里面碰到任何和锁以及多线程安全相关的逻辑。本文来告诉大家,在静态构造函数里面使用锁将带来的问题以及原因

dotnet 使用 ConfigureAwait.Fody 库设置默认的 await 同步上下文切换配置

在 dotnet 里面,使用 await 进行异步逻辑,默认是会尝试切换回调用 await 的线程同步上下文。这个机制对于大多数的上层应用来说都是符合逻辑且方便的逻辑,例如对于带 UI 线程的 WPF 或 WinForms 等应用,基础开发的执行逻辑基本都是在 UI 线程上,此时进入一次 await 再出来,期望如果是进入 await 之前是在 UI 线程,那么执行 await 完成之后,退出的代码也能在 UI 线程执行,正好这就是 dotnet 的默认行为。但是对于库开发者来说,情况就反过来的,库的开发者大部分时候更期望默认不要切换回调用方的线程,采用 Fody 的 ConfigureAwait.Fody 库,可以控制此默认的行为。本文将告诉大家如何使用 ConfigureAwait.Fody 库

dotnet 使用 NamedPipeClientStream 连接一个不存在管道服务名将不断空跑 CPU 资源

本文记录一个开发和代码审查过程中,需要关注的细节。在 dotnet 里,在 .NET 6 和以下版本,包括 .NET Framework 版本,使用 NamedPipeClientStream 进行连接管道服务,如果此时的管道服务没有存在,或者还没有启动,调用 ConnectAsync 或 Connect 方法,将会进入一个循环,不断进行空跑,等待超时或者是连接上。默认的 ConnectAsync 或 Connect 方法,传入的超时时间都是无穷,也就是将会无限重试,不断消耗 CPU 资源

dotnet 启动进程传入不存在的文件夹作为工作目录行为变更

本文记录在 dotnet 下,启动进程,传入不存在的文件夹作为进程的工作目录,分别在 .NET Framework 和 .NET Core 的行为

dotnet format 忽略生成代码的格式化

我给团队引入了自动格式化代码机器人,这个机器人有点傻,会将生成的代码也进行格式化,每次都会我的代码生成工具打架。为了让这两个机器人和好,我探索了让 dotnet format 忽略对生成代码进行自动格式化的方法

dotnet 通过 DockerfileContext 解决项目放在里层文件夹导致 VisualStudio 构建失败

本文告诉大家,如何解决 csproj 项目文件放入到里层的文件夹,不放在 sln 所在文件夹的第一层子文件夹,导致 VisualStudio 2022 在构建 docker 映像提示找不到文件的问题

dotnet 根据基线包版本实现库版本兼容

本文来告诉大家如何根据 基线包版本 的功能来实现自动在构建过程中,告诉开发者,当前版本是否存在不兼容旧版本的变更。其不兼容变更包括二进制中断变更和 API 不兼容变更和源代码中断变更。可以让库开发者花更少的精力在测试兼容性上

dotnet 使用 Newtonsoft.Json 输出枚举首字符小写

本文告诉大家如何使用 Newtonsoft.Json 输出枚举首字符小写

dotnet 写一个支持层层继承属性的对象

我最近在造一个比 Excel 差得多的表格控件,其中一个需求是属性的继承。大家都知道,表格里面有单元格,单元格里面允许放文本,文本可以放多段文本。本文的主角就是文本段落的样式属性,包括文本字体字号颜色等等属性。文本段落的属性,如果没有特别设置,将使用单元格里面的文本样式属性。而如果单元格里面,没有特别指定此单元格使用特殊的文本样式,将会继承使用当前所在的行的文本样式。如果当前行没有特殊指定文本样式属性,那么将会使用文档的默认样式。文档默认样式将会根据是否有特殊指定而采用主题样式 如此复杂的层层继承逻辑,如果每个属性都需要自己一层层去寻找,那代码量将会特别多。维护起来就想吃桌子

dotnet 构建还原失败 NuGet.targets 错误可能原因

我在一次断电关机之后,发现我所有的项目都构建不通过了,提示在 NuGet.targets 文件的第 130 行错误。原因就是存在有某个被项目引用的 NuGet 包被损坏,在进行 NuGet 还原时读取这个包出错

dotnet 读 WPF 源代码笔记 简单聊聊文本布局换行逻辑

在 WPF 里面,带了基础的文本库功能,如 TextBlock 等。文本库排版的重点是在文本的分行逻辑,也就是换行逻辑,如何计算当前的文本字符串到达哪个字符就需要换到下一行的逻辑就是文本布局的重点模块。本文来简单聊聊 WPF 的文本布局逻辑

dotnet 性能优化 利用哈希思想优化大对象集合相等判断性能

利用哈希的其中一个思想,相同的对象的哈希值相同,可以用来提升一些大对象集合的进行对象相等判断的性能。大对象的相等判断指的是有某些类型的相等判断需要用到对象的很多属性或字段进行参与判断逻辑才能判断两个对象是否相等,当这些大对象存放在集合里面,此时进行大量的相等判断将会因为需要有大量的属性或字段的判断而降低性能。本文告诉大家如何使用此哈希的思想提升判断的性能

dotnet 读 WPF 源代码笔记 渲染收集是如何触发

在 WPF 里面,渲染可以从架构上划分为两层。上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令。上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GFX 层,作用是根据收到的渲染的命令绘制出界面。本文所聊的是渲染上层部分,在 WPF 框架是如何做到界面刷新渲染,包括此调用的顺序以及框架逻辑

dotnet 教你写一个可以搞炸本机所有 WCF 应用的程序方法

作为团队里面挖掘机出身的我,怎么能不多挖一些坑好将小伙伴们都埋进去呢。本文来告诉大家一个有趣且简单的方法,此方法可以将本机的 WCF 玩坏,不敢说真的搞炸本机所有 WCF 应用,但搞炸大部分基于 WCF 的软件还是没有问题的。阅读本文,你可以不仅可以了解到有这样的逗比方法,更重要的是在你的 WCF 模块炸掉的时候,你知道要甩锅给谁

dotnet 读 WPF 源代码笔记 提升调试效率的 NamedObject 类型

本文来聊聊 WPF 那些值得称赞的设计中的 NamedObject 类型。在 WPF 中,有很多值得我学习的设计开发思想,其中就包括本文将要介绍的 NamedObject 类型。此类型的定义仅仅只是为了方便调试,而没有具体的业务功能

dotnet 读 WPF 源代码 聊聊 DispatcherTimer 的实现

本文来告诉大家在 WPF 框架里面,是如何实现 DispatcherTimer 的功能。有小伙伴告诉我,读源代码系列的博客看不动,原因是太底层了。我尝试换一个方式切入逻辑,通过提问题和解决问题的方法,一步步告诉大家 WPF 是如何实现 DispatcherTimer 的功能

dotnet 读 WPF 源代码 Popup 的 StaysOpen 为 false 将会吃掉其他窗口的首次激活

在 WPF 中,使用 Popup 控件,可以设置 StaysOpen 属性来控制是否在 Popup 失去焦点时,也就是点击界面空白处,自动收起 Popup 控件。但如果有两个窗口,在设置 Popup 控件的 StaysOpen 属性为 false 那么将会吃掉在点击其他窗口的第一次交互,如鼠标点击或触摸点击时将不会让本进程的其他窗口 Activate 激活

dotnet 忽略输出文件夹的正则表达式

本文告诉大家在 dotnet 里面忽略 obj 和 x86 等输出文件夹的正则表达式内容

dotnet 读 WPF 源代码笔记 插入触摸设备的初始化获取设备信息

在 WPF 触摸应用中,插入触摸设备,即可在应用里面使用上插入的触摸设备。在 WPF 使用触摸设备的触摸时,需要获取到触摸设备的信息,才能实现触摸

dotnet 读 WPF 源代码笔记 了解 WPF 已知问题 用户设备上不存在 Arial 字体将导致应用闪退

本文来告诉大家 WPF 已知问题,在用户的设备上,如果不存在 Arial 字体,同时安装了一些诡异的字体,那么也许就会让应用在使用到诡异的字体的时候,软件闪退

dotnet 运行时获取某类型的对象占用内存大小

本文将告诉大家一个黑科技方法在运行时动态获取对象本身占用空间,不包括对象引用的其他对象的空间大小的方法

dotnet 读 WPF 源代码笔记 WriteableBitmap 的渲染和更新是如何实现

在 WPF 框架提供方便进行像素读写的 WriteableBitmap 类,本文来告诉大家在咱写下像素到 WriteableBitmap 渲染,底层的逻辑

dotnet 文档应用的撤销重做设计

文档应用是指如 Word 或 PPT 等的提供给用户进行内容创作的工具,而撤销重做其实也被称为撤销恢复功能。本文来告诉大家撤销重做这个模块的设计路线,从简单的复杂

dotnet 读 WPF 源代码笔记 创建 SolidColorBrush 性能没有想象那么差

在 WPF 中,常用的画刷里面有纯色画刷 SolidColorBrush 类。因为画刷会对应到 DirectX 的资源,因此之前我以为纯色画刷其实会比 Color 会占用更多的资源。在 WPF 中 Color 其实是结构体,创建速度快。而 SolidColorBrush 是画刷,会对应 DirectX 资源,相对来说性能会比较差。但在通过阅读 WPF 的源代码,发现其实 SolidColorBrush 的创建的性能其实是特别好的,因此请不要担心创建了太多的纯色画刷类

dotnet 桌面端基于 AppHost 的配置式自动切换更新后的应用程序路径

在桌面应用端开发的时候,应用更新有很多实现方式,本文来告诉大家一个基于 dotnet core 或 .NET 5 的 AppHost 方式的配置式软件更新方法。这个方法的特点是入口的 Exe 文件可以固定不动,每次更新的时候只需要更新某个配置文件的路径,即可实现在应用启动的时候,读取配置文件的路径加载某个版本的软件跑起来。而且本文的方法不需要额外其他一个独立的启动进程,而是入口文件进程就是最终的 dotnet 进程,可以做到固定到任务栏等不会在自动更新的时候丢失

dotnet 修复 ILLinkTasksAssembly 特性的值的计算结果无效

在加上 IL Link 的项目里面,在升级到 .NET 6 预览版,有一些项目将会构建不通过,或者有些 C++ CLI 项目加载失败。提示 元素 UsingTask 中“AssemblyFile”特性的值“$(ILLinkTasksAssembly)”的计算结果“”无效。原因就是 .NET 6 预览版里面,或者自己的设备上 ILLinkTasksAssembly 属性定义失效

dotnet 读 WPF 源代码笔记 默认的 Main 函数是在哪创建的

在使用默认的 WPF 项目开发的时候,咱是不需要自己编写 Main 函数的,在 WPF 中的 Main 函数是存放在 App.g.cs 里面,看起来这个 Main 函数是生成的函数,本文将介绍在 WPF 框架中是如何创建这个入口函数

dotnet 在 Windows 系统上使用 stakx 的 WIC 库

在 Windows 系统上,有一个很重要的概念是 Windows Imaging Component 也就是 WIC 层,这是专门用来处理多媒体相关的系统组件,特别是用来处理图片相关,包括编码和解码和处理图片。默认在 WPF 中就可以使用封装好的 WIC 层,也就是说最好的 WIC 库就是 WPF 框架了。但是如果在 WPF 之外呢,我有一点特别的需求,我想要绕过 WPF 框架,通过纯控制台的方式使用到 WIC 层的逻辑,此时可以使用 stakx 的 WIC 库。当然,最后发现最好的封装依然 WPF 框架,即使是控制台也能使用 WPF 哦

dotnet 读 WPF 源代码笔记 为什么设置了SplashScreen会让Application.Current.Activated事件不触发

在 WPF 应用中,可以非常方便将一张图片设置为 SplashScreen 启动界面欢迎图,但是如果有设置了启动界面欢迎界面,那么 Application.Current.Activated 事件就不会被触发。本文通过 WPF 框架开源的代码告诉大家这个原因

dotnet 使用 TypeNameFormatter 库格式化输出反射泛型类型

默认的反射输出带泛型的类型,都会使用反引号的字符串。使用 TypeNameFormatter 库可以输出贴近代码的输出

dotnet tool 自动找到项目里面重复的 NuGet 依赖项

使用新的 SDK 风格的 csproj 的时候,允许 NuGet 包进行依赖传递。意思是如果我 A 项目安装了库 L 那么如果有 B 项目引用 A 项目,那么自动 B 项目也就安装了库 L 而不需要项目 B 再次手动安装。也就是如果此时的 B 项目里面也加上了 L 库的安装,那么这个安装就是多余的。本文安利大家一个工具,可以自动了解有哪些项目的哪些库是多余安装的,通过依赖传递就能安装上,不需要手动安装,可以删除

dotnet 读 WPF 源代码笔记 Stroke 类可能存在的内存泄露

在 WPF 中,使用 Stroke 类时,可能会出现内存泄露,原因是 DrawingAttributes 的事件被监听没有释放。本文将从源代码的角度告诉大家这个内存泄露问题和如何解决