.NET Core学习笔记(2)—— WPF使用UWP Custom Control
自.NET Core 3.0开始,某软加入了对WPF的支持。同时对XAML Islands也做了进一步加强。在.NET Core 3.0之前,我们只能在WPF程序中,通过两种方式有限制地使用Standard UWP Control:
微软包装好的第一方控件,比如InkCanvas,InkToolbar,MediaPlayerElement和MapControl,这些可以直接当成WPF的控件写到XAML中。
通过WindowsXamlHost来使用的其他微软第一方Standard UWP Control,这种方式不支持XAML,需要在cs代码中进行类型转换和订阅事件。
这两种方式都存在一些问题:
很多UWP Control和WPF Control虽然同名,但实际仍是不同namespace下的不同class,在传递数据时会遇到很大的麻烦,例如设置FontFamily,Brush时会发现其实是两套同名class,分别属于System.Windows.Media和Windows.UI.Xaml.Media这两套namespace。
不支持XAML导致UI的实现受到极大的限制,对Style和Template的使用极不友好。导致在一个WPF程序中,很难将UI界面上同时存在的WPF Control和UWP Control设置成相同的外观。
而在.NET Core 3.0中,我们终于可以在WPF中嵌入UWP Custom Control。虽仍然是通过WindowsXamlHost来导入Custom Control,但这意味着:
我们可以创建一个独立的UWP Control Library。在该Library中,和UWP API的交互将不存在任何障碍。同时通过良好的封装,将类型转换的逻辑写在内部,对外仅暴露WPF类型的情况下,可以有效的避免UWP Control和WPF Control同名的问题。在外部调用的WPF程序看来,这就是一个纯的WPF Control。
因为Style和Template不再受到限制,对UI的控制力完全释放,我们甚至可以将整个页面放到UWP Custom Control中,制作一个完全使用UWP Control的exe程序。
下面我们就来看看如何具体实现:
首先我们需要安装.NET Core 3.0,在此基础之上我们才可以创建基于.NET Core的WPF程序了。

创建一个空的WPF工程后,在NuGet中搜索Microsoft.Toolkit.Wpf.UI.XamlHost并进行安装。这个Package将提供WindowsXamlHost对象供我们导入UWP Custom Control。完成后,记得将WPF工程的类型,从默认的Any CPU改成x64或者x86。这是因为UWP工程不支持Any CPU。
接下来创建的第二个工程,是一个空的UWP工程,UWP的版本确保是1903或者更新。通过NuGet安装Microsoft.Toolkit.Win32.UI.XamlApplication。这个空的UWP工程将成为WPF程序和UWP Custom Control之间的桥梁。

对于这个空的UWP工程,我们仅需保留App.xml文件,将App的继承关系改为继承自XamlApplication对象。
<xaml:XamlApplication
x:Class="MyUWPApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
xmlns:local="using:MyUWPApp">
</xaml:XamlApplication>
App.xaml.cs中,也仅保留构造函数即可。
sealed partial class App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.Initialize();
}
}
接着将MainPage.xaml文件整个删除,编译通过后,在WPF工程里添加对MyUWPApp的reference,这个中间人的工程就准备完毕了。
接下来让我们创建真正的UWP Custom Control Library。首先选择Class Library(Universal Windows),创建完成后,右键工程文件选择Unload再选择Edit,在工程文件的最下方,添加下述配置项:
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<EnableTypeInfoReflection>false</EnableTypeInfoReflection>
<EnableXBindDiagnostics>false</EnableXBindDiagnostics>
</PropertyGroup>
</Project>
保存后Reload工程。完成上述操作后,再新建几个简单的UWP Custome Control。之后需要在WPF和MyUWPApp这两个工程中,分别添加对UWPClassLibrary工程的reference。这些reference的添加都是必须的,缺少了其中的任何一项,都会导致最终Host UWP Control失败。
此时让我们返回到WPF工程中,开始使用UWPClassLibrary中刚刚创建的UWP Custom Control。
<Grid>
<xaml:WindowsXamlHost InitialTypeName="UWPClassLibrary.SplitViewDemo" ChildChanged="WindowsXamlHost_ChildChanged_1" />
</Grid>
和之前使用微软第一方Control较为类似,也是通过WindowsXamlHost 节点指定类型,以及在ChildChanged事件来进行类型转换获取对象实例。
private void WindowsXamlHost_ChildChanged_1(object sender, EventArgs e)
{
global::Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost windowsXamlHost =
sender as global::Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost;
global::UWPClassLibrary.SplitViewDemo userControl =
windowsXamlHost.GetUwpInternalObject() as global::UWPClassLibrary.SplitViewDemo; if (userControl != null)
{
userControl.IconList = new ObservableCollection<NavItem>
{
new NavItem { Symbol= Symbol.Save},
new NavItem { Symbol= Symbol.Scan},
new NavItem { Symbol= Symbol.Share},
new NavItem { Symbol= Symbol.Stop},
new NavItem { Symbol= Symbol.Video},
new NavItem { Symbol= Symbol.Volume},
};
}
}
在我们的Sample工程中,我将名为SplitViewDemo的UserControl整个丢到了WPF工程的Page中。运行后我们可以发现,这看起来就像是套了WPF外壳的UWP页面。

