从桌面应用程序移动到 UWP

如果你有使用 .NET Framework(包括 WPF 和 Windows 窗体)或 C++ Win32 API 构建的现有桌面应用程序,则可以使用多个选项迁移到 通用 Windows 平台 (UWP) 和 Windows 10/11。

将桌面应用程序打包到 MSIX 包中

可以在 MSIX 包中打包桌面应用程序,以便访问更多 Windows 10 和 Windows 11 功能。 MSIX 是一种新式的 Windows 应用包格式,提供所有 Windows 应用(包括 UWP、WPF、Windows 窗体和 Win32 应用)的通用打包体验。 将桌面 Windows 应用打包到 MSIX 包中即可访问可靠的安装和更新体验、功能系统灵活的托管安全模型、对 Microsoft Store 的支持、企业管理以及许多自定义分发模型。 无论你是否具有源代码,还是只有一个安装程序文件(如 MSI 或 App-V 安装程序),你都可以打包应用程序。 打包应用程序后,可以集成 UWP 功能,例如包扩展和其他 UWP 组件。

有关详细信息,请参阅 从代码需要包标识的功能生成 MSIX 包。

使用 Windows 运行时 API

可以在 WPF、Windows 窗体或 C++ Win32 桌面应用中直接调用许多 Windows 运行时 API,以便集成对 Windows 10 用户来说焕然一新的体验。 例如,可以调用 Windows 运行时 API,以便将 Toast 通知添加到桌面应用。

有关详细信息,请参阅在桌面应用中使用 Windows 运行时 API

将 .NET Framework 应用迁移到 UWP 应用

如果应用程序在 .NET Framework 上运行,可以利用 .NET Standard 2.0 将应用程序迁移到 UWP 应用。 将尽可能多的代码移动到 .NET Standard 2.0 类库中,然后创建可引用 .NET Standard 2.0 库的 UWP 应用。

在 .NET Standard 2.0 库中共享代码

如果应用程序在 .NET Framework 上运行,请将尽可能多的代码放入 .NET Standard 2.0 类库中。 只要代码使用标准中定义的 API,就可以在 UWP 应用中重复使用它。 与在 .NET Standard 库中共享代码比以往更容易,因为 .NET Standard 2.0 中包含了更多 API。

下面的视频将向你介绍相关的详细信息。

添加 .NET Standard 库

首先,将一个或多个 .NET Standard 类库添加到解决方案。

添加 dotnet 标准项目

添加到解决方案的库数取决于计划如何组织代码。

确保每个类库都面向 .NET Standard 2.0

目标 .NET Standard 2.0

可以在类库项目的属性页中找到此设置。

在桌面应用程序项目中,添加对类库项目的引用。

调用 dot NET 项目的类库引用的解决方案资源管理器窗格的屏幕截图。

接下来,使用工具确定代码符合标准的数量。 这样,在将代码移动到库中之前,可以决定可以重复使用哪些部分、哪些部件需要最少的修改,哪些部分将保持应用程序特定的部分。

检查库和代码兼容性

我们将从从第三方获取的 Nuget 包和其他 dll 文件开始。

如果应用程序使用其中任何一个,请确定它们是否与 .NET Standard 2.0 兼容。 可以使用 Visual Studio 扩展或命令行实用工具执行此操作。

使用这些相同的工具分析代码。 在此处下载工具(dotnet-apiport),然后观看此视频,了解如何使用它们。  

如果代码与标准不兼容,请考虑实现该代码的其他方法。 首先打开 .NET API 浏览器。 可以使用该浏览器查看 .NET Standard 2.0 中提供的 API。 请确保将列表的范围限定为 .NET Standard 2.0。

dot net 选项

某些代码特定于平台,需要保留在桌面应用程序项目中。

示例:将数据访问代码迁移到 .NET Standard 2.0 库

假设我们有一个非常基本的 Windows 窗体应用程序,该应用程序显示我们 Northwind 示例数据库中的客户。

Windows 窗体应用

该项目包含一个 .NET Standard 2.0 类库,其中包含名为 Northwind 的静态类。 如果我们将此代码移动到 Northwind 类中,它将不进行编译,因为它使用 SQLConnectionSqlCommandSqlDataReader 类,以及 .NET Standard 2.0 中不可用的那些类。

public static ArrayList GetCustomerNames()
{
    ArrayList customers = new ArrayList();

    using (SqlConnection conn = new SqlConnection())
    {
        conn.ConnectionString = ...; // Your connection string goes here.

        conn.Open();

        SqlCommand command = new SqlCommand("select ContactName from customers order by ContactName asc", conn);

        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                customers.Add(reader[0]);
            }
        }
    }

    return customers;
}

不过,我们可以使用 .NET API 浏览器 查找替代方法。 DbConnection.NET Standard 2.0 中提供了这些和DbCommandDbDataReader类,因此我们可以改用它们。

