WPF中使用ListView封装组合控件TreeView+DataGrid

 (关注博主后,在“粉丝专栏”,可免费阅读此文)        

wpf的功能非常强大,很多控件都是原生的,但是要使用TreeView+DataGrid的组合,就需要我们自己去封装实现。

我们需要的效果如图所示:

这2个图都是第三方控件自带的,并且都是收费使用。

现在我们就用原生的控件进行封装一个。

本文源码效果截图,(搞了好几天,的确有难度,所以源码也收费,便宜,赚点辛苦费)

功能如上图所示, 目前基本上把常用的样式都实现了,购买源码后,可以自行修改样式。

首先说明一下,实现上面的效果,有3种方法

第一种:技术的选择是TreeView。

WPF中使用TreeView封装组合控件TreeView+DataGrid-CSDN博客

第二种:技术的选择是DataGrid。

WPF中使用DataGrid封装组合控件TreeView+DataGrid-CSDN博客

第三种:技术的选择是ListView。(也就是本文的演示)

本文演示的是ListView的实现。

1.首先建立一个wpf程序

2.封装TreeList.cs



namespace ListView.TreeDataGrid
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    public class TreeList : ListView
    {
        #region Properties

        /// <summary>
        /// Internal collection of rows representing visible nodes, actually displayed in the ListView
        /// </summary>
        internal ObservableCollectionAdv<TreeNode> Rows
        {
            get;
            private set;
        }


        private ITreeModel _model;
        public ITreeModel Model
        {
            get { return _model; }
            set
            {
                if (_model != value)
                {
                    _model = value;
                    _root.Children.Clear();
                    Rows.Clear();
                    CreateChildrenNodes(_root);
                }
            }
        }

        private TreeNode _root;
        internal TreeNode Root
        {
            get { return _root; }
        }

        public ReadOnlyCollection<TreeNode> Nodes
        {
            get { return Root.Nodes; }
        }

        internal TreeNode PendingFocusNode
        {
            get;
            set;
        }

        public ICollection<TreeNode> SelectedNodes
        {
            get
            {
                return SelectedItems.Cast<TreeNode>().ToArray();
            }
        }

        public TreeNode SelectedNode
        {
            get
            {
                if (SelectedItems.Count > 0)
                    return SelectedItems[0] as TreeNode;
                else
                    return null;
            }
        }
        #endregion

        public TreeList()
        {
            Rows = new ObservableCollectionAdv<TreeNode>();
            _root = new TreeNode(this, null);
            _root.IsExpanded = true;
            ItemsSource = Rows;
            ItemContainerGenerator.StatusChanged += ItemContainerGeneratorStatusChanged;
        }

        void ItemContainerGeneratorStatusChanged(object sender, EventArgs e)
        {
            if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated && PendingFocusNode != null)
            {
                var item = ItemContainerGenerator.ContainerFromItem(PendingFocusNode) as TreeListItem;
                if (item != null)
                    item.Focus();
                PendingFocusNode = null;
            }
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new TreeListItem();
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is TreeListItem;
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            var ti = element as TreeListItem;
            var node = item as TreeNode;
            if (ti != null && node != null)
            {
                ti.Node = item as TreeNode;
                base.PrepareContainerForItemOverride(element, node.Tag);
            }
        }

        internal void SetIsExpanded(TreeNode node, bool value)
        {
            if (value)
            {
                if (!node.IsExpandedOnce)
                {
                    node.IsExpandedOnce = true;
                    node.AssignIsExpanded(value);
                    CreateChildrenNodes(node);
                }
                else
                {
                    node.AssignIsExpanded(value);
                    CreateChildrenRows(node);
                }
            }
            else
            {
                DropChildrenRows(node, false);
                node.AssignIsExpanded(value);
            }
        }

        internal void CreateChildrenNodes(TreeNode node)
        {
            var children = GetChildren(node);
            if (children != null)
            {
                int rowIndex = Rows.IndexOf(node);
                node.ChildrenSource = children as INotifyCollectionChanged;
                foreach (object obj in children)
                {
                    TreeNode child = new TreeNode(this, obj);
                    child.HasChildren = HasChildren(child);
                    node.Children.Add(child);
                }
                Rows.InsertRange(rowIndex + 1, node.Children.ToArray());
            }
        }

        private void CreateChildrenRows(TreeNode node)
        {
            int index = Rows.IndexOf(node);
            if (index >= 0 || node == _root) // ignore invisible nodes
            {
                var nodes = node.AllVisibleChildren.ToArray();
                Rows.InsertRange(index + 1, nodes);
            }
        }

        internal void DropChildrenRows(TreeNode node, bool removeParent)
        {
            int start = Rows.IndexOf(node);
            if (start >= 0 || node == _root) // ignore invisible nodes
            {
                int count = node.VisibleChildrenCount;
                if (removeParent)
                    count++;
                else
                    start++;
                Rows.RemoveRange(start, count);
            }
        }

        private IEnumerable GetChildren(TreeNode parent)
        {
            if (Model != null)
                return Model.GetChildren(parent.Tag);
            else
                return null;
        }

        private bool HasChildren(TreeNode parent)
        {
            if (parent == Root)
                return true;
            else if (Model != null)
                return Model.HasChildren(parent.Tag);
            else
                return false;
        }

        internal void InsertNewNode(TreeNode parent, object tag, int rowIndex, int index)
        {
            TreeNode node = new TreeNode(this, tag);
            if (index >= 0 && index < parent.Children.Count)
                parent.Children.Insert(index, node);
            else
            {
                index = parent.Children.Count;
                parent.Children.Add(node);
            }
            Rows.Insert(rowIndex + index + 1, node);
        }
    }
}

