DotNetCore 3.0 助力 WPF 开发

前言

Visual Studio 2019 已经正式发布了,DotNetCore 3.0 的正式版也指日可待。在之前的版本中,作为一名基于微软生态的传统 WPF 程序员看着隔壁同学在开发 DotNetCore 网站时用着各种特性好生羡慕,想着巨硬啥时候能让客户端开发者也能尝尝甜头。

那么,现在是时候可以尝试一下了。

需要说明的一点的是,DotNetCore 3.0 虽然跨平台,但是基于此的 WPF 却是针对 Windows 特定平台的实现,并不能跨 Linux 和 MacOS 。

开发环境准备

要想开发 DotNetCore 版本的 WPF,首先需要确保我们的机器上已经安装了如下

  • Visual Studio 2019 下载地址

需要安装的组件如下图所示

640?wx_fmt=png

640?wx_fmt=png

  • DotNetCore 3.0 SDK 下载地址

直接默认安装即可。

全新的开发体验

在首次使用 VS2019 创建 DotNetCore 版本的 WPF 程序时,VS 可能会给你爆个如下图所示的错误:

640?wx_fmt=png

按照错误提示即可解决该问题,如下图所示

640?wx_fmt=png

接着选择 TOOLS -> Options,配置如下图所示

640?wx_fmt=png

Hello World

首先,我们可以通过 VS 创建一个基于 DotNetCore 的 项目模板,然后我们看一下与传统的 WPF 项目模板有什么区别。如下图所示,创建一个 WPF 项目

640?wx_fmt=png

创建完成后,尝试编译编译运行(注:第一次编译可能需要较长时间),如下图所示

640?wx_fmt=png

如果我们仔细看一下这个新版的项目模板,会发现与传统的项目模板相比,有好几处发生了改变:

  • **.csproj 的组织方式发生了改变,与传统的组织方式相比,内容精简的快没有了;

  • 项目默认会引用 Microsoft.NETCore.Platforms 和 Microsoft.WindowsDesktop.App,这两个 Package 都是针对 WinForm 和 WPF 的特定包

  • 项目属性中也有一些改动

  • 生成目录中也有改动,会生成一些以 json 结尾的文件

上述这些改动都是最直观的改动,但是这些改动貌似不痛不痒,并不能吸引传统 WPF 开发者投入使用。接触过 DotNetCore Web 方向的开发者已经对里面的 DI,HttpClientFactory,EFCore 等使用的炉火纯青,那我们能不能在 WPF 中也使用这些东西呢?答案是必须要能啊,所有我们还需要探索一下它的一些硬核功能。下面列举几个我目前知道的几个我觉得很炫酷的功能。

使用 DI 和 Service Provider

能够使用 DI 和 Service Provider,这是我觉得最值得说一下的,因为它的使用方式简直和在 DotNetCore Web 里面的一摸一样,值得一说。

首先,我们创建一个 DotNetCore 版本的 WPF 项目,然后引用如下包:

  • Microsoft.Extensions.DependencyInjection

  • Microsoft.Extensions.Options.ConfigurationExtensions

  • Microsoft.Extensions.Configuration.FileExtensions

  • Microsoft.Extensions.Configuration.Json

注:上述包都需要安装 预览版本的 3.0.0 版本的才行

然后,在我们的项目根目录下创建一个 appsettings.json 文件,文件内容如下所示:

{
"AppSettings": {
"StringSetting": "Value",
"IntegerSetting": 42,
"BooleanSetting": true
}
}

然后将该文件的 Build Action 设置为 ContentCopy To Output Directiory 设置为 Copy if newer

接着,我们在项目根目录下创建一个 AppSettings.cs 文件,用于隐射上面的 appsettings.json 文件,示例代码如下所示:

public class AppSettings
{
public string StringSetting { get; set; }

public int IntegerSetting { get; set; }

public bool BooleanSetting { get; set; }
}

然后,我们创建一个自定义的接口服务 ISampleService和对应实现 SampleService,示例代码如下所示:

public interface ISampleService
{
string GetCurrentDate();
}

public class SampleService : ISampleService
{
public string GetCurrentDate() => DateTime.Now.ToLongDateString();
}

