乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发 - 实现桌面应用现代化

关于构建现代Windows桌面应用

https://docs.microsoft.com/zh-cn/windows/apps/get-started/

若要构建适用于Windows 11Windows 10的新应用,首先要决定构建哪种类型的应用。Visual Studio中的Windows.NET开发工具提供了几种可以构建的不同类型的应用,每种都有自己的VisualStudio项目类型和不同的优势。

image

每种应用类型都包括应用模型(用于定义应用的生命周期)、默认UI框架(用于创建在Windows桌面环境中运行应用,例如Word和Excel)以及对一组全面的托管API本机API的访问权限(用于使用Windows功能)。其中一些平台有一些共同的特征,更适用于特定类型的应用程序。

无论选择从哪种应用类型开始,你都有权访问大多数Windows平台功能,从而在应用中提供新式体验。例如,即使生成WPF、Windows窗体或经典Win32桌面应用,仍可以使用MSIX包部署Windows OS和Windows SDK提供的Windows运行时(WinRT)API以及Windows应用SDK(Windows App SDK)提供的API

桌面应用类型

https://www.microsoft.com/design/fluent/

应用类型 备注说明
WinUI3 Windows UI库(WinUI)3是适用于Windows桌面应用的初装本机用户界面(UI)框架,包括使用C#和.NET的托管应用以及将C++与Win32API结合使用的本机应用。通过将Fluent Design System整合到所有体验、控件和样式中,WinUI使用最新的UI模式提供一致、直观且可访问的体验。

若要生成WinUI 3应用,请从Windows应用SDK(Windows App SDK)中提供的项目模板之一开始。Windows应用SDK(Windows App SDK)提供了一组统一的API和工具,各种目标Windows OS版本上的任何C++ Win32或C# .NET应用都能够一致地使用它们。
本机Win32 本机Win32桌面应用(有时也称为经典桌面应用)是本机Windows应用程序的原始应用类型,需要具备对Windows和硬件的直接访问权限。这使得此应用类型成为需要最高级别性能和直接访问系统硬件的应用程序的理想选择。

与在托管运行时环境上(如WinRT和.NET)相比,将Win32API与C++结合使用可以实现最高级别的性能和效率,方法是通过使用非托管代码对目标平台进行更多控制。但是,对应用程序的执行进行这种级别的控制需要更加谨慎和更集中的注意力才能正确执行,同时,需牺牲开发效率以提高运行时性能。

以下是Win32API和C++提供的一些主要功能,使你能够生成高性能应用程序。

* 硬件级优化,包括对资源分配、对象生存期、数据布局、对齐、字节封装等的严格控制。
* 通过内部函数访问面向性能的指令集,如SSE和AVX。
* 使用模板进行高效且类型安全的泛型编程。
* 高效且安全的容器和算法。
* DirectX,尤其是Direct3D和DirectCompute(请注意,UWP还提供DirectX互操作)。
* 使用C++/WinRT创建新式桌面Win32应用,这些应用具有对Windows运行时(WinRT)API的一级访问权限
WPF WPF是为托管型Windows应用程序而建立的平台,具有对.NET 5或.NET Framework的访问权限,并使用XAML标记将UI与代码分隔开来。此平台旨在用于需要复杂UI、自定义样式和图形密集型方案的桌面应用程序。WPF开发技能类似于UWP开发技能,因此从WPF迁移到UWP应用比从Windows窗体迁移更容易。
Windows窗体 Windows窗体是用于托管型Windows应用程序的原始平台,具有一个轻型UI模型和对.NET5或.NET Framework的访问权限。它擅长帮助开发人员快速开始构建应用程序,即使对于刚接触该平台的开发人员也是如此。这是一种基于窗体的快速应用程序开发平台,其中包含大量内置的可视化和非可视化拖放控件。Windows窗体不使用XAML,因此,如果决定以后将应用程序扩展到UWP,则需要完全重写UI。
Windows版React Native React Native是Facebook的一个开发平台,可用于构建跨平台应用。React Native for Windows引入了对Windows10和Windows11 SDK的React Native支持,使你能够使用JavaScript为Windows 10和Windows 11支持的所有设备(包括电脑、平板电脑、二合一、Xbox、混合现实设备等)构建本机Windows应用。

