循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(7) -- 图标列表展示和选择处理
我们在WPF应用端的界面中,使用lepoco/wpfui 来做主要的入口框架,这个项目它的菜单内置了不少图标,我们需要在动态菜单的配置中,使用它作为图标的展示处理,本篇随笔介绍如何基于图标枚举集合进行图标的展示和选择处理。并扩展到Font-Awesome-WPF的处理进行展示和选择。
1、lepoco/wpfui 项目的图标库
lepoco/wpfui 项目的图标库来源于Fluent System Icons,项目地址是:https://github.com/microsoft/fluentui-system-icons
这些图标映射到枚举对象 SymbolRegular 和 SymbolFilled,一个是常规的,一个是填充的图标,如下枚举对象所示。

图标主要通过前面的名称来区分展示的,图标列表主要展示效果如下所示。

我们可以通过代码把这些枚举内容全部加载到列表中进行使用。
var iconList = EnumHelper.GetMemberKeyValue<SymbolRegular>();
foreach (var icon in iconList)
{
this.AllItems.Add(new CListItem(icon.Key, icon.Value.ToString()));
}
我们为了处理这些图标内容,需要按照MVVM的设计模式,设计相关的视图模型和视图界面,由于图标比较多,测试一次性展示的时候太过耗时,因此把它们分页处理,实际运行的界面效果如下所示。
1)图标列表选择界面

2)图标选择后的展示界面
我们一般在动态菜单设置页面中用到图标的选择处理,如下界面所示。

