翼度科技»论坛 编程开发 .net 查看内容

循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
在我们开发的前端项目中,往往为了方便,都需对一些控件进行自定义的处理,以便实现快速的数据绑定以及便捷的使用,本篇随笔介绍通过抽取常见字典列表,实现通用的字典类型绑定;以及通过自定义控件的属性处理,实现系统字典内容的快捷绑定的操作。
1、下拉列表的数据绑定

在我们创建下拉列表的时候,我们一般处理方式,是在对应的数据模型中添加对应的下拉列表的集合对象,然后在控件绑定对应的ItemSource,如下所示是视图模型,我们增加一个性别的列表参考。
  1. /// <summary>
  2. /// 用户列表-视图模型对象
  3. /// </summary>
  4. public partial class UserListViewModel : BaseListViewModel<UserInfo, int, UserPagedDto>
  5. {
  6.     /// <summary>
  7.     /// 性别
  8.     /// </summary>
  9.     [ObservableProperty]
  10.     private <strong>List<CListItem></strong><strong> genderItems</strong>;
  11.     /// <summary>
  12.     /// 构造函数
  13.     /// </summary>
  14.     /// <param name="service">业务服务接口</param>
  15.     public UserListViewModel(IUserService service) : base(service)
  16.     {
  17.         //初始化性别的列表
  18.         this.<strong>GenderItems</strong> = new List<CListItem>()
  19.         {
  20.             new CListItem("男"),
  21.             new CListItem("女")
  22.         };
  23.     }
复制代码
然后初始化后,就可以在界面上进行数据的绑定了,如下是对应控件的界面代码。
  1. [/code][align=center][/align]
  2.  这种方式可能是经常用到的方式,随着不同界面代码的编写,我们发现很多这样下拉列表,如机构可能有一些类别(来自枚举对象)需要处理,其他页面也有类似的需求。
  3. [code]/// <summary>
  4. /// 机构(部门)信息 列表-视图模型对象
  5. /// </summary>
  6. public partial class OuListViewModel : BaseListViewModel<OuInfo, int, OuPagedDto>
  7. {
  8.     /// <summary>
  9.     /// 机构分类
  10.     /// </summary>
  11.     [ObservableProperty]
  12.     private <strong>List<CListItem> categoryItems</strong> = new();
  13.     /// <summary>
  14.     /// 构造函数
  15.     /// </summary>
  16.     /// <param name="service">业务服务接口</param>
  17.     public OuListViewModel(IOuService service) : base(service)
  18.     {  
  19.         //机构分类
  20.         string[] enumNames = <strong>EnumHelper.GetMemberNames<OUCategoryEnum></strong>();
  21.         this.CategoryItems.Clear();
  22.         <strong>this.CategoryItems.AddRange(enumNames.Select(s => new</strong><strong> CListItem(s)));</strong>
  23.     }
复制代码
如果每次都需要在对应的视图模型上创建这些列表,则显得累赘、臃肿。因为这些下拉列表的内容,是界面中常用到的列表,我们是否可以把它作为一个公用的对象模型来使用呢。
为了方便,我们来创建一个对象DictItemsModel ,用来初始化系统用到的所有参考列表对象,如下代码所示。
  1. /// <summary>
  2. /// 定义一些系统常用的字典项目,供页面参考引用
  3. /// </summary>
  4. public partial class<strong> DictItemsModel : ObservableObject</strong>
  5. {
  6.     /// <summary>
  7.     /// 性别
  8.     /// </summary>
  9.     [ObservableProperty]
  10.     private  List<CListItem> genderItems = new();
  11.     /// <summary>
  12.     /// 机构分类
  13.     /// </summary>
  14.     [ObservableProperty]
  15.     private List<CListItem> ouCategoryItems = new();
  16.     //******更多列表处理**********
  17.     /// <summary>
  18.     /// 构造函数
  19.     /// </summary>
  20.     public DictItemsModel()
  21.     {
  22.         InitDictItem(); // 初始化字典
  23.     }
  24.     /// <summary>
  25.     /// 初始化字典
  26.     /// </summary>
  27.     /// <returns></returns>
  28.     public async Task InitDictItem()
  29.     {
  30.         //初始化性别的列表
  31.         this.GenderItems = new List<CListItem>()
  32.         {
  33.             new(""),
  34.             new("男"),
  35.             new("女")
  36.         };
  37.         //机构分类
  38.         this.OuCategoryItems = EnumHelper.GetMemberNames<OUCategoryEnum>().Select(s => new CListItem(s)).ToList();
  39.         this.OuCategoryItems.Insert(0, new CListItem(""));
  40.         //*********************
  41.     }
  42. }
复制代码
然后,我们在应用程序的XAML代码中,引入对应的静态资源,相当于每次使用这些的时候,是使用该对象的实例。
  1. <Application
  2.     x:Class="WHC.SugarProject.WpfUI.App"
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5.     xmlns:helpers="clr-namespace:WHC.SugarProject.WpfUI.Helpers"
  6.     xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
  7.     DispatcherUnhandledException="OnDispatcherUnhandledException"
  8.     Exit="OnExit"
  9.     Startup="OnStartup">
  10.     <Application.Resources>
  11.         <ResourceDictionary>
  12.             
  13.             <helpers:IntToBooleanConverter x:Key="IntToBooleanConverter" />
  14.             
  15.             <strong><helpers:DictItemsModel x:Key="DictItemsModel" /></strong>
  16.             
  17.         </ResourceDictionary>
  18.     </Application.Resources>
  19. </Application>
  20.             
复制代码
有了这些定义,我们的下拉列表的数据源ItemSource的属性改动一下就可以实现一致的效果了,相当于抽取了字典列表到独立的类中处理了。
  1. [/code][code]
复制代码
上面代码中,我们通过Source={StaticResource DictItemsModel}来指定数据源的位置来自静态资源即可。如机构列表,通过枚举进行解析到的集合如下所示,当然其他数据也可以通过相应的处理实现。
  

通过这种把常见的字典类别集中到一个类中进行维护,除了统一处理列表的初始化外,也方便我们在界面代码中的统一使用。
2、自定义系统字典列表控件

我们框架一般都维护一个通用的字典类型和字典项目的信息,通过维护这些常见的系统字典信息,可以为我们的界面的一些下拉类列表提供数据支持,是指实现通用、统一的字典处理。

以前在Winform中绑定字典列表的时候,一般通过扩展函数BindDictItems就可以实现类型绑定了,有兴趣可以了解下随笔《在Winform开发框架中下拉列表绑定字典以及使用缓存提高界面显示速度》、《使用扩展函数方式,在Winform界面中快捷的绑定树形列表TreeList控件和TreeListLookUpEdit控件》、《在Winform开发中,我们使用的几种下拉列表展示字典数据的方式》、《在各种开发项目中使用公用类库的扩展方法,通过上下文方式快速调用处理函数》。
对WPF来说,我们需要改变下思路,和Vue3的BS的控件的处理方式类似,我们通过给他指定一个字典类型的名称,让它自己取得对应列表,进行绑定处理即可,因此我们自定义字典列表控件即可。
  1.     /// <summary>
  2.     /// 自定义下拉列表,方便绑定字典类型
  3.     /// </summary>
  4.     public class <strong>ComboBox</strong> : HandyControl.Controls.ComboBox
复制代码
创建一个继承自所需下拉列表控件,可以使用原生控件继承,不过我这里偏向于UI更好的HandyControl的ComboBox。
然后给它指定对应的字典类型属性,对应我们系统的字典大类名称。
  1.     /// <summary>
  2.     /// 自定义下拉列表,方便绑定字典类型
  3.     /// </summary>
  4.     public class ComboBox : HandyControl.Controls.ComboBox
  5.     {
  6.         /// <summary>
  7.         /// 字典类型名称
  8.         /// </summary>
  9.         public string?<strong> DictTypeName</strong>
  10.         {
  11.             get { return (string?)GetValue(DictTypeNameProperty); }
  12.             set { SetValue(DictTypeNameProperty, value); }
  13.         }
  14.         public static readonly DependencyProperty <strong>DictTypeNameProperty</strong> = DependencyProperty.Register(
  15.             nameof(DictTypeName), typeof(string), typeof(ComboBox),
  16.             new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(<strong>OnDictTypeNamePropertyChanged</strong>)));
复制代码
封装过自定义的WPF控件的话,我们知道,增加一个自定义属性,就需要同时增加一个自定义属性+Property的 DependencyProperty 属性对象,如上代码所示。
通过PropertyChangedCallback的回调处理,实现设置字典类型值后触发控件内部数据的处理逻辑,也就是需要从字典服务中获取下拉类别数据,变为控件的ItemSource集合即可。
一般情况下,我们实现下面的代码逻辑,获得数据源就差不过可以了。
  1. private static async void OnDictTypeNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  2. {
  3.     if (d is not ComboBox control)
  4.         return;
  5.     if (control != null)
  6.     {
  7.         var oldValue = (string?)e.OldValue;  // 旧的值
  8.         var newValue = (string?)e.NewValue; // 更新的新的值
  9.         //更新下拉列表的数据源
  10.         if(!newValue.IsNullOrEmpty() && !control.IsInDesignMode())
  11.         {
  12.             var itemList = await <strong>BLLFactory<IDictDataService></strong><strong>.Instance.GetListItemByDictType(newValue)</strong>;
  13.             if (itemList != null)
  14.             {
  15.                 itemList.Insert(0, new CListItem(""));//CListItem具有Text、Value两个属性<strong>
  16.                 control.ItemsSource =</strong><strong> itemList;</strong>
  17.                 control.ShowClearButton = true;
  18.                 control.SelectedValuePath = control.SelectedValuePath.IsNullOrEmpty() ? "Value" : control.SelectedValuePath;
  19.             }
  20.         }
  21.     }
  22. }
复制代码
同理,我们按照同样的处理方式,做一个复选框的下拉列表CheckComboBox。
  1. /// <summary>
  2. /// 自定义下拉列表,方便绑定字典类型
  3. /// </summary>
  4. public class CheckComboBox : HandyControl.Controls.CheckComboBox
  5. {
  6.     /// <summary>
  7.     /// 字典类型名称
  8.     /// </summary>
  9.     public string? DictTypeName
  10.     {
  11.         get { return (string?)GetValue(DictTypeNameProperty); }
  12.         set { SetValue(DictTypeNameProperty, value); }
  13.     }
  14.     public static readonly DependencyProperty DictTypeNameProperty = DependencyProperty.Register(
  15.         nameof(DictTypeName), typeof(string), typeof(CheckComboBox),
  16.         new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnDictTypeNamePropertyChanged)));
复制代码
完成上面的自定义控件编写,我们需要在UI上放置控件,指定它的指定类型就可以了。
[code][/code]完成后,我们测试下自定义控件的处理效果。

 
   

效果符合实际的期望。而且代码和普通WPF控件的使用类似,只需要增加一个 DictTypeName="客户类型" 的类似写法即可。可以极大的减轻我们绑定常见系统字典的下拉列表的复杂度。
界面效果如下所示。

 

来源:https://www.cnblogs.com/wuhuacong/archive/2023/10/21/17778978.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具