通过使用React Native for Windows,可以使用JavaScript或TypeScript编写大部分或全部应用代码,该框架会生成本机UWP XAML应用程序。如果你的应用需要调用平台API,通常可以通过众多社区模块中的某个来实现此目的,或者,如果尚不存在这样一个模块,也可以轻松编写一个本机模块来公开它。
UWP 通用Windows平台(UWP)为所有运行Windows10及更高版本的设备提供通用类型系统、API和应用程序模型。UWP不仅可以用于为Windows电脑创建桌面应用程序,同时,它也是Xbox、HoloLens和SurfaceHub应用程序的唯一支持平台。UWP应用可以是本机应用,也可以是托管应用。

UWP是一个高度可自定义的平台,使用XAML标记将UI(展示)与代码(业务逻辑)分隔。UWP适用于需要复杂UI、自定义样式和图形密集型方案的桌面应用。UWP还针对默认UX体验内置了对FluentDesign系统的支持,并提供了对Windows运行时(WinRT)API的访问。

升级已有桌面应用

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/

如果你当前有WPFWindows窗体本机Win32桌面应用,Windows OS通用Windows应用SDK提供了很多功能可用来在应用中提供新式体验。你可按照自己的进度,在应用中将其中大多数功能用作模块化组件,而不必为其他平台重新编写应用。

有很多功能可用于增强你的现有桌面应用,下面仅举几例:

  • Windows应用SDK NuGet包安装到现有项目中,以调用Windows应用SDKAPI,以在应用中本地化资源、呈现文本等。

https://docs.microsoft.com/zh-cn/windows-app-sdk/get-started.md#use-the-windows-app-sdk-in-an-existing-project

  • 调用Windows运行时(WinRT)API以使用最新的Windows功能增强桌面应用。

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-enhance

  • 使用包扩展,将桌面应用与新式Windows体验集成。例如,将“启动”磁贴指向你的应用,将你的应用设为共享目标,或者通过你的应用发送toast通知。

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-extensions

  • 使用XAML孤岛在桌面应用中托管WinRT XAML控件。很多最新Windows UI功能仅适用于WinRT XAML控件。

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/xaml-islands

  • 使用MSIX打包和部署桌面应用。MSIX是一种新式Windows应用包格式,提供适合所有Windows应用的通用打包体验。MSIX汇集了MSI.appxApp-VClickOnce安装技术的最佳方面,按照安全可靠的目标构建。

https://docs.microsoft.com/zh-cn/windows/msix/

Windows 11的桌面应用中的圆角

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/apply-rounded-corners

圆角是Windows 11几何的最显而易见的特征。在Windows 11上,系统会将所有预装应用(Inbox App)(包括所有UWP应用)和大多数其他应用的顶级窗口自动设为圆角(但可能不会对某些Win32应用执行圆角操作)。

根据设计,应用在最大化、贴靠、在虚拟机(VM)中运行,或者在Windows虚拟桌面(WVD)上运行时不是圆角。

image

我的应用为什么不是圆角的?

如果应用的主窗口未采用自动圆角设置,这是因为你以阻止采用圆角的方式自定义了框架。从桌面窗口管理器(DWM)的角度来看,应用主要分为下面三类:

  1. 默认采用圆角设置的应用。

这包括需要系统提供的完整框架和标题控件(最小值/最大值/关闭按钮)的应用,例如记事本。还包括向系统提供足够信息以便系统可以正确地对它们进行圆角操作的应用,例如设置 WS_THICKFRAMEWS_CAPTION窗口样式或提供1个像素的非工作区边框(系统可以使用该边框设置圆角)。

  1. 根据策略不采用圆角但实际可采用圆角的应用。

此类别中的应用通常希望自定义大多数窗口框架,但仍然需要系统绘制的边框和阴影,例如Microsoft Office。如果应用根据策略未采用圆角,则可能由下述原因之一导致:

  • 缺少框架样式
  • 非工作区为空
  • 其他自定义,例如用于自定义阴影的其他非子窗口

