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

发布时间:2023年12月23日

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

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博客

文章来源:https://blog.csdn.net/u012563853/article/details/135173736
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。