(关注博主后,在“粉丝专栏”,可免费阅读此文)
wpf的功能非常强大,很多控件都是原生的,但是要使用TreeView+DataGrid的组合,就需要我们自己去封装实现。
我们需要的效果如图所示:
这2个图都是第三方控件自带的,并且都是收费使用。
现在我们就用原生的控件进行封装一个。
本文源码效果如下,(搞了好几天,的确有难度,所以源码也收费,便宜,赚点辛苦费)
功能如图所示, 目前已经实现了一部分。
首先说明一下,实现上面的效果,有3种方法
第一种:技术的选择是TreeView(也就是本文的演示)。
第二种:技术的选择是DataGrid。
第三种:技术的选择是ListView。
本文演示的是使用TreeView的实现。
1.首先建立一个wpf程序
2. 封装TreeGrid
namespace TreeView.TreeDataGrid.Controls
{
//这里有一个骚操作,就是把引用放在里面
using System;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
public class TreeGrid : TreeView
{
static TreeGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGrid), new FrameworkPropertyMetadata(typeof(TreeGrid)));
}
#region ColumnMappings DependencyProperty
public string ColumnMappings
{
get { return (string)GetValue(ColumnMappingsProperty); }
set { SetValue(ColumnMappingsProperty, value); }
}
public static readonly DependencyProperty ColumnMappingsProperty =
DependencyProperty.Register("ColumnMappings", typeof(string), typeof(TreeGrid),
new PropertyMetadata("", new PropertyChangedCallback(TreeGrid.OnColumnMappingsPropertyChanged)));
private static void OnColumnMappingsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnColumnMappingsValueChanged();
}
}
protected void OnColumnMappingsValueChanged()
{
if (!string.IsNullOrEmpty(ColumnMappings))
{
ResetMappingColumns(ColumnMappings);
}
}
private void ResetMappingColumns(string mapping)
{
GridViewColumnCollection items = new GridViewColumnCollection();
var columns = mapping.Split(new char[] { ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var c in columns)
{
var index = c.IndexOf(':');
var title = "";
var name = "";
if (index > 0)
{
title = c.Substring(0, index);
name = c.Substring(index + 1);
}
else
{
title = c;
name = c;
}
DataTemplate temp = null;
var res = this.FindTreeResource(name);
if (res != null && res is DataTemplate template)
{
temp = template;
}
else
{
temp = new DataTemplate();
FrameworkElementFactory element = null;
if (items.Count == 0)
{
element = new FrameworkElementFactory(typeof(TreeItemContentControl));
element.SetValue(ContentControl.ContentProperty, new Binding(name));
}
else
{
element = new FrameworkElementFactory(typeof(TreeGridCell));
element.SetValue(ContentControl.ContentProperty, new Binding(name));
}
temp.VisualTree = element;
}
var col = new GridViewColumn
{
Width = 200,
Header = title,
CellTemplate = temp,
};
items.Add(col);
}
Columns = items;
}
#endregion
#region Columns DependencyProperty
public GridViewColumnCollection Columns
{
get { return (GridViewColumnCollection)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeGrid),
new PropertyMetadata(null, new PropertyChangedCallback(TreeGrid.OnColumnsPropertyChanged)));
private static void OnColumnsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnColumnsValueChanged();
}
}
protected void OnColumnsValueChanged()
{
}
#endregion
#region RowHeight DependencyProperty
public double RowHeight
{
get { return (double)GetValue(RowHeightProperty); }
set { SetValue(RowHeightProperty, value); }
}
public static readonly DependencyProperty RowHeightProperty =
DependencyProperty.Register("RowHeight", typeof(double), typeof(TreeGrid),
new PropertyMetadata(30.0, new PropertyChangedCallback(TreeGrid.OnRowHeightPropertyChanged)));
private static void OnRowHeightPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnRowHeightValueChanged();
}
}
protected void OnRowHeightValueChanged()
{
}
#endregion
#region ShowCellBorder DependencyProperty
public bool ShowCellBorder
{
get { return (bool)GetValue(ShowCellBorderProperty); }
set { SetValue(ShowCellBorderProperty, value); }
}
public static readonly DependencyProperty ShowCellBorderProperty =
DependencyProperty.Register("ShowCellBorder", typeof(bool), typeof(TreeGrid),
new PropertyMetadata(false, new PropertyChangedCallback(TreeGrid.OnShowCellBorderPropertyChanged)));
private static void OnShowCellBorderPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnShowCellBorderValueChanged();
}
}
protected void OnShowCellBorderValueChanged()
{
}
#endregion
#region IconStroke DependencyProperty
public Brush IconStroke
{
get { return (Brush)GetValue(IconStrokeProperty); }
set { SetValue(IconStrokeProperty, value); }
}
public static readonly DependencyProperty IconStrokeProperty =
DependencyProperty.Register("IconStroke", typeof(Brush), typeof(TreeGrid),
new PropertyMetadata(new SolidColorBrush(Colors.LightGray), new PropertyChangedCallback(TreeGrid.OnIconStrokePropertyChanged)));
private static void OnIconStrokePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnIconStrokeValueChanged();
}
}
protected void OnIconStrokeValueChanged()
{
}
#endregion
#region CellBorderBrush DependencyProperty
public Brush CellBorderBrush
{
get { return (Brush)GetValue(CellBorderBrushProperty); }
set { SetValue(CellBorderBrushProperty, value); }
}
public static readonly DependencyProperty CellBorderBrushProperty =
DependencyProperty.Register("CellBorderBrush", typeof(Brush), typeof(TreeGrid),
new PropertyMetadata(new SolidColorBrush(Colors.LightGray), new PropertyChangedCallback(TreeGrid.OnCellBorderBrushPropertyChanged)));
private static void OnCellBorderBrushPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is TreeGrid)
{
(obj as TreeGrid).OnCellBorderBrushValueChanged();
}
}
protected void OnCellBorderBrushValueChanged()
{
}
#endregion
protected override DependencyObject GetContainerForItemOverride()
{
return new TreeGridItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is TreeGridItem;
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
}
}
public class TreeGridItem : TreeViewItem
{
public event EventHandler IconStateChanged;
static TreeGridItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGridItem), new FrameworkPropertyMetadata(typeof(TreeGridItem)));
}
public TreeGridItem()
{
this.DataContextChanged += TreeGridItem_DataContextChanged;
}
private void TreeGridItem_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (DataContext != null && DataContext is TreeItemData treeData)
{
this.SetBinding(IsExpandedProperty, new Binding("IsExpanded") { Source = treeData, Mode = BindingMode.TwoWay });
}
}
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
}
protected override DependencyObject GetContainerForItemOverride()
{
return new TreeGridItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is TreeGridItem;
}
}
/*
* https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/GridViewRowPresenter.cs,ace7d38fc902993d
* GridViewRow里的每个元素,增加了一个默认的Margin,这样在设置边框的时候会比较麻烦,在运行时去掉
*/
public class TreeGridCell : ContentControl
{
static TreeGridCell()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGridCell), new FrameworkPropertyMetadata(typeof(TreeGridCell)));
}
public TreeGridCell()
{
Loaded += TreeGridCell_Loaded;
}
private void TreeGridCell_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= TreeGridCell_Loaded;
var p = VisualTreeHelper.GetParent(this);
if (p != null && p is FrameworkElement f && f.Margin.Left > 0)
{
f.Margin = new Thickness(0);
}
}
}
public static class TreeHelper
{
public static T FindParent(this DependencyObject obj)
{
var p = VisualTreeHelper.GetParent(obj);
if (p == null)
{
return default(T);
}
if (p is T tt)
{
return tt;
}
return FindParent(p);
}
public static T FindTreeResource(this FrameworkElement obj, string key)
{
if (obj == null)
{
return default(T);
}
var r = obj.TryFindResource(key);
if (r == null)
{
r = Application.Current.TryFindResource(key);
}
if (r != null && r is T t)
{
return t;
}
var p = FindParent(obj);
if (p != null)
{
return FindTreeResource(p, key);
}
return default(T);
}
}
}
3.TreeGrid.xaml
4.代码很多,最终的源码格式
需要源码请联系我。
本文来源:
WPF组合控件TreeView+DataGrid之TreeView封装-CSDN博客