.net core/5/6/7中WPF如何優雅的開始開發

BruceNeter 發表於 2022-11-25
.Net

WPF是微軟的.net平臺中的一個桌面客戶端應用程式框架,經常用於企業開發windows桌面客戶端,廣泛應用於中小企業快速開發一款工具,本人也是比較喜歡利用WPF開發一些小工具。

知名案例

1.虎牙直播客戶端
2.西門子醫療上位機
其中西門子醫療的上位機程式稱得上使用WPF技術的極其優秀的專案。(:德國人寫程式碼真的很嚴格工整。
當然西門子的.net還是基於framework,模組之間通訊用的WCF,依賴注入使用的spring.net我在的時候好像準備改成Autofac了。扯遠了~

.net core/5/6/7中開發WPF

伴隨著.net5這個半成品出世,.net framework和core正式合併到一起,在core中也是支援建立WPF模板程式碼的,那麼我們如何在新的平臺下優雅的使用WPF開發一個小工具呢?

MVVM

老的framework我喜歡使用MvvmLightLibs,但是目前用過的都知道該包已經被標記為棄用了,推薦使用微軟的CommunityToolkit.Mvvm,我們可以在專案檔案中新增該包的引用

<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />

新增好了之後我們將我們的viewmodel繼承ObservableObject具體使用可以看園子裡的一篇文章https://www.cnblogs.com/dino623/p/building_MVVM_programs_using_MVVM_Toolkit.html
示例程式碼:

public class MainWindowViewModel : ObservableObject
    {
        /// <summary>
        /// 屬性變更通知
        /// </summary>
        private Page _currentPage;
        public Page CurrentPage
        {
            get => _currentPage;
            set => SetProperty(ref _currentPage, value);
        }

        //命令繫結
        public RelayCommand ShiftWorkPageCommand { get; set; }
        public RelayCommand OpenWorkSpaceCommand { get; set; }
        }
    }

當然該包還帶了同程式下模組釋出訂閱的實現。本身的事件也支援繫結非同步方法。

DI

常用的依賴注入元件有spring.net,autofac,當然autofac在現在看來也是非常流行強大的。.net一直有一個自帶的依賴注入容器,功能沒有autofac強大,但是一般也夠用。我們需要在專案檔案中匯入微軟提供的相關的包。

<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />

我們會在程式啟動的時候建立一個預設的Host宿主物件,WPF的起始類就是app.cs裡,我們可以覆寫OnStartup方法,在其中啟動一個Host,並且將一些服務註冊進來。如日誌,配置檔案,資料庫配置等。

public partial class App : Application
    {
        public static IServiceProvider ServiceProvider;
        protected async override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var hostbuilder = CreateHostBuilder(e.Args);
            var host = await hostbuilder.StartAsync();
            ServiceProvider = host.Services;
            host.Services.GetRequiredService<MainWindow>()?.Show();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            var hostBuilder = Host.CreateDefaultBuilder(args).UseSerilog((context, logger) =>//註冊Serilog
            {
                logger.ReadFrom.Configuration(context.Configuration);
                logger.Enrich.FromLogContext();
            });
            hostBuilder.ConfigureServices((ctx, services) =>
            {
                services.AddSingleton<MainWindow>();
                services.AddSingleton<MainWindowViewModel>();
            });

            return hostBuilder;
        }
    }

tips :記得把App.xaml中的StartUpUri刪除掉。
上面的程式碼中,我們就註冊了serilog日誌,以及一些我們需要注入的物件,我們可以控制他們的生命週期,關於如何使用.net自帶的依賴注入以及為什麼需要控制反轉可以看這篇網址:https://www.cnblogs.com/youring2/p/10926590.html。

那麼如何使用呢?
我們可以在需要注入的地方透過構造器注入,比如我們的MainWindowViewModel是需要繫結到MainWindow的上下文物件上的,我們可以這樣做:

public partial class MainWindow : Window
    {
        public MainWindow(MainWindowViewModel viewModel)
        {
            InitializeComponent();
            DataContext = viewModel;
        }
    }

這樣程式在例項化MainWindow的時候就會從容器中取到MainWindowViewModel例項放到構造中,不需要我們關心如何去new這樣一個物件。

我們還在App.cs中放了一個靜態的ServiceProvider儲存ServiceProvider的例項,方便我們全域性使用,這是因為有的地方我們不方便構造器的依賴注入,我們就可以利用該物件使用依賴查詢的辦法獲取物件例項:

ServiceProvider.GetRequiredService<MainWindowViewModel>();

Configuration

如何按照上面做的我們在WPF啟動的時候註冊一個預設的Host,那麼也會將配置模組帶入到專案中,我們如何使用配置模組?我們可以在專案根目錄下建立一個appsettings.json檔案,並且右鍵->屬性
設定成這樣
.net core/5/6/7中WPF如何優雅的開始開發
這樣我們就可以使用.net自帶的IConfiguration進行配置檔案的讀取。這個IConfiguration也是可以透過構造方法注入的,我們想在程式裡或者配置檔案裡這個節點的配置就可以如下操作:
.net core/5/6/7中WPF如何優雅的開始開發
.net core/5/6/7中WPF如何優雅的開始開發
當然了具體更多操作和用法,包括需要根據不同環境區分載入不同的配置以及不喜歡appsettings.json這個名字,想用其他名字都是可以配置的。appsettings.json是他框架預設的配置檔名字,會去找根目錄下這個檔案,如果你沒有配置成其他名字的話。更多配置的操作可以檢視該網址:https://www.cnblogs.com/stulzq/p/8570496.html

結尾

目前為止我們只是介紹了幾個方面的WPF的在.net core/5/6/7中的優雅用法。也是一個基礎的搭建,當然只有一個良好的基礎,一個低耦合,符合規範的基礎才能hold住之後寫程式碼天高任鳥飛的願景哈哈哈哈。
我自己做的一個lol外掛也是使用WPF做的,目前全網下載量破萬,github star 180+,也是基於這些概念開發的,有興趣的小夥伴可以瞭解也好,學習也好。
https://github.com/BruceQiu1996/NPhoenix