天天看點

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

(給DotNet加星标,提升.Net技能)

轉自:hippieZhou

cnblogs.com/hippieZhou/p/10637348.html

前言

Visual Studio 2019 已經正式釋出了,.NET Core 3.0的正式版也指日可待。

之前的版本中,作為一名基于微軟生态的傳統 WPF 程式員看着隔壁同學在開發

DotNetCore網站時用着各種特性好生羨慕,想着巨硬啥時候能讓用戶端開發者也能嘗嘗甜頭。那麼,現在是時候可以嘗試一下了。

需要說明的一點的是,DotNetCore 3.0雖然跨平台,但是基于此的 WPF 卻是針對 Windows 特定平台的實作,并不能跨 Linux 和 MacOS 。

開發環境準備

要想開發 DotNetCore 版本的 WPF,首先需要確定我們的機器上已經安裝了如下

Visual Studio 2019 :https://visualstudio.microsoft.com/downloads/#2019rc

需要安裝的元件如下圖所示

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發
treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

DotNetCore 3.0 SDK:https://dotnet.microsoft.com/download/dotnet-core/3.0

直接預設安裝即可。

全新的開發體驗

在首次使用 VS2019 建立 DotNetCore 版本的 WPF 程式時,VS 可能會給你爆個如下圖所示的錯誤:

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

按照錯誤提示即可解決該問題,如下圖所示

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

接着選擇 TOOLS -> Options,配置如下圖所示

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

Hello World

首先,我們可以通過 VS 建立一個基于 DotNetCore 的 項目模闆,然後我們看一下與傳統的 WPF 項目模闆有什麼差別。如下圖所示,建立一個 WPF 項目

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

建立完成後,嘗試編譯編譯運作(注:第一次編譯可能需要較長時間),如下圖所示

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

如果我們仔細看一下這個新版的項目模闆,會發現與傳統的項目模闆相比,有好幾處發生了改變:

  • **.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 設定為 Content, To Output Directiory 設定為  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.Show();
    }private void ConfigureServices(IServiceCollection services){// 向全局容器中注冊一個視圖
        services.AddTransient(typeof(MainWindow));// 在全局容器中配置 AppSettings
        services.Configure(Configuration.GetSection(nameof(AppSettings)));// 在全局容器中注冊自定義服務
        services.AddScoped();
    }
}
           

修改完畢後,我們可以嘗試編譯我們的項目,如果不出意外的啊,我們的程式會正常啟動起來。這裡就不做截圖說明了。

看了上述代碼,是不是覺得很有意思啊,這種全新的開發模式頓時把我們的代碼水準提升了好幾個檔次。這種使用方式和在 AspDotNetCore 簡直一摸一樣。

比如,我們在上面注冊了 AppSettings 和一個基于 ISampleService 接口的實作 SampleService,那麼我們就可以在 MainWindow 的構造函數中使用,比如,我們可以參考下面的示例代碼:

public partial class MainWindow : Window
{
private readonly ISampleService _sampleService;
private readonly IOptions _settings;public MainWindow(ISampleService sampleService, IOptions settings){
        InitializeComponent();
        _sampleService = sampleService;var val = _sampleService.GetCurrentDate();
        _settings = settings;
    }private void ButtonExit_Click(object sender, RoutedEventArgs e){
        Application.Current.Shutdown();
    }
}
           

然後,我們可以監視一下 **_settings** 的值,如下圖所示:

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

通過這個簡單的例子,我們可以看到這種全新方式的依賴注入已經得到微軟的大力支援,将基于 .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();
        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 設定為 Content, To Output Directiory 設定為  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();
        mainView.Show();base.OnStartup(e);
    }private void ConfigurationServices(ServiceCollection services){
        services.AddTransient(typeof(MainWindow));
        services.AddDbContext(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 的頁籤中,我們可以看到如下配置

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

我們可以依據具體情況,來選擇合适的釋出方式進行釋出。當然,我們也可以借助 Desktop App Converter 工具,将我們的應用分發到 windows Store 上。

總結

通過上述幾個簡單的示例,我們可以看到傳統的 WPF 已經被微軟注入了新鮮的血液,并且在微軟生态下的 C/S端 和 B/S端 開發模式漸趨相同。大大減輕了學習曲線。能夠讓技術在最短的時間裡變現,這也是我最看重的地方。

無論是過去還是現在,我都時不時地聽身邊的人說不應該過度依賴工具,但是我想說的是 技術服務于現實,而工具隻是為了加速變現,如果一項技術再好再優秀,它卻不能創造現實價值,服務生活,那麼我甯願放棄使用它。微軟為開發者提供了 DotNetCore 的好技術,而 VisualStudio 系列工具作為生産力工具,隻是為了提高生産效率。在效率為王的今天,誰赢得了時間,就赢得了一切。

最後,我不打算吹捧 DotNetCore、WPF、VisualStudio,以免有人說我會誤導萌新。還是那句話,實踐出真知,感興趣的話可以自己動手嘗試一下。

此外,目前 DotNetCore 3.0 還是處于預覽階段,是以可能會有一些坑。但是誰能保證自己第一次就能把事情做的完美呢?時間會證明一切。

補充

評論中很多朋友問到跨平台的問題,是以我補充了一張圖。

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

推薦閱讀

(點選标題可跳轉閱讀)

實際體驗Span 的驚人表現

C#8.0可空引用類型的使用注意要點

.NET Core新型ORM功能介紹

看完本文有收獲?請轉發分享給更多人

關注「DotNet」加星标,提升.Net技能 

treeview wpf代碼設定選中_.NET Core 3.0 助力 WPF 開發

喜歡就點一下「在看」呗~