当前位置: 首页 > news >正文

WPF 很少人知道的科技

本文介绍不那么常见的 WPF 相关的知识。


本文内容

    • 在 C# 代码中创建 DataTemplate
    • 多个数据源合并为一个列表显示
    • 使用附加属性做缓存,避免内存泄漏
    • 使用 ConditionalWeakTable 做非 WPF 版本的缓存
    • 使用代码模拟触摸
    • 模拟 UWP 界面
    • 模拟 Fluent Design 特效

在 C# 代码中创建 DataTemplate

大多数时候我们只需要在 XAML 中就可以实现我们想要的各种界面效果。这使得你可能已经不知道如何在 C# 代码中创建同样的内容。

比如在代码中创建 DataTemplate,主要会使用到 FrameworkElementFactory 类型。

可以参考:

  • WPF 后台创建 DateTemplate - Iron 的博客 - CSDN博客

多个数据源合并为一个列表显示

WPF 提供 CompositionCollection 用于将多个列表合并为一个,以便在 WPF 界面的同一个列表中显示多个数据源的数据。

<ListBox Name="WalterlvDemoListBox">
    <ListBox.Resources>
        <CollectionViewSource x:Key="Items1Source" Source="{Binding Items1}"/>
        <CollectionViewSource x:Key="Items2Source" Source="{Binding Items2}"/>
    </ListBox.Resources>
    <ListBox.ItemsSource>
        <CompositeCollection>
            <CollectionContainer Collection="{Binding Source={StaticResource Items1Source}}" />
            <CollectionContainer Collection="{Binding Source={StaticResource Items2Source}}" />
            <ListBoxItem>Walterlv End Item 1</ListBoxItem>
            <ListBoxItem>Walterlv End Item 2</ListBoxItem>
        </CompositeCollection>
    </ListBox.ItemsSource>
</ListBox>

关于 CompositeCollection 的使用示例可以参考:

  • How to: Implement a CompositeCollection - Microsoft Docs

神樹桜乃写了一份非 WPF 框架的版本,如果希望在非 WPF 程序中使用,可以参考:

  • Sakuno.Base/ConcatenatedCollectionView`T.cs at master · KodamaSakuno/Sakuno.Base

使用附加属性做缓存,避免内存泄漏

在没有使用 WPF 的时候,如果我们要为一个对象添加属性或者行为,我们可能会使用字典来实现。但字典带来了内存泄漏的问题,要自己处理内存泄漏问题可能会写比较复杂的代码。

然而,WPF 的附加属性可以非常容易地为对象添加属性或者行为,而且也不用担心内存泄漏问题。

例如,我曾经用 WPF 来模拟 UWP 流畅设计(Fluent Design)中的光照效果,使用附加属性来管理此行为则完全不用担心内存泄漏问题:

  • 流畅设计 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟实现啦!

使用 ConditionalWeakTable 做非 WPF 版本的缓存

如果你有一些非 WPF 的对象需要做类似 WPF 那种附加属性,那么可以考虑使用 ConditionalWeakTable 来实现,Key 是那个对象,而 Value 是你需要附加的属性或者行为。

这里的引用关系是 Key 引用着 Value,如果 Key 被回收,那么 Value 也可以被回收。

  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)

使用代码模拟触摸

WPF 默认情况下的触摸是通过 COM 组件 PimcManager 获取到的,在禁用实时触摸后会启用系统的 TOUCH 消息获取到,如果开启了 Pointer 消息那么会使用 POINTER 消息。

我们可以继承自 TouchDevice 来模拟触摸,详见:

  • WPF 模拟触摸设备

模拟 UWP 界面

在现有的 Windowing API 下,系统中看起来非常接近系统级的窗口样式可能都是用不同技术模拟实现的,只是模拟得很像而已。

如果要将 WPF 模拟得很像 UWP,可以参考我的这两篇博客:

  • WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)
  • WPF 应用完全模拟 UWP 的标题栏按钮

模拟 Fluent Design 特效

目前 WPF 还不能直接使用 Windows 10 Fluent Design 特效。当然如果你的程序非常小,那么模拟一下也不会伤害太多性能:

  • 流畅设计 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟实现啦!
  • 在 Windows 10 上为 WPF 窗口添加模糊特效

然而充分利用 Fluent Design 的高性能,需要上 XAML Islands,详见:

  • Using the UWP XAML hosting API in a desktop application - Windows apps | Microsoft Docs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • WPF 程序的编译过程
  • 制作通过 NuGet 分发的源代码包时,如果目标项目是 WPF 则会出现一些问题(探索篇,含解决方案)
  • .NET 的程序集加载上下文
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • Windows 10 解决无法完整下载安装语言包(日语输入法无法下载使用)
  • 从零开始制作 NuGet 源代码包(全面支持 .NET Core / .NET Framework / WPF 项目)
  • 如何快速创建 Visual Studio 代码片段?
  • 从 git 的历史记录中彻底删除文件或文件夹
  • 如果不用 ReSharper,那么 Visual Studio 2019 能还原 ReSharper 多少功能呢?
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • 如何监视 WPF 中的所有窗口,在所有窗口中订阅事件或者附加 UI
  • 如何追踪 WPF 程序中当前获得键盘焦点的元素并显示出来
  • 使用 Visual Studio 编译时,让错误一开始发生时就停止编译(以便及早排查编译错误节省时间)
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .pyc 想到的一些问题
  • [case10]使用RSQL实现端到端的动态查询
  • 【React系列】如何构建React应用程序
  • 【译】理解JavaScript:new 关键字
  • ES6核心特性
  • js写一个简单的选项卡
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Spring Cloud中负载均衡器概览
  • XML已死 ?
  • 记录一下第一次使用npm
  • 普通函数和构造函数的区别
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 温故知新之javascript面向对象
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #pragma multi_compile #pragma shader_feature
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (第27天)Oracle 数据泵转换分区表
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (四)Linux Shell编程——输入输出重定向
  • (转)详解PHP处理密码的几种方式
  • .gitattributes 文件
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .NET 指南:抽象化实现的基类
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .Net6 Api Swagger配置
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • [AIGC] 开源流程引擎哪个好,如何选型?
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [EFI]MSI GF63 Thin 9SCXR电脑 Hackintosh 黑苹果efi引导文件
  • [github配置] 远程访问仓库以及问题解决
  • [ICCV2017]Neural Person Search Machines
  • [javaSE] GUI(Action事件)
  • [JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别
  • [JavaWeb]——获取请求参数的方式(全面!!!)
  • [Linux](15)线程基础,线程控制,线程的互斥与同步
  • [NOI2012]迷失游乐园