为了有效的对图标进行分页展示,视图模型需要包含一些分页所需的对象信息,如下代码所示。
/// <summary>
/// SymbolRegular 的图标查询视图模型
/// </summary>
public partial class SymbolRegularListViewModel : BaseViewModel
{
/// <summary>
/// 选择的图表项目
/// </summary>
[ObservableProperty]
private CListItem selectedItem = new(); /// <summary>
/// 符合条件的图标列表
/// </summary>
[ObservableProperty]
private List<CListItem> iconItems = new(); /// <summary>
/// 所有图标
/// </summary>
[ObservableProperty]
private List<CListItem> allItems = new(); /// <summary>
/// 分页对象
/// </summary>
[ObservableProperty]
private PagingData pagerInfo = new PagingData() { CurrentPageIndex = 1, PageSize =60 };
由于图标不用访问数据库,因此在枚举读取初始化后存储所有的图标集合,并以集合为基础进行图标名称的检索及排序处理。
在查询处理的时候,我们需要把分页的页码和页面大小等信息转换为记录数的跳转及获取变量,如下所示。
/// <summary>
/// 转换下分页信息,为查询对象的属性
/// </summary>
protected virtual void ConvertPagingInfo()
{
//根据传入的分页信息构建查询记录数和位置
this.SkipCount = (this.PagerInfo.CurrentPageIndex - 1) * this.PagerInfo.PageSize;
this.MaxResultCount = this.PagerInfo.PageSize;
}
查询处理的代码如下所示(在视图模型上处理代码)
/// <summary>
/// 触发查询处理命令
/// </summary>
/// <returns></returns>
[RelayCommand]
public virtual void Search()
{
//切换第一页
this.PagerInfo.CurrentPageIndex = 1;
//查询更新
GetData();
} /// <summary>
/// 根据分页和查询条件查询,请求数据
/// </summary>
/// <returns></returns>
public virtual void GetData()
{
//转换下分页信息
ConvertPagingInfo();
if (this.Filter.IsNullOrEmpty())
{
this.IconItems = AllItems.Skip(this.SkipCount).Take(this.MaxResultCount).ToList();
this.PagerInfo.RecordCount = this.AllItems.Count;
}
else
{
this.IconItems = AllItems.Where(s => s.Text.Contains(this.Filter, StringComparison.OrdinalIgnoreCase)).Skip(this.SkipCount).Take(this.MaxResultCount).ToList();
this.PagerInfo.RecordCount = AllItems.Where(s => s.Text.Contains(this.Filter, StringComparison.OrdinalIgnoreCase)).Count();
}
}
选择图标的列表展示界面,遵循MVVM的视图界面代码规范,标准化处理即可,对查询搜索框的处理响应进行查询处理。
/// <summary>
/// SymbolRegularSelectPage.xaml 交互逻辑
/// </summary>
public partial class SymbolRegularSelectPage : INavigableView<SymbolRegularListViewModel>
{
/// <summary>
/// 视图模型对象
/// </summary>
public SymbolRegularListViewModel ViewModel { get; } /// <summary>
/// 构造函数
/// </summary>
/// <param name="viewModel">视图模型对象</param>
public SymbolRegularSelectPage(SymbolRegularListViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
} /// <summary>
/// 过滤查询事件
/// </summary>
private void SearchBar_OnSearchStarted(object sender, HandyControl.Data.FunctionEventArgs<string> e)
{
this.ViewModel.Search();
}
2、对图标使用ItemsControl控件进行控制输出
图标是一个集合对象,因此我们如果需要按照我们格式进行展示,可以使用ItemsControl来进行处理。
ItemsControl可以通过控制 ItemsControl.ItemsPanel 的ItemsPanelTemplate模板进行控制布局面板,可以通过控制 ItemsControl.Template 的ControlTemplate来控制输出格式的总模板,可以通过控制 ItemsControl.ItemTemplate的DataTemplate来控制输出每个项目的模板,这个控件ItemsControl提供了很灵活的控制模板处理。如下XAML界面代码所示。
<ItemsControl
x:Name="chkIcons"
Height="580"
HorizontalContentAlignment="Left"
ItemsSource="{Binding ViewModel.IconItems}"
ScrollViewer.CanContentScroll="True"
VirtualizingStackPanel.IsVirtualizing="true"
VirtualizingStackPanel.VirtualizationMode="Standard">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
HorizontalAlignment="Left"
VerticalAlignment="Top"
Columns="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Width="80"
Height="80"
Margin="8,8"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="Button_Click"
FontSize="32"
MouseDoubleClick="Button_MouseDoubleClick"
Tag="{Binding}"
ToolTip="{Binding Text, Mode=OneTime}"
ToolTipService.InitialShowDelay="240">
<ui:SymbolIcon
FontSize="48"
Foreground="CornflowerBlue"
Symbol="{Binding Text}"
Tag="{Binding}"
ToolTip="{Binding Text}" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer
Width="Auto"
CanContentScroll="True"
VerticalScrollBarVisibility="Visible">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
展示界面效果如下所示

当然这里面还有分页的界面代码,使用的是HandyControl的分页控件处理。
<hc:Pagination
DataCountPerPage="{Binding ViewModel.PagerInfo.PageSize}"
IsJumpEnabled="True"
MaxPageCount="{Binding ViewModel.PagerInfo.MaxPageCount}"
MaxPageInterval="5"
PageIndex="{Binding ViewModel.PagerInfo.CurrentPageIndex, UpdateSourceTrigger=PropertyChanged}">
<hc:Interaction.Triggers>
<hc:EventTrigger EventName="PageUpdated">
<hc:EventToCommand Command="{Binding ViewModel.PageUpdatedCommand}" PassEventArgsToCommand="True" />
</hc:EventTrigger>
</hc:Interaction.Triggers>
</hc:Pagination>
而对每项的选择,我们单击选中,双击选中并返回处理,代码逻辑如下所示。
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
if (button != null)
{
if (button.Tag is CListItem item)
{
this.ViewModel.SelectedItem = item;
}
}
} private void Button_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var button = (Button)sender;
if (button != null)
{
if (button.Tag is CListItem item)
{
this.ViewModel.SelectedItem = item;
this.DialogResult = true;
}
}
}
而选择的信息展示,我们可以通过一个面板来组合展示相关图标名称和图标效果即可。
<WrapPanel
Grid.Column="0"
Margin="10,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="当前选择:" />
<ui:SymbolIcon
FontSize="32"
Foreground="CornflowerBlue"
Symbol="{Binding ViewModel.SelectedItem.Text}"
ToolTip="{Binding ViewModel.SelectedItem.Text}" />
<TextBlock
Margin="10,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Blue"
Text="{Binding ViewModel.SelectedItem.Text}" />
</WrapPanel>
确认选择后返回的内容展示,我们也是使用类似的方式处理界面的