更改其中一项会破坏自动圆角设置。尽管我们确实尝试了使用系统启发式方法为尽可能多的应用设置圆角,但存在一些无法预测的自定义组合,因此我们针对这些情况提供了手动选择加入API。如果你在应用中解决这些问题或调用选择加入API(如以下部分所述),则系统可执行圆角设置。但请注意,该API是对系统的提示,不保证能执行圆角设置,具体取决于自定义项。

  1. 即使调用选择加入API也无法采用圆角的应用。

这些应用没有框架或边框,通常具有高度自定义的UI。如果应用执行以下操作之一,则无法采用圆角设置:

  • 每像素alpha分层
  • 窗口区域

例如,应用可能使用每像素alpha分层在其主窗口周围绘制透明像素,以实现自定义阴影效果,这会使窗口不再是矩形,因此系统无法对其采用圆角。

如何选择使用圆角

a. API定义

https://www.microsoft.com/software-download/windowsinsiderpreviewSDK

如果应用根据策略未采用圆角设置,你可选择性地调用我们新的API,来使你的应用可选择使用圆角。此API表示为要传递到DwmSetWindowAttribute API的枚举值,如新的DWM_WINDOW_CORNER_PREFERENCE枚举中所示。DWM_WINDOW_CORNER_PREFERENCEdwmapi.h标头中定义,且在最新的Insider Preview SDK中提供。

枚举值 说明
DWMWCP_DEFAULT 让系统决定是否对窗口采用圆角设置。
DWMWCP_DONOTROUND 绝不对窗口采用圆角设置。
DWMWCP_ROUND 适当时采用圆角设置。
DWMWCP_ROUNDSMALL 适当时可采用半径较小的圆角设置。

指向此枚举中相应值的指针将传递给DwmSetWindowAttribute的第三个参数。对于指定要设置的属性的第二个参数,传递在DWMWINDOWATTRIBUTE枚举中定义的新DWMWA_WINDOW_CORNER_PREFERENCE值。

b. 对于C#应用

DwmSetWindowAttribute是本机C++ API。如果应用基于.NET并使用C#,则需要使用P/Invoke导入dwmapi.dllDwmSetWindowAttribute函数签名。系统会将所有标准的WinFormsWPF应用像任何其他应用一样自动设为圆角,但如果你自定义了窗口框架或使用第三方框架,并且这样做导致丢失了默认的圆角操作,则可能需要选择加入采用圆角

c. 示例 1 - 在C#中对应用的主窗口采用圆角 - WPF

若要在C# WPF桌面应用中调用DwmSetWindowAttribute,需要使用P/Invoke导入dwmapi.dllDwmSetWindowAttribute函数签名。首先,需要重新定义本机dwmapi.h标头中所需的枚举值,然后使用C#类型来声明等效于原始本机函数的函数。由于原始本机函数采用第三个参数的指针,因此请确保使用ref关键字,以便可以在调用该函数时传递变量的地址。可以在MainWindow.xaml.csMainWindow类中执行此操作。

using System.Runtime.InteropServices;
using System.Windows.Interop;

public partial class MainWindow : Window
{
    // The enum flag for DwmSetWindowAttribute's second parameter, which tells the function what attribute to set.
    public enum DWMWINDOWATTRIBUTE
    {
        DWMWA_WINDOW_CORNER_PREFERENCE = 33
    }

    // The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
    // what value of the enum to set.
    public enum DWM_WINDOW_CORNER_PREFERENCE
    {
        DWMWCP_DEFAULT      = 0,
        DWMWCP_DONOTROUND   = 1,
        DWMWCP_ROUND        = 2,
        DWMWCP_ROUNDSMALL   = 3
    }

    // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function.
    [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern long DwmSetWindowAttribute(IntPtr hwnd,
                                                     DWMWINDOWATTRIBUTE attribute,
                                                     ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute,
                                                     uint cbAttribute);

    // ...
    // Various other definitions
    // ...
}

接下来,在MainWindow构造函数中,在调用InitalizeComponent后创建WindowInteropHelper类的新实例,以获取指向基础HWND窗口句柄)的指针。请确保在显示窗口之前使用EnsureHandle方法强制系统为窗口创建HWND,因为通常系统仅在退出构造函数后创建HWND