3.TreeStyles.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:local="clr-namespace:ListView.TreeDataGrid"
                    >
    <Style TargetType="{x:Type local:TreeListItem}">
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
        <Style.Triggers>
            <!--隔行换色-->
            <Trigger Property="ListBox.AlternationIndex"  Value="0" >
                <Setter Property="Background" Value="#e7e7e7" />
            </Trigger>
            <Trigger Property="ListBox.AlternationIndex" Value="1" >
                <Setter Property="Background" Value="#f2f2f2" />
            </Trigger>

            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" Value="Orange"/>
            </Trigger>

            <Trigger Property="IsSelected" Value="True">
                <!--选中的行颜色-->
                <Setter Property="Background" Value="Aqua"/>
            </Trigger>
        </Style.Triggers>
    </Style>

    <Style x:Key="TreeListItemNodeStyle" TargetType="{x:Type local:TreeListItem}" >
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
										  ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" 
										  HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
										  VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
										  SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                    <ControlTemplate.Triggers>
                        <Trigger Property="UIElement.IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground">
                                <Setter.Value>
                                    <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

4.最终源码实例

说明: 使用ListView封装的时候,难度最大,或者没有找到最好的方法实现。

需要源码请联系我。

本文来源:

WPF中使用ListView封装组合控件TreeView+DataGrid-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/265895.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nsum问题

题目 题解 暴力法 class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:if len(nums) < 4:return []nums.sort()N len(nums)res []for i in range(N-3):for j in range(i1, N-2):for k in range(j1, N-1):for m in range(k1, N):tmp…

灰盒测试简要指南!

在本文中&#xff0c;我们将了解什么是灰盒测试、以及为什么要使用它&#xff0c;以及它的优缺点。 在软件测试中&#xff0c;灰盒测试是一种有用的技术&#xff0c;可以确保发布的软件是高性能的、安全的并满足预期用户的需求。这是一种从外部测试应用程序同时跟踪其内部操作…

ffmpeg使用入门

1. ffmpeg是什么&#xff1a; FFmpeg是一款音视频编解码工具&#xff0c;也是一组音视频编解码开发套件&#xff0c;为开发者提供了丰富的音视频处理调用接口。 FFmpeg源代码编译后会生成三个可执行程序&#xff0c;分别是&#xff1a;ffmpeg、ffplay、ffprobe&#xff0c; 这…

行为型设计模式(四):中介模式 命令模式

中介模式 Mediator 1、什么是中介模式 中介模式用于减少对象之间的直接通信&#xff0c;让系统可以更加松耦合。定义了一个中介者对象&#xff0c;该对象封装了一系列对象的交互&#xff0c;使得对象之间不再直接相互引用&#xff0c;而是通用这个中介者对象进行通信。 2、为…

【开源工程及源码】超级经典开源项目实景三维数字孪生智慧港口

智慧港口可视化平台&#xff0c;旨在实现对港口运营的全面监测、智能管理和优化决策。飞渡科技利用数字化、模拟和仿真的技术&#xff0c;通过互联的传感器和设备&#xff0c;实现实时数据的采集、传输和分析&#xff0c;将港口内外的复杂数据以直观、易懂的方式呈现&#xff0…

搜索二叉树(超详解)

文章目录 前言查找搜索二叉树的结构insertfinderase递归版本Findinserterase 二叉树的拷贝问题搜索二叉树的应用Key模型Key/Value的模型 前言 普通二叉树其实意义不大&#xff0c; 如果用二叉树存储数据的话&#xff0c;还不如顺序表&#xff0c;链表这些。 搜索二叉树它的意义…

核货宝订单管理系统提高企业效率

核货宝订单管理系统可以帮助企业提高效率&#xff0c;具体体现在以下几个方面&#xff1a; 一、订单自动化处理&#xff1a;核货宝订单管理系统支持订单批发和多渠道订单导入&#xff0c;它可以从订单的接收、处理、跟进、发货、到售后服务等环节都可以通过系统自动完成&#x…

DBA-MySql面试问题及答案-上

文章目录 1.什么是数据库?2.如何查看某个操作的语法?3.MySql的存储引擎有哪些?4.常用的2种存储引擎&#xff1f;6.可以针对表设置引擎吗&#xff1f;如何设置&#xff1f;6.选择合适的存储引擎&#xff1f;7.选择合适的数据类型8.char & varchar9.Mysql字符集10.如何选择…