然后,修改我们的 App.xaml 文件,删除掉默认添加的启动视图代码 StartupUri="MainWindow.xaml"

接着,修改我们的 App.xaml.cs 文件,示例代码如下所示:

public partial class App : Application
{
public IServiceProvider ServiceProvider { get; private set; }

public IConfiguration Configuration { get; private set; }

protected override void OnStartup(StartupEventArgs e)
{
// 初始化配置建造器
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

// 获取配置建造器创建的对象
Configuration = builder.Build();

//配置全局服务容器
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);

ServiceProvider = serviceCollection.BuildServiceProvider();

var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}

private void ConfigureServices(IServiceCollection services)
{
// 向全局容器中注册一个视图
services.AddTransient(typeof(MainWindow));

// 在全局容器中配置 AppSettings
services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));

// 在全局容器中注册自定义服务
services.AddScoped<ISampleService, SampleService>();
}
}

修改完毕后,我们可以尝试编译我们的项目,如果不出意外的啊,我们的程序会正常启动起来。这里就不做截图说明了。

看了上述代码,是不是觉得很有意思啊,这种全新的开发模式顿时把我们的代码水平提升了好几个档次。这种使用方式和在 AspDotNetCore 简直一摸一样。比如,我们在上面注册了 AppSettings 和一个基于 ISampleService 接口的实现 SampleService,那么我们就可以在 MainWindow 的构造函数中使用,比如,我们可以参考下面的示例代码:

    public partial class MainWindow : Window
{
private readonly ISampleService _sampleService;
private readonly IOptions<AppSettings> _settings;
public MainWindow(ISampleService sampleService, IOptions<AppSettings> settings)
{
InitializeComponent();

_sampleService = sampleService;
var val = _sampleService.GetCurrentDate();

_settings = settings;
}

private void ButtonExit_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}

然后,我们可以监视一下 **_settings** 的值,如下图所示:

640?wx_fmt=png

通过这个简单的例子,我们可以看到这种全新方式的依赖注入已经得到微软的大力支持,将基于 .NetCore 的 CS模式 和 BS模式 开发方式进行了统一,学习曲线是不是又下降了很多啊。

使用 HttpClientFactory

众所周知,HttpClient 在实际的使用场景中还是存在一些弊端,在 DotNetCore 的 Web 端中,很多同学用了 HttpClientFactory 如鱼得水,减少了很多不必要的麻烦。现在,我们同样可以将这一利器在 WPF 中使用。

我们新建一个基于 DotNetCore 3.0 的 WPF 项目,然后引入如下包:

  • Microsoft.Extensions.DependencyInjection

  • Microsoft.Extensions.Http

然后,修改我们的 App.xaml 文件,删除掉默认添加的启动视图代码 StartupUri="MainWindow.xaml",并修改 App.xaml.cs 文件,示例代码如下所示:

public partial class App : Application
{
public ServiceProvider ServiceProvider { get; private set; }

protected override void OnStartup(StartupEventArgs e)
{
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);

ServiceProvider = serviceCollection.BuildServiceProvider();

var mainView = ServiceProvider.GetRequiredService<MainWindow>();
mainView.Show();

base.OnStartup(e);
}

private void ConfigureServices(ServiceCollection services)
{
services.AddHttpClient();
services.AddTransient(typeof(MainWindow));
}
}

最后,修改我们的 MainWindow.xaml.cs 文件,示例代码如下所示:

public partial class MainWindow : Window
{
private readonly IHttpClientFactory _httpClientFactory;
public MainWindow(IHttpClientFactory httpClientFactory)
{
InitializeComponent();

_httpClientFactory = httpClientFactory;
}

private async void ButtonExit_Click(object sender, RoutedEventArgs e)
{
var client = _httpClientFactory.CreateClient();
var html = await client.GetStringAsync("http://www.baidu.com");
//Application.Current.Shutdown();
}
}

这就是关于 HttpClientFactory 的简单使用。

使用 EFCore

最后介绍的一大利器就是巨硬的 EFCore,这个东西也很溜,值得我们尝试使用。这里我使用 Sqlite 为例。

我们新建一个基于 DotNetCore 3.0 的 WPF 项目,然后引入如下包:

  • Microsoft.Extensions.DependencyInjection

  • Microsoft.Extensions.Configuration.FileExtensions

  • Microsoft.Extensions.Configuration.Json

  • Microsoft.EntityFrameworkCore.Sqlite

