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

WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件

在 WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit) 一文中,我们说到了在 WPF 中引入简单的 UWP 控件以及相关的注意事项。不过,通常更有实际价值的是更复杂的 UWP 控件的引入,通常是一整个 Page。

本文将介绍如何在 WPF 项目中引用 UWP 的控件库。


本文内容

      • 创建一个 UWP 控件库
      • 对 WPF 项目的准备工作
      • 不方便的引入方式
      • 编辑 UWP 项目文件
      • 重新加载项目并编译
      • 在 WPF 项目中间接引用 UWP 控件库
      • 在 WPF 项目中使用 UWP 控件库中的控件
        • 参考资料

创建一个 UWP 控件库

建议专门为你复杂的 UWP 控件创建一个 UWP 控件库。在这个控件库中的开发就像普通 UWP 应用一样。这样比较容易创建出更复杂的 UWP 控件出来,而不会与 WPF 项目产生太多的影响。

创建一个 UWP 控件库
▲ 创建一个 UWP 控件库

选择 SDK 版本
▲ 选择 SDK 版本

对 WPF 项目的准备工作

你依然需要阅读 WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit) 一文,以便将你的 WPF 项目改造成可以访问 UWP 类型的项目。

不方便的引入方式

你如果直接让 WPF 项目添加 UWP 项目的引用,将会得到一个错误提示:

不能引用

也就是说并不能直接完成这样的引用。

也许将来 WPF 项目格式更新或者 Visual Studio 的更新能为我们带来这样更直接此引用方式。不过现在来看,还不能如此方便地使用。

编辑 UWP 项目文件

是的,你需要手工编写 UWP 的项目文件。