此修订的版本使用这些类来获取客户列表,但要创建类 DbConnection ,我们需要传入我们在客户端应用程序中创建的工厂对象。

public static ArrayList GetCustomerNames(DbProviderFactory factory)
{
    ArrayList customers = new ArrayList();

    using (DbConnection conn = factory.CreateConnection())
    {
        conn.ConnectionString = ...; // Your connection string goes here.

        conn.Open();

        DbCommand command = factory.CreateCommand();
        command.Connection = conn;
        command.CommandText = "select ContactName from customers order by ContactName asc";

        using (DbDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                customers.Add(reader[0]);
            }
        }
    }

    return customers;
}

在 Windows 窗体的代码隐藏页中,我们只需创建工厂实例并将其传递到方法中。

public partial class Customers : Form
{
    public Customers()
    {
        InitializeComponent();

        dataGridView1.Rows.Clear();

        SqlClientFactory factory = SqlClientFactory.Instance;

        foreach (string customer in Northwind.GetCustomerNames(factory))
        {
            dataGridView1.Rows.Add(customer);
        }
    }
}

创建 UWP 应用

现在,你已准备好将 UWP 应用添加到解决方案。

桌面到 UWP 桥映像

你仍必须设计 XAML 中的 UI 页面并编写任何设备或特定于平台的代码,但完成后,你将能够全面了解 Windows 10 和 Windows 11 设备,你的应用页面将具有适应不同屏幕大小和分辨率的新式感觉。

你的应用将响应除键盘和鼠标以外的输入机制,并且功能与设置在设备之间将直观。 这意味着用户一次了解如何执行操作,然后无论设备如何,它都以非常熟悉的方式工作。

这只是 UWP 附带的一些好处。 若要了解详细信息,请参阅 使用 Windows 构建出色的体验。

添加 UWP 项目

首先,将 UWP 项目添加到解决方案。

UWP 项目

然后,从 UWP 项目添加对 .NET Standard 2.0 库项目的引用。

UWP 解决方案资源管理器 窗格的屏幕截图,其中调用了对 dot NET 项目的类库引用的引用。

生成页面

添加 XAML 页面并调用 .NET Standard 2.0 库中的代码。

UWP 应用

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel x:Name="customerStackPanel">
        <ListView x:Name="customerList"/>
    </StackPanel>
</Grid>
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        SqlClientFactory factory = SqlClientFactory.Instance;

        customerList.ItemsSource = Northwind.GetCustomerNames(factory);
    }
}

若要开始使用 UWP,请参阅 什么是 UWP 应用

访问 iOS 和 Android 设备

可以通过添加 Xamarin 项目来访问 Android 和 iOS 设备。

注意

对于新的跨平台项目,请考虑使用 .NET MAUI。

显示 Android 设备和显示 Xamarin 应用的 i O S 设备的图像。

通过这些项目,可以使用 C# 生成 Android 和 iOS 应用,并完全访问特定于平台的 API 和设备特定的 API。 这些应用利用特定于平台的硬件加速,并编译为本机性能。

他们有权访问基础平台和设备公开的全部功能,包括特定于平台的功能(如 iBeacons 和 Android Fragments),你将使用标准的本机用户界面控件来生成用户期望它们的 UI。

与 UVP 一样,添加 Android 或 iOS 应用的成本较低,因为可以在 .NET Standard 2.0 类库中重复使用业务逻辑。 你必须在 XAML 中设计 UI 页面,并编写任何特定于设备或平台的代码。

添加 Xamarin 项目

首先,将 AndroidiOS跨平台 项目添加到解决方案。

可以在 Visual C# 组下的“添加新项目”对话框中找到这些模板

“添加新项目”对话框的屏幕截图,其中显示了“已安装 > 的 Visual C 锐化”和“Android”、“跨平台”和“i O S”选项。

注意

跨平台项目非常适合没有特定于平台的功能的应用。 可以使用它们生成在 iOS、Android 和 Windows 上运行的基于 XAML 的本机 UI。 在此处了解更多信息。

然后,在 Android、iOS 或跨平台项目中,添加类库项目的引用。

解决方案资源管理器窗格的屏幕截图,其中调用了对 Android、i O S 或跨平台项目的类库引用的引用。

生成页面

我们的示例显示了 Android 应用中的客户列表。

Android 应用

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp" android:textSize="16sp"
    android:id="@android:id/list">
</TextView>
[Activity(Label = "MyAndroidApp", MainLauncher = true)]
public class MainActivity : ListActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SqlClientFactory factory = SqlClientFactory.Instance;

        var customers = (string[])Northwind.GetCustomerNames(factory).ToArray(typeof(string));

        ListAdapter = new ArrayAdapter<string>(this, Resource.Layout.list_item, customers);
    }
}

若要开始使用 Android、iOS 和跨平台项目,请参阅 Xamarin 开发人员门户

后续步骤

查找问题的答案

有问题? 请在 Stack Overflow 上向我们提问。 我们的团队会监视这些标记。 你还可以在此处提问。