本篇动手实践的部分较多,还请各位同学下载Sample工程一探究竟。
Github:
.NET Core学习笔记(2)—— WPF使用UWP Custom Control的更多相关文章
- .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]
原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...
- .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]
原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...
- .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- .NET CORE学习笔记系列(2)——依赖注入【3】依赖注入模式
原文:https://www.cnblogs.com/artech/p/net-core-di-03.html IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流 ...
- .NET CORE学习笔记系列(2)——依赖注入【2】基于IoC的设计模式
原文:https://www.cnblogs.com/artech/p/net-core-di-02.html 正如我们在<控制反转>提到过的,很多人将IoC理解为一种“面向对象的设计模式 ...
- .NET CORE学习笔记系列(2)——依赖注入【1】控制反转IOC
原文:https://www.cnblogs.com/artech/p/net-core-di-01.html 一.流程控制的反转 IoC的全名Inverse of Control,翻译成中文就是“控 ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果) 浮雕效果主要有两个参数:Amount和Wid ...
随机推荐
- sql server newid() 的用法
sql newid()随机函数 从A表随机取2条记录,用SELECT TOP 10 * FROM ywle order by newid()order by 一般是根据某一字段排序,newid() ...
- bzoj 4240: 有趣的家庭菜园 树状数组+贪心
有一个小性质:就是一个下标排列的最小移动次数就是逆序对数. 我们发现最终形态一定是一个波峰. 那么我们求的就是形成波峰的下标最少逆序对数. 考虑将元素从小到大依次插入. 那么,对于第 $i$ 个元素, ...
- 「学习笔记」FFT及NTT入门知识
前言 快速傅里叶变换(\(\text{Fast Fourier Transform,FFT}\) )是一种能在\(O(n \log n)\)的时间内完成多项式乘法的算法,在\(OI\)中的应用很多,是 ...
- 基于部标1078视频协议和苏标Adas协议构建主动安全平台
苏标本身仍然是基于部标808协议的基础上递增起草的,苏标协议是包容808协议的, 不能脱离808协议而独立存在的, 主要基于<JT/T 796 道路运输车辆卫星定位系统平台技术要求>.&l ...
- 全国行政区域代码(免费来拿) xls格式 可直接导入
全部区域代码 地址:https://pan.baidu.com/s/1Elz-zW_nLS8YR8GZAn3WRw 提取码:ze3s
- 搜索sqlserver 存储过程中的关键字
搜索sqlserver 存储过程中的关键字 select * from sys.all_sql_modules where definition like '%SP_NAME%'
- TCP HTTP SOCKET之间的有什么关系
网络由下往上分为 物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层, 三者从本质上来说没有可 ...
- js的一些兼容性易错的的问题
一.属性相关 我们通常把特征(attribute)和属性(property)统称为属性,但是他们确实是不同的概念,特征(attribute)会表现在HTML文本中,对特征的修改一定会表现在元素的out ...
- git sub module
https://github.com/ViRb3/de4dot-cex/blob/master/.gitmodules git submodule sync command - what is it ...
- Javascript-基本类型
数字 JavaScript不区分整数和浮点数,所有数字都用浮点数表示. 能够表示最大值是 -253 ~ 253,包含边界.超过范围的数无法保证低位数字的精度. JavaScript能直接识别十进制的整 ...