经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
WPF实现树形表格控件(TreeListView)
来源:cnblogs  作者:趋时软件  时间:2024/4/3 9:24:20  对本文有异议

前言

  本文将探讨如何利用WPF框架实现树形表格控件,该控件不仅能够有效地展示复杂的层级数据,还能够提供丰富的个性化定制选项。我们将介绍如何使用WPF提供的控件、模板、布局、数据绑定等技术来构建这样一个树形表格。

一、运行效果

1.1默认样式

1.2 自定义样式

二、代码实现

2.1 创建自定义控件(TreeListView)

      新建一个继承自TreeView的控件,并定义一个类型为ViewBase的View依赖属性,用于在代码中指定列。

  1. public class TreeListView : TreeView
  2. {
  3. public ViewBase View
  4. {
  5. get { return (ViewBase)GetValue(ViewProperty); }
  6. set { SetValue(ViewProperty, value); }
  7. }
  8. public static readonly DependencyProperty ViewProperty =
  9. DependencyProperty.Register("View", typeof(ViewBase), typeof(TreeListView));
  10. }

2.2 在TreeListView控件模板中处理列头

   为了在TreeListView中显示列头,需要在合适的位置添加GridViewHeaderRowPresenter控件,并在Columns属性上绑定我们之前定义的View.Columns属性。下面我们首先来分析TreeView控件模板的代码。

  1. <ControlTemplate TargetType="{x:Type TreeView}">
  2. <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
  3. <ScrollViewer x:Name="_tv_scrollviewer_" Background="{TemplateBinding Background}" CanContentScroll="false" Focusable="false" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
  4. <ItemsPresenter/>
  5. </ScrollViewer>
  6. </Border>
  7. <ControlTemplate.Triggers>
  8. <Trigger Property="IsEnabled" Value="false">
  9. <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
  10. </Trigger>
  11. <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
  12. <Setter Property="CanContentScroll" TargetName="_tv_scrollviewer_" Value="true"/>
  13. </Trigger>
  14. </ControlTemplate.Triggers>
  15. </ControlTemplate>

      通过以上代码我们可以看出,只要将GridViewHeaderRowPresenter控件添加到ScrollViewer控件上面即可实现列头功能,但这样会有一个问题,那就是内容宽度超出控件宽度后,鼠标拖动横向滚动条时列头不会跟随下方的数据列表一起滚动。为解决这个问题我们需要将GridViewHeaderRowPresenter放置到ScrollViewer控件模板中,以下为完整代码。

  1. <Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="{x:Type ScrollViewer}">
  2. <Setter Property="Focusable" Value="false" />
  3. <Setter Property="Template">
  4. <Setter.Value>
  5. <ControlTemplate TargetType="{x:Type ScrollViewer}">
  6. <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
  7. <Grid.ColumnDefinitions>
  8. <ColumnDefinition Width="*" />
  9. <ColumnDefinition Width="Auto" />
  10. </Grid.ColumnDefinitions>
  11. <Grid.RowDefinitions>
  12. <RowDefinition Height="*" />
  13. <RowDefinition Height="Auto" />
  14. </Grid.RowDefinitions>
  15.  
  16. <DockPanel Margin="{TemplateBinding Padding}">
  17. <ScrollViewer
  18. DockPanel.Dock="Top"
  19. Focusable="false"
  20. HorizontalScrollBarVisibility="Hidden"
  21. VerticalScrollBarVisibility="Hidden">
  22. <GridViewHeaderRowPresenter
  23. Margin="2,0,2,0"
  24. AllowsColumnReorder="{Binding TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}"
  25. ColumnHeaderContainerStyle="{Binding TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}"
  26. ColumnHeaderContextMenu="{Binding TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}"
  27. ColumnHeaderStringFormat="{Binding TemplatedParent.View.ColumnHeaderStringFormat, RelativeSource={RelativeSource TemplatedParent}}"
  28. ColumnHeaderTemplate="{Binding TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}"
  29. ColumnHeaderTemplateSelector="{Binding TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}"
  30. ColumnHeaderToolTip="{Binding TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}"
  31. Columns="{Binding TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"
  32. SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
  33. </ScrollViewer>
  34. <ScrollContentPresenter
  35. x:Name="PART_ScrollContentPresenter"
  36. CanContentScroll="{TemplateBinding CanContentScroll}"
  37. Content="{TemplateBinding Content}"
  38. ContentTemplate="{TemplateBinding ContentTemplate}"
  39. KeyboardNavigation.DirectionalNavigation="Local"
  40. SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
  41. </DockPanel>
  42.  
  43. <ScrollBar
  44. x:Name="PART_HorizontalScrollBar"
  45. Grid.Row="1"
  46. Cursor="Arrow"
  47. Maximum="{TemplateBinding ScrollableWidth}"
  48. Minimum="0.0"
  49. Orientation="Horizontal"
  50. ViewportSize="{TemplateBinding ViewportWidth}"
  51. Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
  52. Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
  53. <ScrollBar
  54. x:Name="PART_VerticalScrollBar"
  55. Grid.Column="1"
  56. Cursor="Arrow"
  57. Maximum="{TemplateBinding ScrollableHeight}"
  58. Minimum="0.0"
  59. Orientation="Vertical"
  60. ViewportSize="{TemplateBinding ViewportHeight}"
  61. Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
  62. Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
  63. <DockPanel
  64. Grid.Row="1"
  65. Grid.Column="1"
  66. Background="{Binding Background, ElementName=PART_VerticalScrollBar}"
  67. LastChildFill="false">
  68. <Rectangle
  69. Width="1"
  70. DockPanel.Dock="Left"
  71. Fill="White"
  72. Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
  73. <Rectangle
  74. Height="1"
  75. DockPanel.Dock="Top"
  76. Fill="White"
  77. Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
  78. </DockPanel>
  79. </Grid>
  80. </ControlTemplate>
  81. </Setter.Value>
  82. </Setter>
  83. </Style>
  84.  
  85. <Style TargetType="{x:Type local:TreeListView}">
  86. <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
  87. <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
  88. <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
  89. <Setter Property="Template">
  90. <Setter.Value>
  91. <ControlTemplate TargetType="{x:Type local:TreeListView}">
  92. <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
  93. <ScrollViewer Padding="{TemplateBinding Padding}" Style="{StaticResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
  94. <ItemsPresenter />
  95. </ScrollViewer>
  96. </Border>
  97. </ControlTemplate>
  98. </Setter.Value>
  99. </Setter>
  100. </Style>

