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;elsereturn null;}}#endregionpublic 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++;elsestart++;Rows.RemoveRange(start, count);}}private IEnumerable GetChildren(TreeNode parent){if (Model != null)return Model.GetChildren(parent.Tag);elsereturn null;}private bool HasChildren(TreeNode parent){if (parent == Root)return true;else if (Model != null)return Model.HasChildren(parent.Tag);elsereturn 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博客