(关注博主后,在“粉丝专栏”,可免费阅读此文)
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博客