python脚本 链接到ssh服务器 快速登录ssh服务器 ssh登录

此文分享一个python脚本,用于管理和快速链接到ssh服务器。 效果演示 🔥完整演示效果 👇第一步,显然,我们需要选择功能 👇第二步,确认 or 选择ssh服务器,根据配置文件中提供的ssh信息,有以下情况 👇场景一,只有一个候选ssh服务器,则脚本会提示用户是否确认链…

吴恩达RLHF课程笔记

1.创建偏好数据集 一个prompt输入到LLM后可以有多个回答&#xff0c;对每个回答选择偏好 比如{prompt,answer1,answer2,prefer1} 2.根据这个数据集&#xff08;偏好数据集&#xff09;&#xff0c;创建reward model&#xff0c;这个model也是一个LLM,并且它是回归模型&#…

C语言之指针

目录 函数的参数 对象和地址 取地址运算符 注意 指针 注意 指针运算符 注意 在C语言中&#xff0c;指针是一个十分重要的概念&#xff0c;它的作用是“指示对象”。 例如&#xff1a;你要去一座公寓楼找一位朋友&#xff0c;公寓楼由很多楼层组成&#xff0c;每个楼层…

解决 MATLAB 遗传算法中 exitflg=4 的问题

一、优化问题简介 以求解下述优化问题为例&#xff1a; P 1 : min ⁡ p ∑ k 1 K p k s . t . { ∑ k 1 K R k r e q l o g ( 1 α k ∗ p k ) ≤ B b s , ∀ k ∈ K p k ≥ 0 , ∀ k ∈ K \begin{align} {P_1:}&\mathop{\min}_{\bm{p}}{ \sum\limits_{k1}^K p_k } \no…

【Linux笔记】文件查看和编辑

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux学习 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 命令 cat (Concatenate and Display): more 和 less: nano 和 vim (文本编辑器): 结语 我的其他博客 前言 学习Linux命令行和文件…

1854_bash中利用管道进行批量参数传递以及由此实现简单的代码行数统计

Grey 全部学习内容汇总&#xff1a; GreyZhang/bash_basic: my learning note about bash shell. (github.com) 1854_bash中的参数传递以及利用bash进行简单的代码行数统计 有时候需要处理多个文件&#xff0c;把每一个文件作为参数传递给某一个程序。这时候可以用到 xargs&…

高频知识汇总 | 【操作系统】面试题汇总(万字长博通俗易懂)

前言 这篇我亲手整理的【操作系统】资料&#xff0c;融入了我个人的理解。当初我在研习八股文时&#xff0c;深感复习时的困扰&#xff0c;网上资料虽多&#xff0c;却过于繁杂&#xff0c;有的甚至冗余。例如&#xff0c;文件管理这部分&#xff0c;在实际面试中很少涉及&…

Ai图片处理

Ai也可以直接导入PS文件&#xff0c;只不过需要进行一个相关的选择&#xff0c;一般来说是将图层转化为对象 第二个为图层拼合为单个图像&#xff08;不常用&#xff09; 第三个则是将隐藏的图片也进行显示 如果你觉得图片的信息的过少好想插入其他的图片&#xff0c;可以选择…

认识Linux背景

1.发展史 Linux从哪里来&#xff1f;它是怎么发展的&#xff1f;在这里简要介绍Linux的发展史 要说Linux&#xff0c;还得从UNIX说起 UNIX发展的历史 1968年&#xff0c;一些来自通用电器公司、贝尔实验室和麻省理工学院的研究人员开发了一个名叫Multics的特殊操作系统。Mu…

BDD - Python Behave Tags 过滤

BDD - Python Behave Tags 过滤 引言实例创建 feature 文件创建 step 实现 Tag 过滤执行执行单个标签 --tagstagname执行多个标签 OR 关系 --tagstag1,tag2多个标签 AND 关系 --tagstag1 --tagstag2单标签非关系 --tags ~tagname 引言 随着项目进展&#xff0c;QA 创建的 Beh…

【JMeter】使用BeanShell写入内容到文件

一、前言 ​ 在我们日常工作中&#xff0c;可能会遇到需要将请求返回的数据写入到文件中。在我们使用JMeter进行性能测试时&#xff0c;就经常能够遇到这种情况。要想达到这种目的&#xff0c;我们一般采取BeanShell后置处理器来将内容写入到文件。 二、提取 ​ 在目前大多数的…

记一次 Nginx 调参的踩坑经历

最近在基于SSE&#xff08;Server Sent Events&#xff09;做服务端单向推送服务&#xff0c;本地开发时一切顺利&#xff0c;但是在部署到预发环境时就碰到1个很诡异的问题&#xff0c;这里需要简单介绍下我们的整体架构&#xff1a; 整体架构 可以看到所有的请求都会先到统一…