当前位置:   article > 正文

WPF中使用TreeView封装组合控件TreeView+DataGrid-粉丝专栏_wpf treegrid

wpf treegrid

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

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

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

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

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

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

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

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

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

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

第三种:技术的选择是ListView。

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

本文演示的是使用TreeView的实现。

1.首先建立一个wpf程序

2. 封装TreeGrid

  1. namespace TreeView.TreeDataGrid.Controls
  2. {
  3. //这里有一个骚操作,就是把引用放在里面
  4. using System;
  5. using System.Collections.Specialized;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Media;
  10. public class TreeGrid : TreeView
  11. {
  12. static TreeGrid()
  13. {
  14. DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGrid), new FrameworkPropertyMetadata(typeof(TreeGrid)));
  15. }
  16. #region ColumnMappings DependencyProperty
  17. public string ColumnMappings
  18. {
  19. get { return (string)GetValue(ColumnMappingsProperty); }
  20. set { SetValue(ColumnMappingsProperty, value); }
  21. }
  22. public static readonly DependencyProperty ColumnMappingsProperty =
  23. DependencyProperty.Register("ColumnMappings", typeof(string), typeof(TreeGrid),
  24. new PropertyMetadata("", new PropertyChangedCallback(TreeGrid.OnColumnMappingsPropertyChanged)));
  25. private static void OnColumnMappingsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  26. {
  27. if (obj is TreeGrid)
  28. {
  29. (obj as TreeGrid).OnColumnMappingsValueChanged();
  30. }
  31. }
  32. protected void OnColumnMappingsValueChanged()
  33. {
  34. if (!string.IsNullOrEmpty(ColumnMappings))
  35. {
  36. ResetMappingColumns(ColumnMappings);
  37. }
  38. }
  39. private void ResetMappingColumns(string mapping)
  40. {
  41. GridViewColumnCollection items = new GridViewColumnCollection();
  42. var columns = mapping.Split(new char[] { ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
  43. foreach (var c in columns)
  44. {
  45. var index = c.IndexOf(':');
  46. var title = "";
  47. var name = "";
  48. if (index > 0)
  49. {
  50. title = c.Substring(0, index);
  51. name = c.Substring(index + 1);
  52. }
  53. else
  54. {
  55. title = c;
  56. name = c;
  57. }
  58. DataTemplate temp = null;
  59. var res = this.FindTreeResource<DataTemplate>(name);
  60. if (res != null && res is DataTemplate template)
  61. {
  62. temp = template;
  63. }
  64. else
  65. {
  66. temp = new DataTemplate();
  67. FrameworkElementFactory element = null;
  68. if (items.Count == 0)
  69. {
  70. element = new FrameworkElementFactory(typeof(TreeItemContentControl));
  71. element.SetValue(ContentControl.ContentProperty, new Binding(name));
  72. }
  73. else
  74. {
  75. element = new FrameworkElementFactory(typeof(TreeGridCell));
  76. element.SetValue(ContentControl.ContentProperty, new Binding(name));
  77. }
  78. temp.VisualTree = element;
  79. }
  80. var col = new GridViewColumn
  81. {
  82. Width = 200,
  83. Header = title,
  84. CellTemplate = temp,
  85. };
  86. items.Add(col);
  87. }
  88. Columns = items;
  89. }
  90. #endregion
  91. #region Columns DependencyProperty
  92. public GridViewColumnCollection Columns
  93. {
  94. get { return (GridViewColumnCollection)GetValue(ColumnsProperty); }
  95. set { SetValue(ColumnsProperty, value); }
  96. }
  97. public static readonly DependencyProperty ColumnsProperty =
  98. DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeGrid),
  99. new PropertyMetadata(null, new PropertyChangedCallback(TreeGrid.OnColumnsPropertyChanged)));
  100. private static void OnColumnsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  101. {
  102. if (obj is TreeGrid)
  103. {
  104. (obj as TreeGrid).OnColumnsValueChanged();
  105. }
  106. }
  107. protected void OnColumnsValueChanged()
  108. {
  109. }
  110. #endregion
  111. #region RowHeight DependencyProperty
  112. public double RowHeight
  113. {
  114. get { return (double)GetValue(RowHeightProperty); }
  115. set { SetValue(RowHeightProperty, value); }
  116. }
  117. public static readonly DependencyProperty RowHeightProperty =
  118. DependencyProperty.Register("RowHeight", typeof(double), typeof(TreeGrid),
  119. new PropertyMetadata(30.0, new PropertyChangedCallback(TreeGrid.OnRowHeightPropertyChanged)));
  120. private static void OnRowHeightPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  121. {
  122. if (obj is TreeGrid)
  123. {
  124. (obj as TreeGrid).OnRowHeightValueChanged();
  125. }
  126. }
  127. protected void OnRowHeightValueChanged()
  128. {
  129. }
  130. #endregion
  131. #region ShowCellBorder DependencyProperty
  132. public bool ShowCellBorder
  133. {
  134. get { return (bool)GetValue(ShowCellBorderProperty); }
  135. set { SetValue(ShowCellBorderProperty, value); }
  136. }
  137. public static readonly DependencyProperty ShowCellBorderProperty =
  138. DependencyProperty.Register("ShowCellBorder", typeof(bool), typeof(TreeGrid),
  139. new PropertyMetadata(false, new PropertyChangedCallback(TreeGrid.OnShowCellBorderPropertyChanged)));
  140. private static void OnShowCellBorderPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  141. {
  142. if (obj is TreeGrid)
  143. {
  144. (obj as TreeGrid).OnShowCellBorderValueChanged();
  145. }
  146. }
  147. protected void OnShowCellBorderValueChanged()
  148. {
  149. }
  150. #endregion
  151. #region IconStroke DependencyProperty
  152. public Brush IconStroke
  153. {
  154. get { return (Brush)GetValue(IconStrokeProperty); }
  155. set { SetValue(IconStrokeProperty, value); }
  156. }
  157. public static readonly DependencyProperty IconStrokeProperty =
  158. DependencyProperty.Register("IconStroke", typeof(Brush), typeof(TreeGrid),
  159. new PropertyMetadata(new SolidColorBrush(Colors.LightGray), new PropertyChangedCallback(TreeGrid.OnIconStrokePropertyChanged)));
  160. private static void OnIconStrokePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  161. {
  162. if (obj is TreeGrid)
  163. {
  164. (obj as TreeGrid).OnIconStrokeValueChanged();
  165. }
  166. }
  167. protected void OnIconStrokeValueChanged()
  168. {
  169. }
  170. #endregion
  171. #region CellBorderBrush DependencyProperty
  172. public Brush CellBorderBrush
  173. {
  174. get { return (Brush)GetValue(CellBorderBrushProperty); }
  175. set { SetValue(CellBorderBrushProperty, value); }
  176. }
  177. public static readonly DependencyProperty CellBorderBrushProperty =
  178. DependencyProperty.Register("CellBorderBrush", typeof(Brush), typeof(TreeGrid),
  179. new PropertyMetadata(new SolidColorBrush(Colors.LightGray), new PropertyChangedCallback(TreeGrid.OnCellBorderBrushPropertyChanged)));
  180. private static void OnCellBorderBrushPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  181. {
  182. if (obj is TreeGrid)
  183. {
  184. (obj as TreeGrid).OnCellBorderBrushValueChanged();
  185. }
  186. }
  187. protected void OnCellBorderBrushValueChanged()
  188. {
  189. }
  190. #endregion
  191. protected override DependencyObject GetContainerForItemOverride()
  192. {
  193. return new TreeGridItem();
  194. }
  195. protected override bool IsItemItsOwnContainerOverride(object item)
  196. {
  197. return item is TreeGridItem;
  198. }
  199. protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
  200. {
  201. base.OnItemsChanged(e);
  202. }
  203. }
  204. public class TreeGridItem : TreeViewItem
  205. {
  206. public event EventHandler IconStateChanged;
  207. static TreeGridItem()
  208. {
  209. DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGridItem), new FrameworkPropertyMetadata(typeof(TreeGridItem)));
  210. }
  211. public TreeGridItem()
  212. {
  213. this.DataContextChanged += TreeGridItem_DataContextChanged;
  214. }
  215. private void TreeGridItem_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
  216. {
  217. if (DataContext != null && DataContext is TreeItemData treeData)
  218. {
  219. this.SetBinding(IsExpandedProperty, new Binding("IsExpanded") { Source = treeData, Mode = BindingMode.TwoWay });
  220. }
  221. }
  222. protected override void OnVisualParentChanged(DependencyObject oldParent)
  223. {
  224. base.OnVisualParentChanged(oldParent);
  225. }
  226. protected override DependencyObject GetContainerForItemOverride()
  227. {
  228. return new TreeGridItem();
  229. }
  230. protected override bool IsItemItsOwnContainerOverride(object item)
  231. {
  232. return item is TreeGridItem;
  233. }
  234. }
  235. /*
  236. * https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/GridViewRowPresenter.cs,ace7d38fc902993d
  237. * GridViewRow里的每个元素,增加了一个默认的Margin,这样在设置边框的时候会比较麻烦,在运行时去掉
  238. */
  239. public class TreeGridCell : ContentControl
  240. {
  241. static TreeGridCell()
  242. {
  243. DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGridCell), new FrameworkPropertyMetadata(typeof(TreeGridCell)));
  244. }
  245. public TreeGridCell()
  246. {
  247. Loaded += TreeGridCell_Loaded;
  248. }
  249. private void TreeGridCell_Loaded(object sender, RoutedEventArgs e)
  250. {
  251. Loaded -= TreeGridCell_Loaded;
  252. var p = VisualTreeHelper.GetParent(this);
  253. if (p != null && p is FrameworkElement f && f.Margin.Left > 0)
  254. {
  255. f.Margin = new Thickness(0);
  256. }
  257. }
  258. }
  259. public static class TreeHelper
  260. {
  261. public static T FindParent<T>(this DependencyObject obj)
  262. {
  263. var p = VisualTreeHelper.GetParent(obj);
  264. if (p == null)
  265. {
  266. return default(T);
  267. }
  268. if (p is T tt)
  269. {
  270. return tt;
  271. }
  272. return FindParent<T>(p);
  273. }
  274. public static T FindTreeResource<T>(this FrameworkElement obj, string key)
  275. {
  276. if (obj == null)
  277. {
  278. return default(T);
  279. }
  280. var r = obj.TryFindResource(key);
  281. if (r == null)
  282. {
  283. r = Application.Current.TryFindResource(key);
  284. }
  285. if (r != null && r is T t)
  286. {
  287. return t;
  288. }
  289. var p = FindParent<FrameworkElement>(obj);
  290. if (p != null)
  291. {
  292. return FindTreeResource<T>(p, key);
  293. }
  294. return default(T);
  295. }
  296. }
  297. }

