这是一篇“不务正业”的文章,没错,将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
}
启动项目,效果如下。