最近在github上看到一个音乐播放器项目,dopamine(项目地址:GitHub - digimezzo/dopamine-windows: Audio player which tries to make organizing and listening to music as simple and pretty as possible.)
在编译时,提示有一个库找不到

找了好一会,才发现这是调用了UWP的库。
在最初Windows 8 出来时,这一套新的运行时叫Windows RT,后面到Windows 10时,改成了UWP。
因为我也没做过UWP方面的开发,大概了解了一下。里面提供了一些新的API,UI上面也更加炫丽。
所以这里做个总结,如何在WPF中调用UWP的库,以后有需要的时候可以用得到。
===========================================================================
调用UWP API
这里我们以调用一个提供对当前地理位置的访问权限的类为例
Windows.Devices.Geolocation.Geolocator
.Net Framework版本
调用方法比较简单,跟引用其它库一样,直接引用UWP的库即可
1、先引用 Windows.winmd(位置:C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22000.0),后面的版本号以机器上安装的版本为准 。
我也是第一次知道还能引用winmd这种格式

2、引用 System.Runtime.WindowsRuntime.dll(位置:C:\Windows\Microsoft.NET\Framework64\v4.0.30319)
官方博客上说的是C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll这个路径,但我电脑上没有这个文件,所以就到Windows目录下去找了。

.Net Core版本
针对.NET6 及以上版本,直接修改项目工程文件,将目标框架修改为带Windows版本号的即可。
- net6.0-windows10.0.17763.0:Windows 10 版本 1809。
- net6.0-windows10.0.18362.0:Windows 10 版本 1903。
- net6.0-windows10.0.19041.0:Windows 10 版本 2004。
- net6.0-windows10.0.22000.0:Windows 11。
不知道当前系统什么版本,运行输入winver查看

我电脑的系统版本是Windows 1903,所以修改如下:

针对.NET 6以下版本,安装Microsoft.Windows.SDK.Contracts Nuget包。(这里我没测试过)
- 10.0.19041.xxxx:Windows 10 版本 2004
- 10.0.18362.xxxx: Windows 10 版本 1903
- 10.0.17763.xxxx: Windows 10 版本 1809
- 10.0.17134.xxxx: Windows 10 版本 1803
测试
新建一个WPF工程,创建如下测试代码:
xaml
1 <Grid> 2 <Button Content="调用UWP api获取当前地理位置" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"/> 3 </Grid>
xaml.cs
1 private async void Button_Click(object sender, RoutedEventArgs e)
2 {
3 var locator = new Windows.Devices.Geolocation.Geolocator();
4 var location = await locator.GetGeopositionAsync();
5 var position = location.Coordinate.Point.Position;
6 var latlong = string.Format("lat:{0}, long:{1}", position.Latitude, position.Longitude);
7 var result = MessageBox.Show(latlong);
8 }
开启电脑上的定位开关,运行结果如下:

注意:
有两个主要的 WinRT API 集在桌面应用中不受支持或具有限制:
- 需要程序包标识符的 API(请参阅需要程序包标识符的功能)。 此类 API 仅在使用 MSIX 打包的桌面应用中受支持。(应用商店相关)
- 依赖于用户界面 (UI) 功能的 API,这些功能仅在通用 Windows 平台 (UWP) 应用中可用。
基于代码生成 MSIX 程序包可以参考以下链接:基于代码生成 MSIX 程序包概述 - MSIX | Microsoft Learn。这里不做详细介绍了,感兴趣的可以自行了解。
无法在WPF使用UWP跟界面相关的API,解决方案如下:
如何在WPF中使用UWP的控件?
这里主要是借助CommunityToolkit.Wpf.UI.XamlHost包里的WindowsXamlHost控件实现。
以前在WPF中使用Winform控件时,使用了一个叫做WindowsFormHost的控件,原理是创建一个单独的窗口句柄,然后在上面进行绘制。
目测WindowsXamlHost应该也是类似的原理,具体也没有深入了解过。
WindowsXamlHost支持
-
Windows SDK 或 WinUI 库提供UWP 控件
-
自定义 UWP 控件
使用代码创建及显示UWP控件
1、导入Nuget包,Microsoft.Toolkit.UI.XamlHost
2、引用 Windows.winmd
注意:
截止本文发布,
针对.NET Core版本,Microsoft.ToolKit.UI.XamlHost仅支持.NET 5以下版本。以后应该会支持到.NET 5及以后版本
https://learn.microsoft.com/en-us/answers/questions/1010047/does-net6-0-support-xaml-island
针对.Net FrameWork版本,需要添加app.manifest文件,否则运行时会报错。