红色框的界面XAML代码如下所示。
<!-- 组合多个控件显示 -->
<hc:ElementGroup
Width="350"
Height="32"
Margin="5"
Layout="Stack"
Orientation="Horizontal">
<TextBox
x:Name="txtIcon"
Width="230"
hc:TitleElement.Title="图标"
hc:TitleElement.TitlePlacement="Left"
IsReadOnly="True"
Text="{Binding ViewModel.Item.Icon, UpdateSourceTrigger=PropertyChanged}" />
<Border Padding="1,0" Style="{StaticResource BorderRegion}">
<ui:SymbolIcon
Width="50"
FontSize="32"
Symbol="{Binding ViewModel.Item.Icon, UpdateSourceTrigger=PropertyChanged}" />
</Border>
<Button
Command="{Binding SelectIconCommand}"
Content="选择图标"
Style="{StaticResource ButtonPrimary}" />
</hc:ElementGroup>
后面就是存储处理,按照窗口界面弹出,并存储对象属性即可。
3、扩展到Font-Awesome-WPF的处理进行展示和选择
在WPF中使用Font-Awesome-WPF 图标组件的很多,它的项目地址:https://github.com/charri/Font-Awesome-WPF/blob/master/README-WPF.md。
我们也可以用类似的方式来整合这个图标组件到项目中进行使用。
首先在项目的Nugget上添加安装FontAwesome.WPF组件。

或者通过命令进行安装
PM> Install-Package FontAwesome.WPF
在使用的XAML中添加对应的命名空间。
xmlns:fa="http://schemas.fontawesome.io/icons/"
这个图标的组件使用比较简单如下代码所示。
<fa:FontAwesome Icon="Flag" />
和前面的图标组件处理类似,同样需要处理图标枚举到具体图标列表展示的处理过程,图标选择界面运行效果如下所示,由于图标不是很多,所以一次性加载了。