public MainWindow()
{
    InitializeComponent();

    IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle();
    var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
    var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND;
    DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));

    // ...
    // Perform any other work necessary
    // ...
}

d. 示例 2 - 在C#中对应用的主窗口采用圆角 - WinForms

WPF一样,对于WinForms应用,首先需要使用P/Invoke导入dwmapi.dllDwmSetWindowAttribute函数签名。可以在主Form类中执行此操作。

using System;
using System.Runtime.InteropServices;

public partial class Form1 : Form
{
    // The enum flag for DwmSetWindowAttribute's second parameter, which tells the function what attribute to set.
    public enum DWMWINDOWATTRIBUTE
    {
        DWMWA_WINDOW_CORNER_PREFERENCE = 33
    }            

    // The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
    // what value of the enum to set.
    public enum DWM_WINDOW_CORNER_PREFERENCE
    {
        DWMWCP_DEFAULT      = 0,
        DWMWCP_DONOTROUND   = 1,
        DWMWCP_ROUND        = 2,
        DWMWCP_ROUNDSMALL   = 3
    }               

    // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function.
    [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern long DwmSetWindowAttribute(IntPtr hwnd, 
                                                     DWMWINDOWATTRIBUTE attribute, 
                                                     ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, 
                                                     uint cbAttribute);
    
    // ...
    // Various other definitions
    // ...
}

调用DwmSetWindowAttribute也与使用WPF应用时相同,但不必使用帮助程序类获取HWND,因为它只是Form的属性。在调用InitializeComponent后,从Form构造函数中调用它。

public Form1()
{
    InitializeComponent();

    var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
    var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND;
    DwmSetWindowAttribute(this.Handle, attribute, ref preference, sizeof(uint));
    
    // ...
    // Perform any other work necessary
    // ...
}

e. 示例 3 - 在C++中对应用的主窗口采用圆角

对于本机C++应用,可以在创建窗口后,在消息处理函数中调用DwmSetWindowAttribute,以要求系统执行圆角设置。

LRESULT ExampleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{
    switch (message)
    {
    // ...
    // Handle various window messages...
    // ...

    case WM_CREATE:
        // ...
        // Perform app resource initialization after window creation
        // ...
        
        if(hWnd)
        {
            DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUND;
            DwmSetWindowAttribute(hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));
        }
        break;

    // ...
    // Handle various other window messages...
    // ...
    }

    return 0;
}

f. 示例 4 - 对菜单采用半径较小的圆角设置 - C++

默认情况下,菜单是弹出窗口,不采用圆角设置。如果你的应用创建一个自定义菜单,而你希望它沿用其他标准菜单的圆角策略,那么你可调用API来让系统知道该窗口应该采用圆角设置,即使它貌似与默认的圆角策略不匹配也是如此。

HWND CreateCustomMenu()
{
    // Call an app-specific helper to make the window, using traditional APIs.
    HWND hWnd = CreateMenuWindowHelper();

    if (hWnd)
    {
        // Make sure we round the window, using the small radius 
        // because menus are auxiliary UI.
        DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
        DwmSetWindowAttribute(hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));
    }

    return hWnd;
}

g. 示例 5 - 自定义窗口内容来采用圆角设置 - C++

当窗口采用圆角设置时,窗口工作区的一小部分会被剪裁掉。某些应用可能需要调整其内容来进行适应。

例如,垂直滚动条的缩略图可能刚好放在窗口的右下角,因此在采用圆角时可能会被剪裁掉。如果这在视觉上来说是不需要的,你可在窗口采用圆角设置时,调整滚动条的位置。不过,由于窗口并非总是采用圆角设置(例如,在最大化时永远不会是圆角),因此你应调用DwmGetWindowAttribute来确定是否需要调整UI以及调整多少。

LRESULT ExampleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{
    switch (message)
    {
    // ...
    // Handle various window messages...
    // ...

    case WM_SIZE:
        // Whenever an interesting size change takes place, there may be a corresponding rounding change.
        int radius = 0;
        if (SUCCEEDED(DwmGetWindowAttribute(hWnd, DWMWA_WINDOW_CORNER_RADIUS, &radius, sizeof(radius))))
        {
            AdjustScrollbarForCornerRadius(radius);
        }
        break;

    // ...
    // Handle various other window messages...
    // ...
    }

    return 0;
}