如果你阅读过 (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 这篇文章,或者已经 理解了 C# 项目 csproj 文件格式的本质和编译流程,那么对这里 csproj 文件的编辑应该不会感觉到陌生或者害怕。当然,即便你没有编辑过或者不理解 csproj 也不用担心,你只需要按照本文要求进行操作即可。

现在,右击卸载项目,再右击编辑项目文件:

编辑项目文件
▲ 编辑项目文件

找到 Import targets 的哪一行,你需要在那一行前面的任意位置添加以下特别标注为新增的几行:

++  <PropertyGroup>
++    <EnableTypeInfoReflection>false</EnableTypeInfoReflection>
++    <EnableXBindDiagnostics>false</EnableXBindDiagnostics>
++  </PropertyGroup>
    <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />

随后,还要在以上 targets 之后再添加以下代码:

<PropertyGroup>
  <!-- 这里需要填写你的 WPF 项目的路径 -->
  <HostFrameworkProjectFolder>$(ProjectDir)..\Whitman.Wpf</HostFrameworkProjectFolder>
  <ObjPath>obj\$(Platform)\$(Configuration)\</ObjPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
  <ObjPath>obj\$(Configuration)\</ObjPath>
</PropertyGroup>
<PropertyGroup>
  <!-- 把此项目的输出文件都拷贝到 WPF 项目的生成路径下 -->
  <PostBuildEvent>
    md $(HostFrameworkProjectFolder)\$(ProjectName)
    md $(HostFrameworkProjectFolder)\bin\$(Configuration)\$(ProjectName)
    copy $(TargetDir)*.xbf            $(HostFrameworkProjectFolder)\bin\$(Configuration)\$(ProjectName)
    copy $(ProjectDir)*.xaml          $(HostFrameworkProjectFolder)\bin\$(Configuration)\$(ProjectName)
    copy $(ProjectDir)*.xaml.cs       $(HostFrameworkProjectFolder)\$(ProjectName)
    copy $(ProjectDir)$(ObjPath)*.g.* $(HostFrameworkProjectFolder)\$(ProjectName)
  </PostBuildEvent>
</PropertyGroup>

需要注意:

  • 一定要在 targets 之后添加这些代码,因为 $(TargetDir)$(ProjectName) 等属性是在那里的 targets 执行完后才生成的。
  • 你的 UWP 项目中需要有 xaml,比如可以添加一个 MainPage.xaml 和 MainPage.xaml.cs,不然编译的时候可能会出现错误。

重新加载项目并编译

现在,重新加载那个 UWP 控件库,将其编译,以便将 UWP 项目的生成文件复制到 WPF 目录下。

生成的文件已复制到 WPF 目录下
▲ 生成的文件已复制到 WPF 目录下

在 WPF 项目中间接引用 UWP 控件库

现在,在 WPF 项目中开启所有文件夹的显示,然后将 UWP 项目中生成的文件添加到 WPF 项目中:

在 WPF 的项目中添加 UWP 的控件库
▲ 在 WPF 的项目中添加 UWP 的控件库

为了能够在每次编译 WPF 项目的时候确保 UWP 项目先编译,需要为 WPF 项目设置项目依赖。在依赖对话框中将 UWP 项目设为依赖。

添加项目依赖
▲ 添加项目依赖

现在,编译 WPF 项目的时候,会将 UWP 项目编译后的源码也一起编译到 WPF 项目中;相当于间接使用了 UWP 的控件库。

特别的,如果你的项目被 git 进行版本管理,你可能需要忽略 UWP 控件库项目中的文件。方法是在 WPF 项目内生成的 UWP 文件夹下添加一个 .gitignore 文件,填写所有内容忽略:

*.*

忽略所有内容

但记得需要额外通过 git add ./Whitman.Wpf/Whitman.Uwp/.gitignore 把这个文件添加到版本管理中,不然其他人不会生效。

在 WPF 项目中使用 UWP 控件库中的控件

这时,在 WindowsXamlHost 中就可以添加 UWP 控件库中的 MainPage 了。

<XamlHost:WindowsXamlHost InitialTypeName="Walterlv.Whitman.Universal.MainPage" />

于是,你可以在局部获得 UWP 完整 Page 的支持。或者你整个界面都是用 UWP 开发都没问题,并且还能获得 .NET Framework 的完全访问支持。(当然,未来一定是 .NET Core。)

运行后的效果
▲ 运行后的效果

可以使用 UWP 的 Page,并且也能弹出 UWP 的 MessageDialog

而 MainPage 就是普通的 UWP MainPage:

<Page
    x:Class="Walterlv.Whitman.Universal.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Walterlv.Whitman.Universal"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel Width="400" VerticalAlignment="Center">
        <TextBlock>
            <Run Text="欢迎访问 吕毅的博客" />
            <LineBreak />
            <Run Text="https://walterlv.com" />
        </TextBlock>
        <Button Content="Click" Click="DemoButton_Click" />
    </StackPanel>
</Page>
using System;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Walterlv.Whitman.Universal
{
    public sealed partial class MainPage : Page
    {
        public MainPage() => InitializeComponent();

        private async void DemoButton_Click(object sender, RoutedEventArgs e)
        {
            var button = (Button) sender;
            await new MessageDialog("UWP 的消息框,在 WPF 的窗口中。", "walterlv").ShowAsync();
        }
    }
}

参考资料

  • WindowsXAMLHost control - Windows Community Toolkit - Microsoft Docs
  • Enhance your desktop application for Windows 10 - UWP app developer - Microsoft Docs

相关文章:

  • WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • 编写 Target 检测 MSBuild / dotnet build 此次编译是否是差量编译
  • 使用 Win2D 绘制带图片纹理的圆(或椭圆)
  • Win2D 中的游戏循环:CanvasAnimatedControl
  • 使用 Windows 10 中的加速度计(Accelerometer,重力传感器)
  • 用 dotTrace 进行性能分析时,各种不同性能分析选项的含义和用途
  • 如何创建一个基于 .NET Core 3 的 WPF 项目
  • 将基于 .NET Framework 的 WPF 项目迁移到基于 .NET Core 3
  • 了解 .NET 的默认 TaskScheduler 和线程池(ThreadPool)设置,避免让 Task.Run 的性能急剧降低
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • 在有 UI 线程参与的同步锁(如 AutoResetEvent)内部使用 await 可能导致死锁
  • 不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 LazyT 中导致死锁
  • 定义一组抽象的 Awaiter 的实现接口,你下次写自己的 await 可等待对象时将更加方便
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • [数据结构]链表的实现在PHP中
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • angular2开源库收集
  • chrome扩展demo1-小时钟
  • CSS实用技巧干货
  • ESLint简单操作
  • Git同步原始仓库到Fork仓库中
  • httpie使用详解
  • SpringBoot几种定时任务的实现方式
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • Vue ES6 Jade Scss Webpack Gulp
  • Yii源码解读-服务定位器(Service Locator)
  • 阿里云应用高可用服务公测发布
  • 创建一个Struts2项目maven 方式
  • 看域名解析域名安全对SEO的影响
  • 七牛云假注销小指南
  • 如何在 Tornado 中实现 Middleware
  • 试着探索高并发下的系统架构面貌
  • 手写一个CommonJS打包工具(一)
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • $.ajax()
  • $.proxy和$.extend
  • (1)Android开发优化---------UI优化
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (C语言)字符分类函数
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (利用IDEA+Maven)定制属于自己的jar包
  • (六)vue-router+UI组件库
  • (算法设计与分析)第一章算法概述-习题
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (转)linux下的时间函数使用
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .Net Core缓存组件(MemoryCache)源码解析