3.TreeGrid.xaml

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  3. xmlns:local="clr-namespace:TreeView.TreeDataGrid.Controls"
  4. >
  5. <SolidColorBrush x:Key="TreeIconStroke" Color="GreenYellow" />
  6. <Style x:Key="TreeGridItemStyle" TargetType="{x:Type local:TreeGridItem}">
  7. <Setter Property="Foreground" Value="Black"/>
  8. <Setter Property="Background" Value="Transparent"/>
  9. <Setter Property="IsExpanded" Value="True"/>
  10. <Setter Property="BorderBrush" Value="Wheat"/>
  11. <Setter Property="BorderThickness" Value="0,0,0,1"/>
  12. <Setter Property="Template">
  13. <Setter.Value>
  14. <ControlTemplate TargetType="{x:Type local:TreeGridItem}">
  15. <StackPanel>
  16. <Border Name="Bd"
  17. Background="Transparent"
  18. BorderBrush="{TemplateBinding BorderBrush}"
  19. Padding="{TemplateBinding Padding}">
  20. <GridViewRowPresenter x:Name="PART_Header"
  21. Content="{TemplateBinding Header}"
  22. Columns="{Binding Path=Columns,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:TreeGrid}}" />
  23. </Border>
  24. <ItemsPresenter x:Name="ItemsHost" />
  25. </StackPanel>
  26. <ControlTemplate.Triggers>
  27. <Trigger Property="IsExpanded" Value="false">
  28. <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
  29. </Trigger>
  30. <MultiTrigger>
  31. <MultiTrigger.Conditions>
  32. <Condition Property="HasHeader" Value="false"/>
  33. <Condition Property="Width" Value="Auto"/>
  34. </MultiTrigger.Conditions>
  35. <Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
  36. </MultiTrigger>
  37. <MultiTrigger>
  38. <MultiTrigger.Conditions>
  39. <Condition Property="HasHeader" Value="false"/>
  40. <Condition Property="Height" Value="Auto"/>
  41. </MultiTrigger.Conditions>
  42. <Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
  43. </MultiTrigger>
  44. <MultiTrigger>
  45. <!--移动变色-->
  46. <MultiTrigger.Conditions>
  47. <Condition Property="IsFocused" Value="False"/>
  48. <Condition SourceName="Bd" Property="IsMouseOver" Value="true"/>
  49. </MultiTrigger.Conditions>
  50. <Setter Property="Background" Value=" red" TargetName="Bd"/>
  51. </MultiTrigger>
  52. <Trigger Property="IsSelected" Value="true">
  53. <!--选中的背景颜色-->
  54. <Setter TargetName="Bd" Property="Background" Value="YellowGreen"/>
  55. <!--<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>-->
  56. <Setter Property="Foreground" Value="Red"/>
  57. </Trigger>
  58. <!--隔行换色-->
  59. <!--<Trigger Property="AlternationIndex" Value="0" >
  60. <Setter TargetName="Bd" Property="Background" Value="blue" />
  61. </Trigger>
  62. <Trigger Property="AlternationIndex" Value="2" >
  63. <Setter TargetName="Bd" Property="Background" Value="black" />
  64. </Trigger>-->
  65. <!--<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:TreeGrid}, Path=Columns.Count }" Value="0">
  66. <Setter TargetName="Bd" Property="Background" Value="#FFD3D3D3"/>
  67. </DataTrigger>
  68. <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:TreeGrid}, Path=Columns.Count}" Value="2">
  69. <Setter TargetName="Bd" Property="Background" Value="#FFE6E6E6"/>
  70. </DataTrigger>-->
  71. <MultiTrigger>
  72. <MultiTrigger.Conditions>
  73. <Condition Property="IsSelected" Value="true"/>
  74. <Condition Property="IsSelectionActive" Value="false"/>
  75. </MultiTrigger.Conditions>
  76. <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
  77. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
  78. </MultiTrigger>
  79. <Trigger Property="IsEnabled" Value="false">
  80. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
  81. </Trigger>
  82. </ControlTemplate.Triggers>
  83. </ControlTemplate>
  84. </Setter.Value>
  85. </Setter>
  86. <Style.Triggers>
  87. <!--隔行换色-->
  88. <Trigger Property="AlternationIndex" Value="0" >
  89. <Setter Property="Background" Value="#e7e7e7" />
  90. </Trigger>
  91. <Trigger Property="AlternationIndex" Value="1" >
  92. <Setter Property="Background" Value="#f2f2f2" />
  93. </Trigger>
  94. </Style.Triggers>
  95. </Style>
  96. <Style TargetType="{x:Type local:TreeGridItem}" BasedOn="{StaticResource TreeGridItemStyle}"/>
  97. <Style TargetType="{x:Type local:TreeGridCell}">
  98. <Setter Property="HorizontalContentAlignment" Value="Center"/>
  99. <Setter Property="VerticalContentAlignment" Value="Center"/>
  100. <Setter Property="BorderBrush" Value="Red"/>
  101. <Setter Property="Template">
  102. <Setter.Value>
  103. <ControlTemplate TargetType="{x:Type local:TreeGridCell}">
  104. <Border x:Name="CellBorder"
  105. Margin="0,0,-0.5,0"
  106. Background="{TemplateBinding Background}"
  107. BorderBrush="Red"
  108. BorderThickness="0,0,0,1">
  109. <ContentControl Content="{TemplateBinding Content}"
  110. ContentTemplate="{TemplateBinding ContentTemplate}"
  111. HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  112. VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
  113. SnapsToDevicePixels="True"/>
  114. </Border>
  115. <!--BorderBrush="Red"下划线颜色-->
  116. <!--<ControlTemplate.Triggers>
  117. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:TreeGrid},Path=ShowCellBorder}" Value="true">
  118. <Setter TargetName="CellBorder" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:TreeGrid},Path=CellBorderBrush}" />
  119. </DataTrigger>
  120. </ControlTemplate.Triggers>-->
  121. </ControlTemplate>
  122. </Setter.Value>
  123. </Setter>
  124. </Style>
  125. <Style TargetType="{x:Type local:TreeGrid}">
  126. <Setter Property="IconStroke" Value="{StaticResource TreeIconStroke}"/>
  127. <Setter Property="ItemContainerStyle" Value="{StaticResource {x:Type local:TreeGridItem}}"/>
  128. <Setter Property="Template">
  129. <Setter.Value>
  130. <ControlTemplate TargetType="{x:Type local:TreeGrid}">
  131. <Border Background="{TemplateBinding Background}"
  132. BorderBrush="{TemplateBinding BorderBrush}"
  133. BorderThickness="0">
  134. <!--最大边框-->
  135. <DockPanel>
  136. <!--标题栏-->
  137. <GridViewHeaderRowPresenter IsHitTestVisible="False" Columns="{TemplateBinding Columns}" Height="{TemplateBinding RowHeight}" DockPanel.Dock="Top" >
  138. </GridViewHeaderRowPresenter>
  139. <ItemsPresenter />
  140. </DockPanel>
  141. </Border>
  142. </ControlTemplate>
  143. </Setter.Value>
  144. </Setter>
  145. </Style>
  146. </ResourceDictionary>

4.代码很多,最终的源码格式

 源码地址:

https://download.csdn.net/download/u012563853/89003286

本文来源:

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

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读