首先,我们参考上面提到的使用方式,在项目根目录下创建一个 appsettings.json,文件,修改内容如下所示:

{
"ConnectionStrings": {
"SqlConnection": "datasource = default.sqlite"
}
}

然后将该文件的 Build Action 设置为 ContentCopy To Output Directiory 设置为 Copy if newer

接着,我们创建一个 DataContext 类,示例代码如下所示:

public class DataContext : DbContext
{
public DataContext(DbContextOptions options) : base(options)
{
this.Database.Migrate();
}
}

然后删除掉 App.xaml 中的 StartupUri="MainWindow.xaml",并修改 App.xaml.cs,示例代码如下所示:

public partial class App : Application
{
public ServiceProvider ServiceProvider { get; private set; }
public IConfigurationRoot Configuration { get; private set; }

protected override void OnStartup(StartupEventArgs e)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

Configuration = builder.Build();

var serviceCollection = new ServiceCollection();
ConfigurationServices(serviceCollection);

ServiceProvider = serviceCollection.BuildServiceProvider();
var mainView = ServiceProvider.GetRequiredService<MainWindow>();
mainView.Show();

base.OnStartup(e);
}

private void ConfigurationServices(ServiceCollection services)
{
services.AddTransient(typeof(MainWindow));

services.AddDbContext<DataContext>(options=>options.UseSqlite(Configuration.GetConnectionString("SqlConnection")));
}
}

然后我们修改 MainWindow.xaml.cs,示例代码如下所示:

public partial class MainWindow : Window
{
private readonly DataContext _dataContext;

public MainWindow(DataContext dataContext)
{
InitializeComponent();

_dataContext = dataContext;
}

private void ButtonExit_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}

使用方法依然很简单。

支持 UWP 相关控件 和 Windows10 API

传统的 WPF 客户端,如果使用基于 UWP 的相关控件,则可以通过使用 WindowsCommunityToolkit控件库来使用 UWP 的相关控件,该控件库目前可能还不是很完善,但是微软已经在不断添加新功能了。

UWP 是未来发展的趋势,但是对于传统的 WPF,如果想像 UWP 那样也能使用功能更加强大的 API,只需要通过简单添加一些引用就可以实现。微软之前有发布过具体使用的文章,文末有给出链接。

发布方式

基于 DotNetCore 3.0 的 WPF 项目发布方式还是和传统的 WPF 项目发布方式有所差异。全新的发布方式是基于 DotNetCore 的风格来进行设计的。在 Publish 的选项卡中,我们可以看到如下配置

640?wx_fmt=png

我们可以依据具体情况,来选择合适的发布方式进行发布。当然,我们也可以借助 Desktop App Converter 工具,将我们的应用分发到 windows Store 上。

总结

通过上述几个简单的示例,我们可以看到传统的 WPF 已经被微软注入了新鲜的血液,并且在微软生态下的 C/S端 和 B/S端 开发模式渐趋相同。大大减轻了学习曲线。能够让技术在最短的时间里变现,这也是我最看重的地方。

无论是过去还是现在,我都时不时地听身边的人说不应该过度依赖工具,但是我想说的是 技术服务于现实,而工具只是为了加速变现,如果一项技术再好再优秀,它却不能创造现实价值,服务生活,那么我宁愿放弃使用它。微软为开发者提供了 DotNetCore 的好技术,而 VisualStudio 系列工具作为生产力工具,只是为了提高生产效率。在效率为王的今天,谁赢得了时间,就赢得了一切。

最后,我不打算吹捧 DotNetCoreWPFVisualStudio,以免有人说我会误导萌新。还是那句话,实践出真知,感兴趣的话可以自己动手尝试一下。此外,目前 DotNetCore 3.0 还是处于预览阶段,所以可能会有一些坑。但是谁能保证自己第一次就能把事情做的完美呢?时间会证明一切。

补充

评论中很多朋友问到跨平台的问题,所以我补充了一张图。

640?wx_fmt=png

相关参考

  • What's new in .NET Core 3.0 (Preview 2)

  • Around and About .NET World

  • Calling Windows 10 APIs From a Desktop Application

