上一篇ViewModel相互传参和代码直接相关的就已经介绍完毕了整个框架的大概情况,从零开始搭建这个JHRS开发框架遇到的问题还是蛮多的,毕竟WPF笔者是0基破,这些碎碎念的文字只是一个记录而已。
这个JRHS框架即使在笔者看来,也是一个玩具项目,但提供了一些实践中的想法,实际上项目中基本上也是这样使用的,最开始搭建这个框架时,因对WPF并不熟悉,即使到现在对WPF的了解也是皮毛,和资深WPF猿猿比起来,自认能力相距甚远。但在折腾此框架的时候,也是踩了一些坑,有时候难免会将相关的组件源码拉下来看看。
JHRS框架踩坑记
1、使用Prism时,如果用户控件里面绑定了 Load事件,事件名不能和宿主窗体或Page已有Load事件同名。否则会多次执行。
2、使用Prism時,統一彈框,內容區域如果用Frame放置,需要手動設置區域管理器。
3、统一模态弹框组件已经封装完毕。 –已完成 注意点:注册自定义弹框,取值时需要特殊处理,因为prism原生代码不支持传name取,新建一个扩展类修改了弹窗功能。
4、统一提示框(【成功,失败,警告,确认】框) –已完成
5、根据swagger自动生成web api 调用接口和实体对象 –已完成
6、按新的代码结构修改登录功能,网络设置,修改密码等功能。 –已完成
7、统一下拉框 –已完成
8、创建页面,标记Function特性,值取功能的唯一名称(Path值) –已完成
9、封装统一表格分页功能
10、各个功能窗体或Page需要加载的用户控件,根据标记的特性来加载。
11、自动收集查询条件,拼接成规则
12、需要整理每个viewmodel类的规则,如弹框的怎么建,分页列表的怎么建,新增编辑的怎么建,用户控件怎么建(分页实体类,分页控件)等。
13、分页表格数据,在实体类上加上绑定描述特性,用于动态生成DataGrid列。可以设置显示名称,显示顺序,默认复选框绑定项。
14、用户控件对外提供依赖属性时,在使用界面绑定可以指定 Model=Twoway,也可以在控件的依赖属性注册时通过代码指定。参考代码:
public static readonly DependencyProperty SelectedListProperty = DependencyProperty.Register("CheckedList", typeof(IEnumerable<object>), typeof(PagingDataGrid), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
15、状态字段,如果是枚举的话,存在不能选中的问题。要么将实体对象更改为数字,要么界面绑定实现一个转换器。
16、弹框如果要执行取消逻辑,可以在回调函数里面执行。就是打开弹窗的代那儿,可以添加回调函数。
17、弹窗传参利用区域上下文对象
传参:RegionManager.Regions[RegionNames.DialogRegin].Context = args;
获取:RegionManager.Regions[RegionNames.DialogRegin].Context
18、如果界面上所需要的DTO里面没有属性,而为了方便界面实现功能,可以使用部分类的方式添加属性或者其它方法。
做法:在所属相关的模块里面建立ModelExtensions目录,专门保存扩展的DTO类,新建类后,需要将自动生成的命名空间,如ModelExtensions删除。参考 SysRoleDto类。
————————————————–知识点————————————————————
1、WPF触发器
2、Prism订阅事件时,事件对象最好公开Subscriptons对象,可以快速清除,以解决多次订阅导致多次触发事件。
/// <summary> /// 通用弹框页面保存事件对象 /// </summary> public class CommonSaveEvent : PubSubEvent<Border> { public new ICollection<IEventSubscription> Subscriptions => base.Subscriptions; }
订阅时为了避免多次触发,需要先清除已经订阅的对象,直接调用Unsubscribe不起作用。
var ev = EventAggregator.GetEvent<CommonSaveEvent>(); ev.Subscriptions.Clear(); ev.Subscribe(SaveCommand);
3、ViewModel之间,窗体关闭再打开新窗体传参,通过静态变量处理,在主窗体内不同Page切换可以通过发布事件,另外一个Page订阅来实现。
静态变量传参:
/// <summary> /// 选择子系统 /// </summary> public DelegateCommand<Module> SelectModuleCommand => new DelegateCommand<Module>((x) => { MainWindowViewModel.Module = x; ShellSwitcher.Switch<ModuleChooseWindow, MainWindow>(); });
4、查询分组功能。如果有一个字段需要组合成多种查询条件,例如名称,支持拼音简码,全拼查询,只需要在查询条件实体里面多定义几个属性字段,并使用分组拼接即可,额外定义的属性调用转拼音方法即可,并将原始字段组合成分组。
/// <summary> /// 系统角色管理分页查询条件 /// </summary> public class RoleManageQueryCondition { /// <summary> /// 角色名 /// </summary> [QueryRule(FilterOperate.Contains, "RoleName")] public string RoleName { get; set; } /// <summary> /// 角色状态 /// </summary> [QueryRule(FilterOperate.Equal, "RoleStatus")] public int RoleStatus { get; set; } = -1; /// <summary> /// 子系统 /// </summary> [QueryRule(FilterOperate.Equal, "SystemId")] public int SubSystem { get; set; } = -1; }
5、更改状态方法,也可以调用回调函数版本。
this.ChangeStatus<StatusComboBox, RoleSystem>(c, “角色”, p => nameof(p.Status), async (role) => { var response = await RestService.For<IRoleApi>(AuthClient).ChangeSysRoleStatus(role.ID, (EntityStatus)role.Status); if (response.Succeeded) { AlertPopup(response.Message); } });
——————————————页面如何开始———————————————–
1、新建页面后,在xaml添加如下代码:
xmlns:prism=”http://prismlibrary.com/” prism:ViewModelLocator.AutoWireViewModel=”True” xmlns:b=”http://schemas.microsoft.com/xaml/behaviors”
2、管理列表查询页面的查询条件,可以直接绑定ViewModel(主Page的ViewModel),可以在ViewModel里面定义一个对象属性,定义对象属性使用【对象属性名.属性】来绑定,或者直接定义属性来绑定。参考代码:
<s:StatusComboBox Name=”cmbState” SelectedValue=”{Binding Query.Status}” Style=”{StaticResource ComboBox.Common}” MinWidth=”120″/> <dept:DepartmentList Margin=”0,0,20,0″ Width=”120″ SelectedValue=”{Binding DeptID}” Style=”{StaticResource ComboBox.Common}”/>
写在最后
以上记录的内容有点凌乱,是在搭建这个框架时记录下来的,现在也懒得整理了;源码可以直接拉取下来编译,程序跑起来就可以了。
最后声明一下,有bug是很正常的,别抱怨,需要的朋友自己继续踩坑就完事了。