Prism+MaterialDesign+EntityFramework+Postgresql WPF之 架构篇
ccwgpt 2024-10-07 07:04 34 浏览 0 评论
本着每天记录一点成长一点的原则,打算将目前完成的一个WPF项目相关的技术分享出来,供团队学习与总结。
总共分三个部分:
基础篇主要针对C#初学者,巩固C#常用知识点;
中级篇主要针对WPF布局与MaterialDesign美化设计,在减轻代码量的情况做出漂亮的应用;
终极篇为框架应用实战,包含系统分层、MVVM框架Prism安装与使用、ORM框架EntityFramework Core配置与使用、开源数据库Postgresql配置与使用。
目录
- Prism+MaterialDesign+EntityFramework Core+Postgresql WPF开发总结 之 基础篇
- Prism+MaterialDesign+EntityFramework Core+Postgresql WPF开发总结 之 中级篇
- Prism+MaterialDesign+EntityFramework Core+Postgresql WPF开发总结 之 终极篇
前言
此篇主要介绍系统分层模型、如何安装Prism快速开发模板与MVVM框架使用、如何配置ORM框架Entity Framework Core与使用、以及Postgresql数据库配置。
系统分层
项目比较简单,大概分层模型如下:
- View双向绑定ViewModel;
- ViewModel调用Service取得DataModel业务数据;
- Service通过调用Repository取得Entity数据;
- Repository调用Entity Framework Core,自动创建Sql执行并返回Entity对象;
- Entity Framework Core通过驱动链接数据库。
如果项目功能或者对接端末比较多,最好扩展成微服务。
MVVM框架之Prism
MVVM(Model–view–viewmodel)是微软的WPF和Silverlight架构师之一John Gossman于2005年发布的软件架构模式。目的就是把用户界面设计与业务逻辑开发分离,方便团队开发和自动化测试。目前流行的Android开发、Web开发都在使用,具体MVVM的介绍参照个人博客:核心框架MVVM与MVC、MVP的区别(图文详解)。
一、无框架的MVVM实现
设计与逻辑分离的基本就是绑定,通过发布者订阅者模式实现数据更新通知。
1、属性绑定
默认属性为单向绑定,如果需要双向绑定需要实现INotifyPropertyChanged接口。
第一步:一般是建立如下基类。
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MvvmDemo.Common
{
/// <summary>
/// Viewmodel基类,属性双向绑定基础
/// </summary>
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 属性变更通知
/// </summary>
/// <param name="propertyName">属性名</param>
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
第二步:各个ViewModel继承基类。
public class UserViewModel : ViewModelBase
{
private string _userId;
private string _userName;
/// <summary>
/// 用户名
/// </summary>
public string UserId
{
get
{
return _userId;
}
set
{
_userId = value;
NotifyPropertyChanged();
}
}
/// <summary>
/// 用户名
/// </summary>
public string UserName
{
get
{
return _userName;
}
set
{
_userName = value;
NotifyPropertyChanged();
}
}
}
第三步:Xaml绑定属性,实现消息通知。
<TextBox Text="{Binding UserID,Mode=TwoWay}" />
<TextBox Grid.Row="1" Text="{Binding UserName,Mode=OneWay}" />
备注:通过IValueConverter可以做一些特殊绑定处理。比如,经典的就是Bool值控制Visibility。
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibiltyConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
bool? nullable = (bool?)value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Xaml绑定:头部需要引入命名空间。
xmlns:converter="clr-namespace:WpfMvvm.Core.Converters"
<Button
Grid.Row="2"
Visibility="{Binding ShowFlg,Converter={converter:BoolToVisibiltyConverter}}"
Command="{Binding AddCmd}"
Content="登录" />
2、事件绑定
WPF提供了Command事件处理属性,想利用控件中的Command属性需要实现了ICommand接口的属性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MvvmDemo.Common
{
public class DelegateCommand<T>: ICommand
{
/// <summary>
/// 命令
/// </summary>
private Action<T> _Command;
/// <summary>
/// 命令可否执行判断
/// </summary>
private Func<T, bool> _CanExecute;
/// <summary>
/// 可执行判断结束后通知命令执行
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="command">命令</param>
public DelegateCommand(Action<T> command):this(command,null)
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="command">命令</param>
/// <param name="canexecute">命令可执行判断</param>
public DelegateCommand(Action<T> command,Func<T,bool> canexecute)
{
if(command==null)
{
throw new ArgumentException("command");
}
_Command = command;
_CanExecute = canexecute;
}
/// <summary>
/// 命令执行判断
/// </summary>
/// <param name="parameter">判断数据</param>
/// <returns>判定结果(True:可执行,False:不可执行)</returns>
public bool CanExecute(object parameter)
{
return _CanExecute == null ? true : _CanExecute((T)parameter);
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter">参数</param>
public void Execute(object parameter)
{
_Command((T)parameter);
}
}
}
使用它作为事件属性的类型就可以了。
/// <summary>
/// 登陆命令
/// </summary>
public DelegateCommand<string> LoginCommand => new DelegateCommand<string>(
s =>
{
// todo
},
s => !string.IsNullOrEmpty(s)
);
二、Prism的MVVM实现
至于Prism有很多种理由让我选择它,比如:
- 支持MVVM(Binding、Notification、Command等)、微软成员维护
- 支持Unity和DryIoc两种IOC容器
- 支持WPF、UWP、Xamarin.Froms开发
- 封装界面跳转
- 封装弹出消息框
- 自带项目模板与快速开发代码片段
- 创建View时自动创建ViewModel
- 默认自动绑定ViewModel到View
- ...等等
1、配置Prism
最简单的方法:安装Prism Template Pack扩展包。
2、使用Prism
通过Prism项目模板创建项目,目前可以创建WPF(.Net Framework和.Net Core)、UWP、Xamarin.Froms等应用。
以前支持四种容器,现在只支持两种IOC容器:Unity、DryIoc。
*备注:如果通过Prism模板创建项目时出现以下错误:
这是因为Autofac已经不被支持。解决办法:regedit进入注册表HKEY_CURRENT_USER\Software\Prism,把SelectedContainer删除或者改成Unity。
生成的解决方案如下:
亮点:解决方案中自动设置了ViewModel的IOC配置,MainWindow.xaml中ViewModel的绑定也自动设置了。
下面通过建立一个简单的局部界面跳转实例,体验一把Prism的高效率:cmd、propp、vs智能提示。
Prism包提供的代码片段如下,要好好加以利用:
此次项目还用到了以下特性:
2.1 Region Navigation
局部页面跳转:
- 传递对象参数;
- 跳转前确认;
- 自定义如何处理已经显示过的页面(覆盖与否);
- 通过IRegionNavigationJournal接口可以操作页面跳转履历(返回与前进等)。
如上例所示简单应用。
第一步:标识显示位置。
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
第二步:在App.xaml.cs注册跳转页面。
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<PageTwo, PageTwoViewModel>();
}
}
第三步:使用IRegionManager实现跳转。
// 指定需要显示的页面名字与显示位置的ContentControl的名字
_manager.RequestNavigate("ContentRegion", "PageTwo");
2.2、Modules
如果系统功能比较多最好进行分块处理,如下面订单和用户信息的分块处理。
App.xaml.cs中统一各个模块数据。
// ModuleLoader会把各个模块的IOC依赖注入数据汇总共有管理
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<OrderModule>();
moduleCatalog.AddModule<CustomerModule>();
}
各个Module里面还是一样,使用到的所有Service和Repository都注册,使用IOC容器进行生命周期管理。
public class OrderModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MainWin>(PageDefine.Order);
containerRegistry.Register<ISearchService, SearchService>();
}
}
2.3、Dialog Service
自定义消息弹出框,比如警告、错误、提示等消息框。
第一步:自定义消息框控件,ViewModel继承IDialogAware接口并实现:
public class NotificationDialogViewModel : BindableBase, IDialogAware
{
private DelegateCommand<string> _closeDialogCommand;
public DelegateCommand<string> CloseDialogCommand =>
_closeDialogCommand ?? (_closeDialogCommand = new DelegateCommand<string>(CloseDialog));
private string _message;
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
private string _title = "Notification";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public event Action<IDialogResult> RequestClose;
protected virtual void CloseDialog(string parameter)
{
ButtonResult result = ButtonResult.None;
if (parameter?.ToLower() == "true")
result = ButtonResult.OK;
else if (parameter?.ToLower() == "false")
result = ButtonResult.Cancel;
RaiseRequestClose(new DialogResult(result));
}
public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
RequestClose?.Invoke(dialogResult);
}
public virtual bool CanCloseDialog()
{
return true;
}
public virtual void OnDialogClosed()
{
}
public virtual void OnDialogOpened(IDialogParameters parameters)
{
Message = parameters.GetValue<string>("message");
}
}
第二步:App.xaml.cs中注册自定义的消息框,从而覆盖默认的消息框:
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
}
}
第三步:通过IDialogService使用消息框:
private void ShowDialog()
{
var message = "This is a message that should be shown in the dialog.";
//using the dialog service as-is
_dialogService.ShowDialog("NotificationDialog", new DialogParameters(#34;message={message}"), r =>
{
if (r.Result == ButtonResult.None)
Title = "Result is None";
else if (r.Result == ButtonResult.OK)
Title = "Result is OK";
else if (r.Result == ButtonResult.Cancel)
Title = "Result is Cancel";
else
Title = "I Don't know what you did!?";
});
}
第四步:定义消息框显示属性:
<prism:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="ShowInTaskbar" Value="False" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
</Style>
</prism:Dialog.WindowStyle>
其他用法可以参照Prism开源库:https://github.com/PrismLibrary/Prism
Entity Framework Core + Postgresql
EntityFrameworkCore:是对象关系映射(ORM)程序,支持语言集成查询Linq,是轻量、可扩展、开源跨平台的数据访问框架。下一个5.0版本将与.NET 5.0一起发布。EntityFrameworkCore只支持CodeFirst,EntityFramework支持DB First和Code First。之所以选择EFCore是因为:
- 支持CodeFirst
- 支持Linq
- 双向映射(linq映射成sql,结果集映射成对象)
- 速度很快
PostgreSQL:是开源先进的对象-关系型数据库管理系统(ORDBMS),有些特性甚至连商业数据库都不具备。支持JSON数据存储,表之间还可以继承。
一、配置EFCore与PostgreSQL
※PostgreSQL安装参照个人博客:【Windows】PostgreSql安装
1、引入针对PostgreSQL的EFCore包
2、添加DB操作上下文
数据库链接替换为你的链接,一般都是放配置文件管理。
添加Users字段,通过EFCore将自动创建Users表。
using System;
using Microsoft.EntityFrameworkCore;
using WpfMccm.Entitys;
namespace WpfMvvm.DataAccess
{
public class UserDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Server=127.0.0.1;Database=HBMCS;Port=5432;User Id=test;Password=test;Ssl Mode=Prefer;",
npgsqlOptionsAction: options =>
{
options.CommandTimeout(60);
options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorCodesToAdd: null);
});
}
public DbSet<User> Users { get; set; }
}
}
3、安装Microsoft.EntityFrameworkCore.Tools工具
CodeFirst必备神器。进入程序包管理器控制台,输入以下命名安装EFCore设计工具:
※必须安装在启动项目里面,不然会失败。
Install-Package Microsoft.EntityFrameworkCore.Tools
4、创建Migration
程序包管理器控制台,默认项目一定要选择DB操作上下文的项目,然后执行命令:InitDB是文件区分,可以任意修改。
Add-Migration InitDB
执行成功之后,生成带InitDB区分的表定义数据文件:
6、生成数据库脚本(生产阶段用,开发阶段可跳过)
程序包管理器控制台,执行如下命令生成SQL脚本文件:
Script-Migration
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
CREATE TABLE "Users" (
"ID" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"Name" text NULL,
"Age" integer NOT NULL,
CONSTRAINT "PK_Users" PRIMARY KEY ("ID")
);
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20200413133616_InitDB', '3.1.3');
如果系统已经上线,安全起见则需要使用这个方法生成SQL脚本,手动执行SQL更新数据库。
7、更新数据库(开发阶段用)
程序包管理器控制台,执行如下命令将表定义更新到DB(按文件名的时间顺顺添加):
Update-Database
这样我们就通过类创建了一个数据库表Users,同时默认会在__EFMigrationsHistory履历表添加一条合并记录。
※如果__EFMigrationsHistory中记录存在则忽略本次更新。
二、使用DB上下文操作数据库
1、创建IRepository,DB操作基本接口
public interface IRepository<TEntity> where TEntity : class
{
Task<TEntity> GetAsync(int id);
Task<bool> AddAsync(TEntity obj);
}
2、创建UserRepository,User专用的DB操作类
public class UserRepository : IRepository<User>
{
private readonly DbContext _dbContext;
private readonly DbSet<User> _dbSet;
public UserRepository(UserDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<User>();
}
public async Task<bool> AddAsync(User obj)
{
_dbSet.Add(obj);
return await _dbContext.SaveChangesAsync() > 0;
}
public async Task<User> GetAsync(int id)
{
return await _dbSet.FindAsync(id);
}
}
如果需要进行事务操作,可以使用下面方法:
var tran= _dbContext.Database.BeginTransaction();
tran.Commit();
3、Service层调用UserRepository就可以完成用户的操作。
总结
此篇量稍微有点多,非常感谢能看到这里。整体来说Prism简化了应用的设计与架构,EFCore简化了数据库操作。
相关推荐
- 2025南通中考作文解读之四:结构框架
-
文题《继续走,迈向远方》结构框架:清晰叙事,层层递进示例结构:1.开头(点题):用环境描写或比喻引出“走”与“远方”,如“人生如一条长路,每一次驻足后,都需要继续走,才能看见更美的风景”。2.中间...
- 高中数学的知识框架(高中数学知识框架图第三章)
-
高中数学的知识框架可以划分为多个核心板块,每个板块包含具体的知识点与内容,以下为详细的知识框架结构:基础知识1.集合与逻辑用语:涵盖集合的概念、表示方式、性质、运算,以及命题、四种命题关系、充分条件...
- 决定人生的六大框架(决定人生的要素)
-
45岁的自己混到今天,其实是失败的,要是早点意识到影响人生的六大框架,也不至于今天的模样啊!排第一的是环境,不是有句话叫人是环境的产物,身边的环境包括身边的人和事,这些都会对一个人产生深远的影响。其次...
- 2023年想考过一级造价师土建计量,看这30个知识点(三)
-
第二章工程构造考点一:工业建筑分类[考频分析]★★★1.按厂房层数分:(1)单层厂房;(2)多层厂房;(3)混合层数厂房。2.按工业建筑用途分:(1)生产厂房;(2)生产辅助厂房;(3)动力用厂房;(...
- 一级建造师习题集-建筑工程实务(第一章-第二节-2)
-
建筑工程管理与实务题库(章节练习)第一章建筑工程技术第二节结构设计与构造二、结构设计1.常见建筑结构体系中,适用建筑高度最小的是()。A.框架结构体系B.剪力墙结构体系C.框架-剪力墙结构体系D...
- 冷眼读书丨多塔斜拉桥,这么美又这么牛
-
”重大交通基础设施的建设是国民经济和社会发展的先导,是交通运输行业新技术集中应用与创新的综合体现。多塔斜拉桥因跨越能力强、地形适应性强、造型优美等特点,备受桥梁设计者的青睐,在未来跨越海峡工程中将得...
- 2021一级造价师土建计量知识点:民用建筑分类
-
2021造价考试备考开始了,学霸君为大家整理了一级造价师备考所用的知识点,希望对大家的备考道路上有所帮助。 民用建筑分类 一、按层数和高度分 1.住宅建筑按层数分类:1~3层为低层住宅,4~6层...
- 6个建筑结构常见类型,你都知道吗?
-
建筑结构是建筑物中支承荷载(作用)起骨架作用的体系。结构是由构件组成的。构件有拉(压)杆、梁、板、柱、拱、壳、薄膜、索、基础等。常见的建筑结构类型有6种:砖混结构、砖木结构、框架结构、钢筋混凝土结构、...
- 框架结构设计经验总结(框架结构设计应注意哪些问题)
-
1.结构设计说明主要是设计依据,抗震等级,人防等级,地基情况及承载力,防潮抗渗做法,活荷载值,材料等级,施工中的注意事项,选用详图,通用详图或节点,以及在施工图中未画出而通过说明来表达的信息。2.各...
- 浅谈混凝土框架结构设计(混凝土框架结构设计主要内容)
-
浅谈混凝土框架结构设计 摘要:结构设计是个系统的全面的工作,需要扎实的理论知识功底,灵活创新的思维和严肃认真负责的工作态度。钢筋混凝土框架结构虽然相对简单,但设计中仍有很多需要注意的问题。本文针...
- 2022一级建造师《建筑实务》1A412020 结构设计 精细考点整理
-
历年真题分布统计1A412021常用建筑结构体系和应用一、混合结构体系【2012-3】指楼盖和屋盖采用钢筋混凝土或钢木结构,而墙和柱采用砌体结构建造的房屋,大多用在住宅、办公楼、教学楼建筑中。优点:...
- 破土动工!这个故宫“分院”科技含量有点儿高
-
故宫“分院”设计图。受访者供图近日,位于北京海淀区西北旺镇的故宫北院区项目已开始破土动工,该项目也被称作故宫“分院”,筹备近十年之久。据悉,故宫本院每年展览文物的数量不到1万件,但是“分院”建成后,预...
- 装配式结构体系介绍(上)(装配式结构如何设计)
-
PC构件深化、构件之间连接节点做法等与相应装配式结构体系密切相关。本节列举目前常见的几种装配式结构体系:装配整体式混凝土剪力墙结构体系、装配整体式混凝土框架结构体系、装配整体式混凝土空腔结构体系(S...
- 这些不是双向抗侧结构体系(这些不是双向抗侧结构体系的特点)
-
双向抗侧土木吧规范对双向抗恻力结构有何规定?为何不应采用单向有墙的结构?双向抗侧土木吧1.规范对双向抗侧力结构体系的要求抗侧力体系是指抵抗水平地震作用及风荷载的结构体系。对于结构体系的布置,规范针对...
- 2022一级建造师《建筑实务》1A412020 结构设计 精细化考点整理
-
1A412021常用建筑结构体系和应用一、混合结构体系【2012-3】指楼盖和屋盖采用钢筋混凝土或钢木结构,而墙和柱采用砌体结构建造的房屋,大多用在住宅、办公楼、教学楼建筑中。优点:抗压强度高,造价...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- grpc框架 (55)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)