這是一篇“不務正業”的文章,沒錯,將ABP框架集成到WPF項目。作爲一個主打web開發的框架,ABP框架使用多次後就愈發愛不釋手,一直想着能不能將其集成到WPF項目中,過程就在下面了。
1.創建WPF項目並安裝ABP程序包
在解決方案中創建一個WPF項目,名爲AbpDemo.Client。爲了符合整個解決方案的.NET Core環境,創建的也是.NET Core環境下的WPF項目。
打開NuGet管理器,安裝ABP相關的程序包。其中Abp是核心,也是必裝的;Abp.EntityFramworkCore用於數據庫連接,也是必須的。其他的根據需要安裝。
同時,添加對領域層Core、基礎設施層EntityFrameworkCore和應用層Application項目的引用。
2.添加Module類
ABP框架提供了模塊體系用於構建基礎結構,通過Module類來實現不同組件之間的依賴,利用這個特性可以將WPF項目與領域層、基礎設施層、應用層項目建立聯繫。
創建類AbpDemoClientModule,添加相關模塊的引用,同時在生命週期的初始化方法Initialize中進行依賴注入的註冊。
[DependsOn(typeof(AbpDemoCoreModule),
typeof(AbpDemoApplicationModule),
typeof(AbpDemoEntityFrameworkCoreModule))]
public class AbpDemoClientModule:AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
//base.Initialize();
}
}
3.修改啓動類
對於WPF項目而言,App類就是啓動類。修改App類,使得ABP框架也從這裏啓動。在應用啓動方法中初始化ABP啓動器,同時將主窗口註冊到框架中。在應用關閉方法中釋放主窗口和ABP啓動器。
public partial class App : Application
{
private readonly AbpBootstrapper _bootstrapper;
private MainWindow _window;
public App()
{
_bootstrapper = AbpBootstrapper.Create<AbpDemoClientModule>();
}
protected override void OnStartup(StartupEventArgs e)
{
_bootstrapper.Initialize();
_window = _bootstrapper.IocManager.Resolve<MainWindow>();
_window.Show();
//base.OnStartup(e);
}
protected override void OnExit(ExitEventArgs e)
{
_bootstrapper.IocManager.Release(_window);
_bootstrapper.Dispose();
//base.OnExit(e);
}
}
然後將App.xmal中的StartupUri項刪除,否則啓動後會出現兩個窗口。
此外,還需要爲MainWindow類添加接口ISingletonDependency繼承,用來實現註冊。注意,這個依賴被聲明爲單例。因此,創建的MainWindow只是在第一次使用時創建,應用程序的整生命週期使用的是同一實例。
using Abp.Dependency;
public partial class MainWindow : Window, ISingletonDependency
{
public MainWindow()
{
InitializeComponent();
}
}
重新編譯項目並啓動,可以看到主窗口正常顯現。
4.配置數據庫連接
在之前的Web項目中,數據庫連接相關配置是已經設置好的,只需要調整AppSetting.json中的數據庫連接字符串即可,但在WPF項目中就不太一樣了。好在ABP框架提供了對非Web項目進行數據庫配置的方法。仍然是在AbpDemoClientModule類中進行配置。
public override void PreInitialize()
{
string connectionString = "Server=localhost; Database=AbpDemoDb; uid=root;pwd=Admin123;";
Configuration.DefaultNameOrConnectionString = connectionString;
Configuration.Modules.AbpEfCore().AddDbContext<AbpDemoDbContext>(options =>
{
options.DbContextOptions.UseMySql(connectionString);
});
//base.PreInitialize();
}
5.使用應用層方法獲取數據
目前WPF項目的地位類似於之前Web項目的地位,其他項目如領域層、基礎設施層、應用層的作用都是不變的。在WPF項目的窗體類中,通過依賴注入來引入應用層Application中的方法。
public partial class MainWindow : Window, ISingletonDependency
{
private MainWindowViewModel _viewModel;
private readonly IGoodsAppService _goodsAppService;
public MainWindow(IGoodsAppService goodsAppService)
{
_goodsAppService = goodsAppService;
_viewModel = new MainWindowViewModel(goodsAppService);
this.DataContext = _viewModel;
InitializeComponent();
}
}
這裏WPF項目使用了簡單的MVVM模式,在對應的MainWIndowViewModel類中使用接口IGoodsAppService獲取數據。
public class MainWindowViewModel:ViewModelBase
{
private readonly IGoodsAppService _goodsAppService;
public MainWindowViewModel(IGoodsAppService goodsAppService)
{
_goodsAppService = goodsAppService;
InitData();
}
private List<DetailGoodsDto> _goodsList;
public List<DetailGoodsDto> GoodsList
{
get { return _goodsList; }
set
{
if (_goodsList!=value)
{
_goodsList = value;
OnPropertyChanged("GoodsList");
}
}
}
private void InitData()
{
GoodsList = _goodsAppService.All();
}
}
其中基類ViewModelBase實現了接口INotifyPropertyChanged。
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected internal virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
啓動項目,效果如下。