WPF实现树形下拉列表框(TreeComboBox)

这篇具有很好参考价值的文章主要介绍了WPF实现树形下拉列表框(TreeComboBox)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  树形下拉菜单是许多WPF应用程序中常见的用户界面元素,它能够以分层的方式展示数据,提供更好的用户体验。本文将深入探讨如何基于WPF创建一个可定制的树形下拉菜单控件,涵盖从原理到实际实现的关键步骤。

一、需求分析

      树形下拉菜单控件的核心是将ComboBox与TreeView结合起来,以实现下拉时的树状数据展示。在WPF中,可以通过自定义控件模板、样式和数据绑定来实现这一目标。

      我们首先来分析一下ComboBox控件的模板。

<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
    <Grid x:Name="templateRoot" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
        </Grid.ColumnDefinitions>
        <Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Margin="1" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
            <theme:SystemDropShadowChrome x:Name="shadow" Color="Transparent" MinWidth="{Binding ActualWidth, ElementName=templateRoot}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
                <Border x:Name="dropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
                    <ScrollViewer x:Name="DropDownScrollViewer">
                        <Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
                            <Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                <Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
                            </Canvas>
                            <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Grid>
                    </ScrollViewer>
                </Border>
            </theme:SystemDropShadowChrome>
        </Popup>
        <ToggleButton x:Name="toggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
        <ContentPresenter x:Name="contentPresenter" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Content="{TemplateBinding SelectionBoxItem}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    </Grid>
</ControlTemplate>

  从以上代码可以看出,其中的Popup控件就是下拉部分,那么按照常理,我们在Popup控件中放入一个TreeView控件即可实现该需求,但是现实情况远没有这么简单。我们开发一个控件,不仅要从外观上实现功能,还需要考虑数据绑定、事件触发、自定义模板等方面的问题,显然,直接放置一个TreeView控件虽然也能实现功能,但是从封装的角度看,它并不优雅,使用也不方便。那么有没有更好的方法满足以上需求呢?下面提供另一种思路,其核心思想就是融合ComboBox控件与TreeView控件模板,让控件既保留TreeView的特性,又拥有ComboBox的外观。

 二、代码实现

2.1 编辑TreeView模板;

2.2 提取ComboBox的模板代码;

2.3 将ComboBox的模板代码移植到TreeView模板中;

2.4 将TreeView模板包含ItemsPresenter部分的关键代码放入ComboBox模板中的Popup控件内;

      以下为融合后的xaml代码

<ControlTemplate TargetType="{x:Type local:TreeComboBox}">
    <Grid x:Name="templateRoot" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0" MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" />
        </Grid.ColumnDefinitions>
        <Popup
                            x:Name="PART_Popup"
                            Grid.ColumnSpan="2"
                            MaxHeight="{TemplateBinding MaxDropDownHeight}"
                            Margin="1"
                            AllowsTransparency="true"
                            IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                            Placement="Bottom"
                            PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
            <Border
                                x:Name="PART_Border"
                                Width="{Binding RelativeSource={RelativeSource AncestorType=local:TreeComboBox}, Path=ActualWidth}"
                                Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
                                BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
                                BorderThickness="1"
                                SnapsToDevicePixels="true">
                <ScrollViewer
                                    x:Name="_tv_scrollviewer_"
                                    Padding="{TemplateBinding Padding}"
                                    Background="{TemplateBinding Background}"
                                    CanContentScroll="false"
                                    Focusable="false"
                                    HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                    VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
                    <ItemsPresenter />
                </ScrollViewer>
            </Border>
        </Popup>
        <ToggleButton
                            x:Name="toggleButton"
                            Grid.ColumnSpan="2"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                            Style="{StaticResource ComboBoxToggleButton}" />
        <ContentPresenter
                            x:Name="contentPresenter"
                            Margin="{TemplateBinding Padding}"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            Content="{TemplateBinding SelectionBoxItem}"
                            ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                            IsHitTestVisible="False" />
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="false">
            <Setter TargetName="PART_Border" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
        </Trigger>
        <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
            <Setter TargetName="_tv_scrollviewer_" Property="CanContentScroll" Value="true" />
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsGrouping" Value="true" />
                <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
            </MultiTrigger.Conditions>
            <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

       以下为使用控件的代码。

<TreeComboBox
                Width="315"
                MinHeight="30"
                Padding="5"
                HorizontalAlignment="Center"
                VerticalAlignment="Top"
                VerticalContentAlignment="Stretch"
                IsAutoCollapse="True"
                ItemsSource="{Binding Collection}">
    <TreeComboBox.SelectionBoxItemTemplate>
        <ItemContainerTemplate>
            <Border>
                <TextBlock VerticalAlignment="Center" Text="{Binding Property1}" />
            </Border>
        </ItemContainerTemplate>
    </TreeComboBox.SelectionBoxItemTemplate>
    <TreeComboBox.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Collection}">
            <TextBlock
                            Margin="5,0,0,0"
                            VerticalAlignment="Center"
                            Text="{Binding Property1}" />
        </HierarchicalDataTemplate>
    </TreeComboBox.ItemTemplate>
