WPF自定义虚线树形控件
项目领导要求来一个带虚线的树形控件,说这个东西好看,但WPF没有这种虚线型树控件。首先想到是从网上找个现成的,但在网上查了半于,都不如意,没办法,自己写,开干。
项目中有Tree控件Style,直接从上面入手改动,关键在于垂直虚线如何跨多个子结点,而且在最后一个结点处,不能划满格竖线。
经过几轮反复,完成成品样式如下:
主要代码如下:
<Grid x:Name="gridRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!---画竖线-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle x:Name="VerLn1" Width="1" Stroke="#8888" Margin="10,0,0,0"
SnapsToDevicePixels="true" StrokeDashArray="2" StrokeThickness="1" />
</Grid>
<Grid Grid.Row="1">
<Rectangle x:Name="VerLn2" Width="1" Stroke="#8888" Margin="10,0,0,0"
SnapsToDevicePixels="true" StrokeDashArray="2" StrokeThickness="1" />
</Grid>
<!---展开按钮-->
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="HorLn" Height="1" Stroke="#8888" Margin="0,0,0,0"
SnapsToDevicePixels="true" StrokeDashArray="2" StrokeThickness="1"
/>
<ToggleButton x:Name="Expander" ClickMode="Press" Margin="0,0,0,0" Grid.Column="1"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" >
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="Transparent" Height="16" Padding="5" Width="16">
<Path x:Name="ExpandPath" Data="M0,0 L0,6 L6,0 z" Fill="White" Stroke="#FF818181">
<Path.RenderTransform>
<RotateTransform Angle="135" CenterY="3" CenterX="3"/>
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterY="3" CenterX="3"/>
</Setter.Value>
</Setter>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FF595959"/>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF262626"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF27C7F7"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FFCCEEFB"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1CC4F7"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FF82DFFB"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
</Grid>
<!---标题-->
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="2" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<!---此处HorizontalAlignment="Strech",则为扩充。HorizontalContentAlignment默认=LEFT-->
<ContentPresenter x:Name="PART_Header" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}"
ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<Grid Grid.Column="2" Grid.Row="1" Margin="20,0,0,0" >
<ItemsPresenter x:Name="ItemsHost" />
</Grid>
</Grid>
其中,灰底处代码分别为垂直虚线与横虚线。垂直虚线有两条,分别为:VerLn1、VerLn2,VerLn1用于指向自身结点,VerLn2用于包容子结点项。VerLn1采用RowSpan跨两行,当结点为本层最后一个结点时,VerLn1只跨一行,通过触发器来控制,代码如下:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineConverter}}" Value="True">
<Setter TargetName="VerLn1" Property="Grid.RowSpan" Value="1"/>
<Setter Property="Visibility" TargetName="VerLn2" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineConverter}}" Value="False">
<Setter TargetName="VerLn1" Property="Grid.RowSpan" Value="2"/>
</DataTrigger>
代码中LineConverter为转换器,用于判断是否为本层最后一个结点。代码如下:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TreeViewItem item = (TreeViewItem)value;
ItemsControl ctl = ItemsControl.ItemsControlFromItemContainer(item);
bool bOk = ctl.ItemContainerGenerator.IndexFromContainer(item) == ctl.Items.Count - 1;
return bOk;
}
自定义的树形控件完成,前端可通过拼装列表,构建树型列表。
原码下载:https://download.csdn.net/download/ACODE1/89050468