我们先创建MVVM的视图模型对象,如下所示代码。
/// <summary>
/// FontAwesome.WPF的图标查询视图模型
/// </summary>
public partial class FontAwesomeListViewModel : BaseViewModel
{
[ObservableProperty]
private CListItem selectedItem = new(); /// <summary>
/// 符合条件的图标列表
/// </summary>
[ObservableProperty]
private List<CListItem> iconItems = new(); /// <summary>
/// 所有图标
/// </summary>
[ObservableProperty]
private List<CListItem> allItems = new(); /// <summary>
/// 构造函数
/// </summary>
public FontAwesomeListViewModel()
{
this.Title = "FontAwesome.WPF的图标"; //FontAwesomeIcon.Book = 0xf02d
var iconList = EnumHelper.GetMemberKeyValue<FontAwesomeIcon>();
foreach (var icon in iconList)
{
this.AllItems.Add(new CListItem(icon.Key, icon.Value.ToString()));
} ResetData();
}
ItemsControl的对象展示类似,如下所示。
<ItemsControl
x:Name="chkIcons"
Height="900"
HorizontalContentAlignment="Left"
ItemsSource="{Binding ViewModel.IconItems}"
ScrollViewer.CanContentScroll="True"
VirtualizingStackPanel.IsVirtualizing="true"
VirtualizingStackPanel.VirtualizationMode="Standard">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
HorizontalAlignment="Left"
VerticalAlignment="Top"
Columns="9" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Width="80"
Height="80"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="Button_Click"
FontSize="32"
MouseDoubleClick="Button_MouseDoubleClick"
Tag="{Binding}"
ToolTip="{Binding Text, Mode=OneTime}"
ToolTipService.InitialShowDelay="240">
<fa:ImageAwesome
Width="32"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="CornflowerBlue"
Icon="{Binding Text}"
Tag="{Binding}" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer
Width="Auto"
CanContentScroll="True"
VerticalScrollBarVisibility="Visible">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
其实处理的逻辑类似了。在调用的父页面中展示也是使用相应的图标代码即可。
<fa:FontAwesome
Width="50"
FontSize="32"
Icon="{Binding ViewModel.Item.Icon, UpdateSourceTrigger=PropertyChanged}"
ToolTip="{Binding ViewModel.Item.Icon}" />
这样通过动态配置的菜单,我们就可以让它在系统运行的时候动态加载对应的菜单图标了。
菜单模块配置界面列表效果。

系统运行,动态从后端获取菜单及图标展示如下所示。

循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(7) -- 图标列表展示和选择处理的更多相关文章
- 基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发
我喜欢在一个项目开发模式成熟的时候,使用代码生成工具Database2Sharp来配套相关的代码生成,对于我介绍的基于SqlSugar的开发框架,从整体架构确定下来后,我就着手为它们量身定做相关的代码 ...
- 推荐一个基于Vue2.0的的一款移动端开发的UI框架,特别好用。。。
一丶YDUI 一只注重审美,且性能高效的移动端&微信UI. 下面为地址自己研究去吧! 我的项目正在用,以前用的Mint-ui但是现在感觉还是这个好一点,官方给出的解释很清楚,很实用. 官方地址 ...
- 基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
我们在设计数据库表的时候,往往为了方便,主键ID一般采用字符串类型或者GUID类型,这样对于数据库表记录的迁移非常方便,而且有时候可以在处理关联记录的时候,提前对应的ID值.但有时候进行数据记录插入的 ...
- 基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转
在前面随笔,我们介绍过这个基于SqlSugar的开发框架,我们区分Interface.Modal.Service三个目录来放置不同的内容,其中Modal是SqlSugar的映射实体,Interface ...
- 基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口
在基于SqlSugar的开发框架中,我们设计了一些系统服务层的基类,在基类中会有很多涉及到相关的数据处理操作的,如果需要跟踪具体是那个用户进行操作的,那么就需要获得当前用户的身份信息,包括在Web A ...
- 基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录
在我们对数据进行重要修改调整的时候,往往需要跟踪记录好用户操作日志.一般来说,如对重要表记录的插入.修改.删除都需要记录下来,由于用户操作日志会带来一定的额外消耗,因此我们通过配置的方式来决定记录那些 ...
- 基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理
在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询.详细资料查看.新增资料.编辑资料.导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于V ...
- 基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用
在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于El ...
- 基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用
刚完成一些前端项目的开发,腾出精力来总结一些前端开发的技术点,以及继续完善基于SqlSugar的开发框架循序渐进介绍的系列文章,本篇随笔主要介绍一下基于Vue3+TypeScript的全局对象的注入和 ...
- 基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理
在一个应用系统的开发框架中,往往很多地方需要用到缓存的处理,有些地方是为了便于记录用户的数据,有些地方是为了提高系统的响应速度,如有时候我们在发送一个短信验证码的时候,可以在缓存中设置几分钟的过期时间 ...
随机推荐
- 一招带你吃透MySQL高级
MySQL8高级之架构和优化 让 第01章 Linux下MySQL的安装与使用 1.安装 1.1.docker安装 docker run -d \ -p 3309:3306 \ -v /atguigu ...
- Java 字符串反转,举例:键盘录入”abc”输出结果:”cba”
代码如下: public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out. ...
- 讯飞离线语音合成新版(Aikit)-android sdk合成 demo(Java版本)
前言:科大讯飞的新版离线语音合成,由于官网demo是kt语言开发的,咱也看不懂kt,搜遍了全网也没看到一个java版的新版离线语音demo,现记录下,留给有缘人参考!!!!!毕竟咱在这上面遇到了不少的 ...
- 1、笔记本刷ubuntu,安装饥荒服务器
目录 笔记本刷ubuntu,安装饥荒服务器 一.准备 二.笔记本刷机 1.制作Ubuntu server U盘启动盘 2.刷机 3.设置电源不休眠 三.安装饥荒服务器 四.最后说下网络 笔记本刷ubu ...
- 3D降噪_运动估计块运动匹配
运动估计 运动估计是视频去噪技术的重要组成之一,计算相邻两帧视频序列各像素的相对运动偏移量,从而得到其运动轨迹. 点 ( i , j ) (i,j) (i,j)和 ( x , y ) (x,y) (x ...
- java协程线程之虚拟线程
前言 众所周知,java 是没有协程线程的,在我们如此熟知的jdk 1.8时代,大佬们想出来的办法就是异步io,甚至用并行的stream流来实现,高并发也好,缩短事件处理时间也好:大家都在想着自己认为 ...
- Java Maven Settings配置参考
介绍 快速概览 settings.xml文件中的 settings 元素包含用于定义以各种方式配置Maven执行的值的元素,如pom.xml,但不应绑定到任何特定项目或分发给受众.这些值包括本地仓库位 ...
- Sealos 私有化部署完全指南
Sealos 用了五年的时间从一个 K8s 一键安装工具蜕变成了一个真正的云操作系统,将产品体验提升到了极致,也收获了 10w+ 的社区用户. 一个多月前,Sealos 正式发布了公有云托管版本,社区 ...
- windows安装uwsgi报错 AttributeError: module 'os' has no attribute 'uname'
Win10系统不支持安装UWSGI, 不用尝试了 安装 pip install uwsgi windows安装报错 AttributeError: module 'os' has no attribu ...
- JVM调优篇:探索Java性能优化的必备种子面试题
JVM内存模型 首先面试官会询问你在进行JVM调优之前,是否了解JVM内存模型的基础知识.这是一个重要的入门问题.JVM内存模型主要包括程序计数器.堆.本地方法栈.Java栈和方法区(1.7之后更改为 ...