原文地址:https://www.cnblogs.com/hippieZhou/p/10637348.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

H - Square Card HDU - 7063

H - Square Card HDU - 7063 题意&#xff1a; 有两个圆形区域&#xff0c;一个是得分区域&#xff0c;一个是获得奖金区域&#xff0c;现在你有一个边长为a的正方形,当正方形在如果在某一时刻它严格在圆形范围内&#xff0c;才算合法。 问把牌扔到任意的位置被得分和同时获得…

《从零开始学ASP.NET CORE MVC》:VS2019创建ASP.NET Core Web程序(三)

创建ASP.NET Core Web应用程序如果您使用的是VS2017请看 VS2017创建ASP.NET Core Web程序(三)在这个视频中我们将讨论可用的不同项目模板及其功能预制的项目模板有什么不同&#xff0c;哪些是可以使用的&#xff0c;以及他们的作用。在Visual Studio 2019中创建新的ASP.NET Cor…

ASP.NET Core 沉思录 - 结构化日志

在 《ASP.NET Core 沉思录 - Logging 的两种介入方法》中我们介绍了 ASP.NET Core 中日志的基本设计结构。这一次我们来观察日志记录的格式&#xff0c;并进一步考虑如何在应用程序中根据不同的需求选择不同的日志记录形式。太长不读&#xff1a;直接飞到文章最后 :-DMicrosoft…

为什么我们要做单元测试?(二)

引子当我第一篇博客发布&#xff0c;并被张善友老师的公众号转载之后&#xff0c;在公众号文章和博客园的留言中&#xff0c;许多开发者纷纷表示&#xff0c;单元测试作为企业行为&#xff0c;与实施的技术栈不同&#xff0c;不是开发者个人行为&#xff0c;实施单元测试花费的…

P4159 [SCOI2009] 迷路

P4159 [SCOI2009] 迷路 题意&#xff1a; 该有向图有 n 个节点&#xff0c;节点从 1 至 nn 编号&#xff0c;windy 从节点 1 出发&#xff0c;他必须恰好在 t 时刻到达节点 n。 现在给出该有向图(带边权)&#xff0c;你能告诉 windy 总共有多少种不同的路径吗&#xff1f; …

程序员修神之路--提高网站的吞吐量

点击上方蓝色字体&#xff0c;关注我们菜菜哥&#xff0c;有个事你还得帮我呀呦西&#xff0c;YY妹子&#xff0c;最近天这么热了&#xff0c;你怎么还穿这么多&#xff1f;苦笑一下.....前几天写了几个接口&#xff0c;领导让提高一下接口吞吐量这是你技术提高的大好机会呀可吞…

一份.NET 容器化的调查小结

小编在上个月在微信公众号“dotnet跨平台” 做了一个针对.NET 容器化的调查&#xff1a;.NET Core 容器化调查&#xff0c;参与人数702人&#xff0c;由于软件定义基础设施方兴未艾&#xff0c;编排和自动化领域kubernetes占据了主体地位&#xff0c;在平时的工作中和身边的同学…

P2148 [SDOI2009]ED

P2148 [SDOI2009]E&D 题意&#xff1a; 有2n堆石子&#xff0c;第2k-1堆和第2k堆是一组&#xff0c;现在两个人轮流操作&#xff0c;每次操作任选一组石子&#xff0c;然后将改组中的一堆石子移走&#xff0c;将另一堆式子分割成两堆&#xff0c;形成新的两堆石子&#x…

扒一扒.NET Core的环境配置提供程序

前言很久之前&#xff0c;在玩Docker的时候顺便扒了扒&#xff0c;最近&#xff0c;终于下定决心花了些时间整理并成文&#xff0c;希望能够给大家一些帮助。目录 .NET Core中的配置ASP.NET Core中的配置扒一扒环境变量提供程序为什么是“__”&#xff1f;“__”如何变成了“&…

[HNOI2016] 序列(线段树 + 莫队 + 倍增)

problem luogu-P3246 心路历程卡常历程问题存疑 一直在想莫队的做法。发现左右指针的移动对应一段左/右端点固定的子序列&#xff0c;然后可以一个数代表一段相同的贡献。 就开始求 lsti,nxtilst_i,nxt_ilsti​,nxti​ 了。 仔细想想需要找到 lstlsti<l≤lstilst_{lst_…

