循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(7) -- 图标列表展示和选择处理

简介: 循序渐进介绍基于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}" />

这样通过动态配置的菜单,我们就可以让它在系统运行的时候动态加载对应的菜单图标了。

菜单模块配置界面列表效果。

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

 

链接附注

如对我们的代码生成工具有兴趣,可以到官网下载使用《代码生成工具Database2Sharp》。

如需了解我们官网对《SqlSugar开发框架》的介绍,可以参考《SqlSugar开发框架》了解。

如需阅读我们对于《SqlSugar开发框架》文章介绍,可以参考博客园的随笔标签《SqlSugar随笔 , WPF随笔》学习了解。

 

专注于代码生成工具、.Net/.NetCore 框架架构及软件开发,以及各种Vue.js的前端技术应用。著有Winform开发框架/混合式开发框架、微信开发框架、Bootstrap开发框架、ABP开发框架、SqlSugar开发框架等框架产品。
 转载请注明出处:撰写人:伍华聪  http://www.iqidi.com

相关文章
|
3月前
|
C# 开发者 Windows
WPF 应用程序开发:一分钟入门
本文介绍 Windows Presentation Foundation (WPF),这是一种用于构建高质量、可缩放的 Windows 桌面应用程序的框架,支持 XAML 语言,方便 UI 设计与逻辑分离。文章涵盖 WPF 基础概念、代码示例,并深入探讨常见问题及解决方案,包括数据绑定、控件样式与模板、布局管理等方面,帮助开发者高效掌握 WPF 开发技巧。
173 65
C# WPF 中 外部图标引入iconfont,无法正常显示问题 【小白记录】
本文介绍了在C# WPF应用程序中引入外部iconfont图标时可能遇到的显示问题及其解决方法:1) 检查资源路径和引入格式是否正确,确保字体文件引用格式为“#xxxx”,并正确指向字体文件位置;2) 确保图标资源被包含在程序集中,通过设置字体文件的生成操作为Resource(资源)来实现。
C# WPF 中 外部图标引入iconfont,无法正常显示问题 【小白记录】
|
4月前
|
C# UED 开发者
WPF与性能优化:掌握这些核心技巧,让你的应用从卡顿到丝滑,彻底告别延迟,实现响应速度质的飞跃——从布局到动画全面剖析与实例演示
【8月更文挑战第31天】本文通过对比优化前后的方法,详细探讨了提升WPF应用响应速度的策略。文章首先分析了常见的性能瓶颈,如复杂的XAML布局、耗时的事件处理、不当的数据绑定及繁重的动画效果。接着,通过具体示例展示了如何简化XAML结构、使用后台线程处理事件、调整数据绑定设置以及利用DirectX优化动画,从而有效提升应用性能。通过这些优化措施,WPF应用将更加流畅,用户体验也将得到显著改善。
301 1
|
4月前
|
安全 C# 数据安全/隐私保护
WPF安全加固全攻略:从数据绑定到网络通信,多维度防范让你的应用固若金汤,抵御各类攻击
【8月更文挑战第31天】安全性是WPF应用程序开发中不可或缺的一部分。本文从技术角度探讨了WPF应用面临的多种安全威胁及防护措施。通过严格验证绑定数据、限制资源加载来源、实施基于角色的权限管理和使用加密技术保障网络通信安全,可有效提升应用安全性,增强用户信任。例如,使用HTML编码防止XSS攻击、检查资源签名确保其可信度、定义安全策略限制文件访问权限,以及采用HTTPS和加密算法保护数据传输。这些措施有助于全面保障WPF应用的安全性。
62 0
|
4月前
|
C# 开发者 Windows
全面指南:WPF无障碍设计从入门到精通——让每一个用户都能无障碍地享受你的应用,从自动化属性到焦点导航的最佳实践
【8月更文挑战第31天】为了确保Windows Presentation Foundation (WPF) 应用程序对所有用户都具备无障碍性,开发者需关注无障碍设计原则。这不仅是法律要求,更是社会责任,旨在让技术更人性化,惠及包括视障、听障及行动受限等用户群体。
95 0
|
4月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
109 0
|
4月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
118 0
|
7月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
398 0
|
7月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
154 1
|
4月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件