WPF實現(xiàn)樹形表格控件的示例代碼
前言
本文將探討如何利用WPF框架實現(xiàn)樹形表格控件,該控件不僅能夠有效地展示復雜的層級數(shù)據(jù),還能夠提供豐富的個性化定制選項。我們將介紹如何使用WPF提供的控件、模板、布局、數(shù)據(jù)綁定等技術來構建這樣一個樹形表格。
一、運行效果
1.1默認樣式
1.2 自定義樣式
二、代碼實現(xiàn)
2.1 創(chuàng)建自定義控件(TreeListView)
新建一個繼承自TreeView的控件,并定義一個類型為ViewBase的View依賴屬性,用于在代碼中指定列。
public class TreeListView : TreeView { public ViewBase View { get { return (ViewBase)GetValue(ViewProperty); } set { SetValue(ViewProperty, value); } } public static readonly DependencyProperty ViewProperty = DependencyProperty.Register("View", typeof(ViewBase), typeof(TreeListView)); }
2.2 在TreeListView控件模板中處理列頭
為了在TreeListView中顯示列頭,需要在合適的位置添加GridViewHeaderRowPresenter控件,并在Columns屬性上綁定我們之前定義的View.Columns屬性。下面我們首先來分析TreeView控件模板的代碼。
<ControlTemplate TargetType="{x:Type TreeView}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true"> <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}"> <ItemsPresenter/> </ScrollViewer> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> </Trigger> <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true"> <Setter Property="CanContentScroll" TargetName="_tv_scrollviewer_" Value="true"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
通過以上代碼我們可以看出,只要將GridViewHeaderRowPresenter控件添加到ScrollViewer控件上面即可實現(xiàn)列頭功能,但這樣會有一個問題,那就是內容寬度超出控件寬度后,鼠標拖動橫向滾動條時列頭不會跟隨下方的數(shù)據(jù)列表一起滾動。為解決這個問題我們需要將GridViewHeaderRowPresenter放置到ScrollViewer控件模板中,以下為完整代碼。
<Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="{x:Type ScrollViewer}"> <Setter Property="Focusable" Value="false" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollViewer}"> <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <DockPanel Margin="{TemplateBinding Padding}"> <ScrollViewer DockPanel.Dock="Top" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"> <GridViewHeaderRowPresenter Margin="2,0,2,0" AllowsColumnReorder="{Binding TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContainerStyle="{Binding TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContextMenu="{Binding TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderStringFormat="{Binding TemplatedParent.View.ColumnHeaderStringFormat, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplate="{Binding TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplateSelector="{Binding TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderToolTip="{Binding TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}" Columns="{Binding TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </ScrollViewer> <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" KeyboardNavigation.DirectionalNavigation="Local" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </DockPanel> <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Row="1" Cursor="Arrow" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0.0" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" /> <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="1" Cursor="Arrow" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0.0" Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" /> <DockPanel Grid.Row="1" Grid.Column="1" Background="{Binding Background, ElementName=PART_VerticalScrollBar}" LastChildFill="false"> <Rectangle Width="1" DockPanel.Dock="Left" Fill="White" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" /> <Rectangle Height="1" DockPanel.Dock="Top" Fill="White" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" /> </DockPanel> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="{x:Type local:TreeListView}"> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" /> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" /> <Setter Property="ScrollViewer.CanContentScroll" Value="true" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:TreeListView}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <ScrollViewer Padding="{TemplateBinding Padding}" Style="{StaticResource {x:Static GridView.GridViewScrollViewerStyleKey}}"> <ItemsPresenter /> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
2.3 在TreeListViewItem模板中處理子項的展開和收縮
新建一個繼承自TreeViewItem的類,命名為TreeListViewItem(如有個性化需求,可以在該類中處理),編輯控件模板,在模板中添加以下代碼。
<Style TargetType="{x:Type local:TreeListViewItem}"> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:TreeListViewItem}"> <StackPanel> <Border Name="Bd" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <GridViewRowPresenter x:Name="PART_Header" Columns="{Binding RelativeSource={RelativeSource AncestorType=local:TreeListView}, Path=View.Columns}" Content="{TemplateBinding Header}" /> </Border> <ItemsPresenter x:Name="ItemsHost" /> </StackPanel> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="false"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HasHeader" Value="false" /> <Condition Property="Width" Value="Auto" /> </MultiTrigger.Conditions> <Setter TargetName="PART_Header" Property="MinWidth" Value="75" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HasHeader" Value="false" /> <Condition Property="Height" Value="Auto" /> </MultiTrigger.Conditions> <Setter TargetName="PART_Header" Property="MinHeight" Value="19" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="extensions:TreeViewItemExtensions.IsMouseDirectlyOverItem" Value="True" /> </MultiTrigger.Conditions> <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.MouseOver.Background}" /> <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.MouseOver.Border}" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Selector.IsSelectionActive" Value="False" /> <Condition Property="IsSelected" Value="True" /> </MultiTrigger.Conditions> <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedInactive.Background}" /> <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedInactive.Border}" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Selector.IsSelectionActive" Value="True" /> <Condition Property="IsSelected" Value="True" /> </MultiTrigger.Conditions> <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedActive.Background}" /> <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedActive.Border}" /> </MultiTrigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
此處的核心在于模板中添加了GridViewRowPresenter控件,并在Columns屬性上綁定了我們之前定義的View.Columns屬性,這樣就可以在每一行上面顯示列數(shù)據(jù)。還有一個關鍵點是ItemsPresenter,它用于顯示子項數(shù)據(jù),此處命名為ItemsHost,它由屬性觸發(fā)器中的代碼來控件展開和收起。以下是屬性觸發(fā)器代碼。
<Trigger Property="IsExpanded" Value="false"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" /> </Trigger>
2.4 在單元格模板中控件子項的展開與收起
為了達到展開和收起的效果,需要在首列的單元格中控制TreeListViewItem的IsExpanded屬性。以下為完整代碼。
<DataTemplate x:Key="ExpandCellTemplate"> <DockPanel> <ToggleButton x:Name="Expander" Margin="{Binding Path=Level, Converter={StaticResource LevelIndentConverter}, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}" ClickMode="Press" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}" Style="{StaticResource ExpandCollapseToggleStyle}" /> <TextBlock Text="{Binding Property1}" /> </DockPanel> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Path=HasItems, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}" Value="False"> <Setter TargetName="Expander" Property="Visibility" Value="Hidden" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate>
其關鍵代碼為
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeListViewItem}}}"
2.5 控件使用
<TreeListView ItemsSource="{Binding Collection}"> <TreeListView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Collection, IsAsync=True}" /> </TreeListView.ItemTemplate> <TreeListView.View> <GridView> <GridViewColumn CellTemplate="{StaticResource ExpandCellTemplate}" Header="Property1" /> <GridViewColumn DisplayMemberBinding="{Binding Property2}" Header="Property2" /> <GridViewColumn DisplayMemberBinding="{Binding Property3}" Header="Property3" /> <GridViewColumn DisplayMemberBinding="{Binding Property4}" Header="Property4" /> <GridViewColumn DisplayMemberBinding="{Binding Property5}" Header="Property5" /> <GridViewColumn DisplayMemberBinding="{Binding Property6}" Header="Property6" /> <GridViewColumn DisplayMemberBinding="{Binding Property7}" Header="Property7" /> <GridViewColumn DisplayMemberBinding="{Binding Property8}" Header="Property8" /> <GridViewColumn DisplayMemberBinding="{Binding Property9}" Header="Property9" /> <GridViewColumn DisplayMemberBinding="{Binding Property10}" Header="Property10" /> <GridViewColumn DisplayMemberBinding="{Binding Property11}" Header="Property11" /> <GridViewColumn DisplayMemberBinding="{Binding Property12}" Header="Property12" /> </GridView> </TreeListView.View> </TreeListView>
以上就是WPF實現(xiàn)樹形表格控件的示例代碼的詳細內容,更多關于WPF樹形表格控件的資料請關注腳本之家其它相關文章!
相關文章
C#的靜態(tài)工廠方法與構造函數(shù)相比有哪些優(yōu)缺點
這篇文章主要介紹了C#的靜態(tài)工廠方法與構造函數(shù)對比的優(yōu)缺點,文中示例代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下2020-07-07詳解C#中通過委托來實現(xiàn)回調函數(shù)功能的方法
這篇文章主要介紹了C#中通過委托來實現(xiàn)回調函數(shù)功能的方法,文中舉了一個典型的多線程回調程序實例,需要的朋友可以參考下2016-04-04關于Unity中RectTransform與transform的區(qū)別
這篇文章主要介紹了Unity中RectTransform與transform的區(qū)別,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-01-01