Windows 11桌面应用中应用贴靠布局菜单

贴靠布局菜单是Windows 11中的一项关键功能,有助于用户了解窗口贴靠的强大功能。借助该菜单,用户只需将鼠标悬停在“最大化”按钮上或按Win+Z,即可快速对窗口进行布局以在更大的屏幕上进行多任务处理,并通过引导式贴靠助手创建整个布局

image

在Windows 11上,如果应用程序提供了“最大化”标题按钮,系统会自动为所有收件箱应用(包括所有UWP应用和大多数其他应用)提供贴靠布局菜单。但是,某些桌面应用可能没有贴靠布局菜单

为什么我的应用没有贴靠布局菜单?

如果应用程序的主窗口提供了“最大化”标题按钮,但没有提供贴靠布局菜单,这可能是由于你已经以阻止标题按钮或标题栏的方式自定义了标题按钮或标题栏

如何选择使用贴靠布局菜单

如果你有自定义标题栏,可以:

  • 使用Windows应用SDK窗口化API ,并让平台绘制和实现标题按钮。

https://docs.microsoft.com/zh-cn/windows/apps/windows-app-sdk/windowing/windowing-overview

  • 对于Win32应用,请确保你正确响应了WM_NCHITTEST (“最大化/还原”按钮的返回值为HTMAXBUTTON)。

https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest

  • 如果应用使用Electron,你可更新到Electron的v13稳定版本,为应用启用贴靠浮出控件

https://www.electronjs.org

有贴靠布局菜单,但无法正确贴靠?

如果应用程序可调用贴靠布局菜单,但无法正确贴靠到贴靠区域,这可能是因为应用程序的最小大小对于贴靠区域来说太大,无法正确适应。

应用程序应支持最大500epx的最小宽度,才可使贴靠正常工作。但是,建议支持更小的最小宽度(330epx或更小),因为它将与更多的设备和贴靠布局兼容。

桌面应用中调用Windows 运行时 API

https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/desktop-to-uwp-enhance

你可以使用Windows运行时(WinRT)API向桌面应用添加令Windows 10/11用户感到满意的新式体验。

首先,使用必需的引用设置项目。然后,从代码中调用Windows运行时API以为桌面应用带来Windows 10/11体验。你可以为Windows 10/11用户单独生成,也可以不考虑用户所运行的Windows版本而向所有用户分发相同的二进制文件。

修改.NET项目以使用Windows 运行时API

有几个用于.NET项目的选项:

  • 从.NET5开始,可以在项目文件中添加目标框架名字对象(TFM),用于访问WinRT API。此选项支持面向Windows10 1809版或更高版本的项目。
  • 对于早期版本的.NET,可以安装Microsoft.Windows.SDK.ContractsNuGet包,以便将所有必要的引用添加到项目中。此选项支持面向Windows10 1803版或更高版本的项目。
  • 如果你的项目同时面向.NET5(或更高版本)和早期版本的.NET等多个目标,可将项目文件配置为同时使用这两个选项。

修改C++ 桌面 (Win32) 项目以使用Windows 运行时 API

通过C++/WinRT来使用Windows运行时APIC++/WinRT是Windows运行时(WinRT)API的完全标准新式C++ 17语言投影,以基于标头文件的库的形式实现,旨在为你提供对新式Windows API的一流访问。

