• 循序渐进介绍基于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)图标选择后的展示界面

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

     为了有效的对图标进行分页展示,视图模型需要包含一些分页所需的对象信息,如下代码所示。

    复制代码
        /// 
        /// SymbolRegular 的图标查询视图模型
        /// 
        public partial class SymbolRegularListViewModel : BaseViewModel
        {
            /// 
            /// 选择的图表项目
            /// 
            [ObservableProperty]
            private CListItem selectedItem = new();
    
            /// 
            /// 符合条件的图标列表
            /// 
            [ObservableProperty]
            private List iconItems = new();
    
            /// 
            /// 所有图标
            /// 
            [ObservableProperty]
            private List allItems = new();
    
            /// 
            /// 分页对象
            /// 
            [ObservableProperty]
            private PagingData pagerInfo = new PagingData() { CurrentPageIndex = 1, PageSize =60 };
    复制代码

    由于图标不用访问数据库,因此在枚举读取初始化后存储所有的图标集合,并以集合为基础进行图标名称的检索及排序处理。

    在查询处理的时候,我们需要把分页的页码和页面大小等信息转换为记录数的跳转及获取变量,如下所示。

    复制代码
    /// 
    /// 转换下分页信息,为查询对象的属性
    /// 
    protected virtual void ConvertPagingInfo()
    {
        //根据传入的分页信息构建查询记录数和位置
        this.SkipCount = (this.PagerInfo.CurrentPageIndex - 1) * this.PagerInfo.PageSize;
        this.MaxResultCount = this.PagerInfo.PageSize;
    }
    复制代码

    查询处理的代码如下所示(在视图模型上处理代码)

    复制代码
    /// 
    /// 触发查询处理命令
    /// 
    /// 
    [RelayCommand]
    public virtual void Search()
    {
        //切换第一页
        this.PagerInfo.CurrentPageIndex = 1;
        //查询更新
        GetData();
    }
    
    /// 
    /// 根据分页和查询条件查询,请求数据
    /// 
    /// 
    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的视图界面代码规范,标准化处理即可,对查询搜索框的处理响应进行查询处理。

    复制代码
    /// 
    /// SymbolRegularSelectPage.xaml 交互逻辑
    /// 
    public partial class SymbolRegularSelectPage : INavigableView<SymbolRegularListViewModel>
    {
        /// 
        /// 视图模型对象
        /// 
        public SymbolRegularListViewModel ViewModel { get; }  
    
        /// 
        /// 构造函数
        /// 
        /// 视图模型对象
        public SymbolRegularSelectPage(SymbolRegularListViewModel viewModel)
        {
            ViewModel = viewModel;
            DataContext = this;
            InitializeComponent();
        }
    
        /// 
        /// 过滤查询事件
        /// 
        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的视图模型对象,如下所示代码。

    复制代码
    /// 
    /// FontAwesome.WPF的图标查询视图模型
    /// 
    public partial class FontAwesomeListViewModel : BaseViewModel
    {
        [ObservableProperty]
        private CListItem selectedItem = new();
    
        /// 
        /// 符合条件的图标列表
        /// 
        [ObservableProperty]
        private List iconItems = new();
    
        /// 
        /// 所有图标
        /// 
        [ObservableProperty]
        private List allItems = new();
    
        /// 
        /// 构造函数
        /// 
        public FontAwesomeListViewModel()
        {
            this.Title = "FontAwesome.WPF的图标";
    
            //FontAwesomeIcon.Book = 0xf02d
            var iconList = EnumHelper.GetMemberKeyValue();
            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}" />
    复制代码

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

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

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

     

  • 相关阅读:
    什么是数据压缩?解释数据压缩的原理和不同的压缩算法
    易点易动设备管理系统帮助生产企业提升设备巡检效率
    MYSQL(基本篇)——一篇文章带你走进MYSQL的奇妙世界
    第四章 二叉树
    react使用@reduxjs/toolkit和react-redux实现store状态管理
    DevExpress WinForm嵌入子图、允许数据换行显示
    java 两个list比较,删除相同的元素
    2512.奖励最顶尖的K名学生
    高数 | 导数极限定理、分段点求导能不能用公式?导数和导数的极限?
    C++入门学习(4)引用 (讲解拿指针比较)
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/17762715.html