《从零开始学ASP.NET CORE MVC》:ASP.NET Core 中的 Main方法(5)

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core Web 项目文件ASP.NET Core 中的 Main方法一个开始专心写字的人在ASP.NET Core项目中&#xff0c;我们有一个名为Program.cs的文件。在这个文件中&#xff0c;我们有一个public static void Main&#…

.NET中的状态机库Stateless

标题&#xff1a;.NET中的状态机库Stateless 作者&#xff1a;Lamond Lu 地址&#xff1a;https://www.cnblogs.com/lwqlun/p/10674018.html[1]介绍什么是状态机和状态模式状态机是一种用来进行对象建模的工具&#xff0c;它是一个有向图形&#xff0c;由一组节点和一组相应的转…

.net core webapi 前后端开发分离后的配置和部署

背景&#xff1a;现在越来越多的企业都采用了在开发上前后端分离&#xff0c;前后端开发上的分离有很多种&#xff0c;那么今天&#xff0c;我来分享一下项目中得的前后端分离。B/S Saas 项目&#xff1a;&#xff08;这个项目可以理解成个人中心&#xff0c;当然不止这么点功…

ASP.NET Core使用Jaeger实现分布式追踪

前言最近我们公司的部分.NET Core的项目接入了Jaeger&#xff0c;也算是稍微完善了一下.NET团队的技术栈。至于为什么选择Jaeger而不是Skywalking&#xff0c;这个问题我只能回答&#xff0c;大佬们说了算。前段时间也在CSharpCorner写过一篇类似的介绍Exploring Distributed T…

长沙开发者技术大会暨.NET技术社区成立大会倒数第13天

待你扬帆起航&#xff0c;一起精彩纷呈&#xff01;长沙开发者技术大会暨.NET技术社区成立大会倒数第13天&#xff01;2019年4月21日期待与你相聚在.NET技术社区&#xff01;我们今天会完成海报制作和报表表单&#xff0c;海报内容初步如下所示&#xff1a;活动信息 长沙开发者…

C#并行编程(1):理解并行

什么是并行并行是指两个或者多个事件在同一时刻发生。在程序运行中&#xff0c;并行指多个CPU核心同时执行不同的任务&#xff1b;对于单核心CPU,严格来说是没有程序并行的。并行是为了提高任务执行效率&#xff0c;更快的获取结果。与并发的区别&#xff1a;并发是指两个或者多…

P2163 [SHOI2007]园丁的烦恼(二维数点模板题)

P2163 [SHOI2007]园丁的烦恼 题意&#xff1a; 在一个二维平面内有一些点&#xff0c;给你一个左上角和右下角的点&#xff0c;问这个范围内有多少点 题解&#xff1a; 二维数点模板题 我们设F(a,b)表示以(0,0)为左下角&#xff0c;(a,b)为右上角的矩阵内有多少点 如图不难…

Orleans MultiClient 多个Silo复合客户端

介绍Orleans.MultiClient 是一个 Orleans 复合客户端&#xff0c;只需要简单配置就可以简单高效连接和请求 Orleans 服务。Orleans.MultiClient 可以轻松连接多个不同服务的 Orleans 服务,在请求 Orleans 时会根据请求的接口自动寻找 Orleans 客户端&#xff0c;使用者无需关心…

ASP.NET Core 进程内(InProcess)托管(6)《从零开始学ASP.NET CORE MVC》:

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core 中的 Main方法ASP.NET Core 进程内(InProcess)托管在这个视频中我们将讨论在ASP.NET Core中的进程内(InProcess)托管模型什么是Kestrel服务器当一个 ASP.NET Core 应用程序执行的时候&#xff0c;.NET…

约会安排 HDU - 4553

约会安排 HDU - 4553 题意&#xff1a; 题意又丑又长就不叙述了 题解&#xff1a; 这个题一开始理解错了。。。题目相当于是有三种情况占据时间&#xff0c;分别是学习&#xff0c;女神和屌丝&#xff0c;我们用不同的lazy来表示女神和屌丝&#xff0c;根据优先级去更新状态…