2.3 在TreeListViewItem模板中处理子项的展开和收缩

      新建一个继承自TreeViewItem的类,命名为TreeListViewItem(如有个性化需求,可以在该类中处理),编辑控件模板,在模板中添加以下代码。

  1. <Style TargetType="{x:Type local:TreeListViewItem}">
  2. <Setter Property="BorderThickness" Value="1" />
  3. <Setter Property="Template">
  4. <Setter.Value>
  5. <ControlTemplate TargetType="{x:Type local:TreeListViewItem}">
  6. <StackPanel>
  7. <Border
  8. Name="Bd"
  9. Padding="{TemplateBinding Padding}"
  10. Background="{TemplateBinding Background}"
  11. BorderBrush="{TemplateBinding BorderBrush}"
  12. BorderThickness="{TemplateBinding BorderThickness}">
  13. <GridViewRowPresenter
  14. x:Name="PART_Header"
  15. Columns="{Binding RelativeSource={RelativeSource AncestorType=local:TreeListView}, Path=View.Columns}"
  16. Content="{TemplateBinding Header}" />
  17. </Border>
  18. <ItemsPresenter x:Name="ItemsHost" />
  19. </StackPanel>
  20. <ControlTemplate.Triggers>
  21. <Trigger Property="IsExpanded" Value="false">
  22. <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
  23. </Trigger>
  24. <MultiTrigger>
  25. <MultiTrigger.Conditions>
  26. <Condition Property="HasHeader" Value="false" />
  27. <Condition Property="Width" Value="Auto" />
  28. </MultiTrigger.Conditions>
  29. <Setter TargetName="PART_Header" Property="MinWidth" Value="75" />
  30. </MultiTrigger>
  31. <MultiTrigger>
  32. <MultiTrigger.Conditions>
  33. <Condition Property="HasHeader" Value="false" />
  34. <Condition Property="Height" Value="Auto" />
  35. </MultiTrigger.Conditions>
  36. <Setter TargetName="PART_Header" Property="MinHeight" Value="19" />
  37. </MultiTrigger>
  38.  
  39. <MultiTrigger>
  40. <MultiTrigger.Conditions>
  41. <Condition Property="extensions:TreeViewItemExtensions.IsMouseDirectlyOverItem" Value="True" />
  42. </MultiTrigger.Conditions>
  43. <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.MouseOver.Background}" />
  44. <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.MouseOver.Border}" />
  45. </MultiTrigger>
  46. <MultiTrigger>
  47. <MultiTrigger.Conditions>
  48. <Condition Property="Selector.IsSelectionActive" Value="False" />
  49. <Condition Property="IsSelected" Value="True" />
  50. </MultiTrigger.Conditions>
  51. <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedInactive.Background}" />
  52. <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedInactive.Border}" />
  53. </MultiTrigger>
  54. <MultiTrigger>
  55. <MultiTrigger.Conditions>
  56. <Condition Property="Selector.IsSelectionActive" Value="True" />
  57. <Condition Property="IsSelected" Value="True" />
  58. </MultiTrigger.Conditions>
  59. <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedActive.Background}" />
  60. <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedActive.Border}" />
  61. </MultiTrigger>
  62. <Trigger Property="IsEnabled" Value="False">
  63. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
  64. </Trigger>
  65. </ControlTemplate.Triggers>
  66. </ControlTemplate>
  67. </Setter.Value>
  68. </Setter>
  69. </Style>

    此处的核心在于模板中添加了GridViewRowPresenter控件,并在Columns属性上绑定了我们之前定义的View.Columns属性,这样就可以在每一行上面显示列数据。还有一个关键点是ItemsPresenter,它用于显示子项数据,此处命名为ItemsHost,它由属性触发器中的代码来控件展开和收起。以下是属性触发器代码。

  1. <Trigger Property="IsExpanded" Value="false">
  2. <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
  3. </Trigger>