</TreeComboBox>

三、运行效果

3.1 单选效果

WPF实现树形下拉列表框(TreeComboBox)

 文章来源地址https://www.toymoban.com/news/detail-844123.html

 3.2 多选效果

WPF实现树形下拉列表框(TreeComboBox)

 

四、个性化外观

   当控件默认外观无法满足需求时,我们可以通过编辑样式的方式来实现个性化外观,也可以引用第三方UI库样式,以下为使用MaterialDesign的效果。

4.1 单选效果

WPF实现树形下拉列表框(TreeComboBox)

 

4.2 多选效果

 

 

WPF实现树形下拉列表框(TreeComboBox)

 

 

到了这里,关于WPF实现树形下拉列表框(TreeComboBox)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • el-select与el-tree结合使用,实现select框下拉使用树形结构选择数据

    使用el-select与el-tree,实现如下效果, 代码如下:  注意点:搜索input框的代码一点放在option上面,不要放在option里面,否则一点击搜索框,下拉框就会收起来,不能使用。

    2024年02月13日
    浏览(37)
  • QT实现多级下拉列表导航菜单,可折叠(QTreewidget实现)

    目录 创建多级列表 在ui中拖入一个QTreewidget控件。 双击该控件,打开编辑树窗口部件。​编辑​编辑 进行列表控件设置: 在项目前添加图标: 效果: QT实现多级下拉列表,可折叠 做项目的时候需要实现一个可折叠的多级下拉列表,用QTreewidget就可以实现,而且直接在ui文件

    2024年02月16日
    浏览(40)
  • 前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)

    目录 一、前言 1.什么是树形菜单 2.树形菜单的使用场景 二、案例实现 1.需求分析 2.前期准备工作 ①导入依赖 ②工具类 BaseDao(通用增删改查) BuildTree(完成平级数据到父子级的转换) ResponseUtil(将数据转换成json格式进行回显) ③编写实体 3.dao层编写 4.servlet层编写 5.jsp页面搭

    2024年02月13日
    浏览(26)
  • Vue Treeselect树形下拉框的使用

        昨天在做一个表单,里面有一项是以tree形式为选项的select框↓      于是乎,用到了vue中的treeselect组件,在此记录一下。 1、绑值, :value=“form.astdeptId”,主要绑的就是id或者code,通过id或code找到对应的label回显 2、options是数据源,正常调接口获取就行了 3、append-to-bo

    2024年02月06日
    浏览(34)
  • 在WPF应用中使用GongSolutions.WPF.DragDrop实现列表集合控件的拖动处理

    WPF应用中,控件本身也可以通过实现事件代码实现拖动的处理,不过如果我们使用GongSolutions.WPF.DragDrop来处理,事情会变得更加简单轻松,它支持很多控件的拖动处理,如ListBox, ListView, TreeView, DataGrid等源自ItemsControl的控件,本篇随笔介绍在工作流模块中拖动TreeView和DataGrid列表

    2024年02月05日
    浏览(33)
  • 如何自定义iview树形下拉内的内容

    1.使用render函数给第一层父级定义  2. 使用树形结构中的render函数来定义子组件  3.呈现结构  

    2024年02月10日
    浏览(22)
  • vue element select下拉框树形多选

    components 文件下新建 SelectTree文件 index.vue SelectTree index.vue 使用:

    2024年02月13日
    浏览(35)
  • vue2+elementUI 下拉树形多选框

    效果如图所示:  1.新建el-select-tree.vue组件 2.页面引入组件使用

    2024年02月12日
    浏览(33)
  • vue2 - 详细介绍element UI中在el-select嵌套el-tree树形控件实现下拉选择树型结构数据的效果实例(组件封装)

    在项目上常用使用到 el-select 和 el-tree 组合实现,记录下两者结合的实现过程。(代码以及注释清晰明了,代码直接使用即可) 要求根据项目接口提供的数据,el-tree 里的数据是一次性返回来的,点击最后一层级时,请求接口,在点击层级下方追加数据追加的数据要显示勾

    2024年04月15日
    浏览(43)
  • java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数

    将数据源放到一个新建的隐藏的sheet中 将选项的子选项的对应字典设置到名称管理器中(名称是当前选项的内容,值是他对应的子菜单的单元格范围,在1里面的sheet中) 子菜单的数据根据INDIRECT函数去左边那个单元格获取内容,根据内容去名称管理器中获取字典的key,也就是

    2024年01月22日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包