添加app.manifest文件的方法是启用ClickOnce安全设置,然后再取消即可。

在MainWindow.cs中添加代码如下:
1 public partial class MainWindow : Window
2 {
3 public MainWindow()
4 {
5 InitializeComponent();
6 CreateUWPControlsFirst();
7 }
8
9 private void CreateUWPControlsFirst()
10 {
11 //初始化UWP容器环境
12 Windows.UI.Xaml.Hosting.WindowsXamlManager.InitializeForCurrentThread();
13
14 //创建一个UWP按钮
15 Windows.UI.Xaml.Controls.Button myButton = new Windows.UI.Xaml.Controls.Button();
16 myButton.Name = "btn_Message";
17 myButton.Width = 188;
18 myButton.Height = 48;
19 myButton.TabIndex = 0;
20 myButton.Content = "弹出UWP消息框";
21 myButton.Click += MessageButton_Click;
22 Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost myHostControl = new Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost();
23 myHostControl.Name = "myWindowsXamlHostControl";
24 myHostControl.Child = myButton;
25 myHostControl.HorizontalAlignment = HorizontalAlignment.Center;
26 myHostControl.VerticalAlignment = VerticalAlignment.Center;
27 this.grid.Children.Add(myHostControl);
28 }
29
30 private async void MessageButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
31 {
32 var messageDialog = new MessageDialog("这是一个示例的消息框");
33 messageDialog.Commands.Add(new UICommand(
34 "确定",
35 new UICommandInvokedHandler(this.Confirm)));
36 messageDialog.Commands.Add(new UICommand(
37 "取消",
38 new UICommandInvokedHandler(this.Cancel)));
39 messageDialog.DefaultCommandIndex = 0;
40 messageDialog.CancelCommandIndex = 1;
41 await messageDialog.ShowAsync();
42 }
43
44 private void Confirm(IUICommand command)
45 {
46
47 }
48
49 private void Cancel(IUICommand command)
50 {
51
52 }
53 }
运行效果:

在XAML中直接创建UWP控件
添加命名空间前缀:
1 xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
使用InitialTypeName属性设置初始控件类型
1 InitialTypeName="Windows.UI.Xaml.Controls.CalendarView"
添加当容器里控件渲染后事件处理程序
1 ChildChanged="MyCalendar_ChildChanged"
完整代码如下:
MainWindow.xaml
1 <Window x:Class="HostUWPControl.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:HostUWPControl" 7 xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost" 8 mc:Ignorable="d" 9 Title="MainWindow" Height="450" Width="800"> 10 <Grid Name="grid"> 11 <xamlhost:WindowsXamlHost x:Name="myCalendar" InitialTypeName="Windows.UI.Xaml.Controls.CalendarView" 12 Margin="10,10,10,10" Width="600" Height="300" ChildChanged="MyCalendar_ChildChanged" /> 13 </Grid> 14 </Window>
MainWindow.xaml.cs
1 private void MyCalendar_ChildChanged(object sender, EventArgs e)
2 {
3 WindowsXamlHost windowsXamlHost = (WindowsXamlHost)sender;
4 var calendarView =(Windows.UI.Xaml.Controls.CalendarView)windowsXamlHost.Child;
5 if (calendarView != null)
6 {
7 calendarView.SelectedDatesChanged += (obj, args) =>
8 {
9 if (args.AddedDates.Count > 0)
10 {
11 MessageBox.Show("当前选择的日期是: " + args.AddedDates[0].DateTime.ToString());
12 }
13 };
14 }
15 }
运行效果:

目前已经有部分UWP控件支持直接在XAML中添加,需要对项目进行一定的配置,这里就不做介绍了,上面两种方式在日常开发中应该够用了。后面有时间再更新如何直接在XAML中添加UWP控件。
示例代码
参考文档:
Call Windows Runtime APIs in desktop apps
Call Windows Runtime APIs in desktop apps - Windows apps | Microsoft Learn
Calling Windows 10 APIs From a Desktop Application
Calling Windows 10 APIs From a Desktop Application - Windows Developer Blog
Windows Runtime APIs not supported in desktop apps
桌面应用中不支持的 Windows 运行时 API - Windows apps | Microsoft Learn
Building an MSIX package from your code
基于代码生成 MSIX 程序包概述 - MSIX | Microsoft Learn
Use XAML Islands to host a UWP XAML control
Use XAML Islands to host a UWP XAML control in a C# WPF app - Windows apps | Microsoft Learn
https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/xaml-islands#host-controls


![[Docker][Docker NetWork][下]详细讲解](https://i-blog.csdnimg.cn/direct/f996e9bc2d0e4f16b6d23d1c71f8df63.png)