2.4 在单元格模板中控件子项的展开与收起

   为了达到展开和收起的效果,需要在首列的单元格中控制TreeListViewItem的IsExpanded属性。以下为完整代码。

  1. <DataTemplate x:Key="ExpandCellTemplate">
  2. <DockPanel>
  3. <ToggleButton
  4. x:Name="Expander"
  5. Margin="{Binding Path=Level, Converter={StaticResource LevelIndentConverter}, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}"
  6. ClickMode="Press"
  7. IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}"
  8. Style="{StaticResource ExpandCollapseToggleStyle}" />
  9. <TextBlock Text="{Binding Property1}" />
  10. </DockPanel>
  11. <DataTemplate.Triggers>
  12. <DataTrigger Binding="{Binding Path=HasItems, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}" Value="False">
  13. <Setter TargetName="Expander" Property="Visibility" Value="Hidden" />
  14. </DataTrigger>
  15. </DataTemplate.Triggers>
  16. </DataTemplate>

其关键代码为

  1. IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}"

2.5 控件使用

  1. <TreeListView ItemsSource="{Binding Collection}">
  2. <TreeListView.ItemTemplate>
  3. <HierarchicalDataTemplate ItemsSource="{Binding Collection, IsAsync=True}" />
  4. </TreeListView.ItemTemplate>
  5. <TreeListView.View>
  6. <GridView>
  7. <GridViewColumn CellTemplate="{StaticResource ExpandCellTemplate}" Header="Property1" />
  8. <GridViewColumn DisplayMemberBinding="{Binding Property2}" Header="Property2" />
  9. <GridViewColumn DisplayMemberBinding="{Binding Property3}" Header="Property3" />
  10. <GridViewColumn DisplayMemberBinding="{Binding Property4}" Header="Property4" />
  11. <GridViewColumn DisplayMemberBinding="{Binding Property5}" Header="Property5" />
  12. <GridViewColumn DisplayMemberBinding="{Binding Property6}" Header="Property6" />
  13. <GridViewColumn DisplayMemberBinding="{Binding Property7}" Header="Property7" />
  14. <GridViewColumn DisplayMemberBinding="{Binding Property8}" Header="Property8" />
  15. <GridViewColumn DisplayMemberBinding="{Binding Property9}" Header="Property9" />
  16. <GridViewColumn DisplayMemberBinding="{Binding Property10}" Header="Property10" />
  17. <GridViewColumn DisplayMemberBinding="{Binding Property11}" Header="Property11" />
  18. <GridViewColumn DisplayMemberBinding="{Binding Property12}" Header="Property12" />
  19. </GridView>
  20. </TreeListView.View>
  21. </TreeListView>

 

 技术交流群
 
 联系方式

原文链接:https://www.cnblogs.com/qushi2020/p/18109923

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号