若要为C++/WinRT配置项目,请执行以下操作:

  • 对于新项目,你可以安装`C++/WinRTVisualStudio扩展(VSIX)``,并使用该扩展中包含的其中一个C++/WinRT项目模板。

https://marketplace.visualstudio.com/items?itemName=CppWinRTTeam.cppwinrt101804264

  • 对于现有项目,可以在项目中安装Microsoft.Windows.CppWinRTNuGet包。

https://www.nuget.org/packages/Microsoft.Windows.CppWinRT/

添加Windows 10/11体验

a. 首先,确定要添加的体验

有很多选择。例如,可通过使用盈利API来简化你的采购订单流,或在要分享有趣的内容时(例如其他用户发布了新图片)吸引用户对应用程序的注意。

image

即使用户忽略或关闭你的消息,他们仍可在操作中心中再次看到该消息,然后单击该消息打开你的应用。这可以加强用户与应用程序的互动,并使你的应用程序看似已与操作系统深度集成。稍后,我们将在本文中向你演示用于实现该体验的代码。

b. 决定是增强还是扩展

你经常会听到我们使用术语“增强”和“扩展”,因此我们需要花些时间来说明一下这两个术语的确切含义。

我们使用术语“增强”来描述可以直接从桌面应用对其进行调用的Windows运行时API(无论你是否选择将应用程序打包到MSIX包中)。当你选择Windows 10/11体验后,请确定创建它所需的API,然后查看该API是否出现在此列表中。这是你可以直接从桌面应用中调用的API的列表。如果你的API未出现在此列表中,那是因为与该API关联的功能只在UWP进程内运行。通常情况下,其中包括呈现UWP XAML(例如UWP地图控件或Windows Hello安全提示)的API。

尽管通常不能直接从桌面调用呈现UWPXAML的API,但你可以使用其他方法。如果要托管UWPXAML控件或其他自定义视觉体验,则可以使用XAML岛(从Windows10版本1903开始)和可视化层(从Windows10版本1803开始)。可以在打包或未打包的桌面应用中使用这些功能。

如果已选择将桌面应用打包到MSIX包中,则另一种选择是通过向解决方案中添加UWP项目来“扩展”应用程序。桌面项目仍是应用程序的入口点,但UWP项目使你可以访问此列表中未显示的所有API。桌面应用可以使用应用服务来与UWP进程通信,我们可针对如何进行相关设置提供很多指导。如果你要添加的体验需要UWP项目,请参阅使用UWP组件进行扩展。

c. 引用API协定

如果你可以直接从桌面应用中调用API,请打开浏览器并搜索该API的引用主题。在API的摘要下,你会找到一个描述用于该API的API协定的表。下面是该表的一个示例:

image

如果你有基于.NET的桌面应用,请添加对该API协定的引用,然后将该文件的CopyLocal属性设置为False。如果你有一个基于C++的项目,请将包含此协定的文件夹的路径添加到“附加包含目录”中。

d. 调用API以添加你的体验

https://docs.microsoft.com/zh-cn/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts

以下代码用于显示我们之前看到的通知窗口。此列表中显示了这些API,因此你可以将此代码添加到桌面应用中并立即执行此代码。

支持Windows XP、Windows Vista和Windows 7/8安装库

你可以为适用于Windows 10/11的应用程序增加新式体验,而无需创建新分支和维护不同代码库。

如果要为Windows 10/11用户生成单独的二进制文件,请使用条件编译。如果你希望生成要部署到所有Windows用户的一组二进制文件,请使用运行时检查。

让我们快速查看一下每个选项。

a. 条件编译

你可以保留一个代码库,并编译一组仅面向Windows 10/11用户的二进制文件。

首先,向项目中添加新的生成配置。

image

对于该生成配置,请创建一个常量以标识调用Windows运行时API的代码。

对于基于.NET的项目,该常量称为“条件编译常量”。

image

对于基于C++的项目,该常量称为“预处理器定义”。

image

在任意UWP代码块前添加该常量。

[System.Diagnostics.Conditional("_UWP")]
private void ShowToast()
{
 ...
}
#if _UWP
void UWP::ShowToast()
{
 ...
}
#endif

仅当在活动生成配置中定义了该常量时,编译器才会生成该代码。

b. 运行时检查

可以不考虑用户所运行的Windows版本而为所有Windows用户编译一组二进制文件。仅当用户在Windows 10/11上以打包的应用程序形式运行应用程序时,应用程序才会调用Windows运行时API

https://docs.microsoft.com/zh-cn/archive/blogs/appconsult/desktop-bridge-identify-the-applications-context

向代码添加运行时检查最简单的方法是安装以下Nuget包:桌面桥帮助程序,然后使用IsRunningAsUWP()方法关闭调用Windows运行时API的所有代码。

相关示例

posted @ 2021-09-05 23:08  TaylorShi  阅读(2403)  评论(0编辑  收藏  举报