[WPF实用技巧]如何使WPF的TreeView节点之间有连线_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > [WPF实用技巧]如何使WPF的TreeView节点之间有连线

[WPF实用技巧]如何使WPF的TreeView节点之间有连线

 2014/12/28 23:02:37  Learning hard  程序员俱乐部  我要评论(0)
  • 摘要:示例代码:TreeViewEx.zip原文地址:http://www.codeproject.com/Tips/673071/WPF-TreeView-with-WinForms-Style-FomatIntroductionWPFdefaultTreeViewisverygood,butmanypeoplestillwantittohavelinesjoineachofitschildelements,likeWindowsFormsTreeView,includingme
  • 标签:view 实用 技巧 实用技巧

 

 

 

 

 

 

 

示例代码:TreeViewEx.zip

原文地址:http://www.codeproject.com/Tips/673071/WPF-TreeView-with-WinForms-Style-Fomat

 

Introduction

WPF default TreeView is very good, but many people still want it to have lines join each of its child elements, like Windows Forms TreeView, including me. I have searched on the internet and have some examples, but they were not designed well enough.

Now, I myself designed a TreeView with style as WinForms. Hope this will help many people!

Source Code

All you need is an XAML file and a code behind.

First, you need draw Toggle Button: From Triangle button to Plus-Minus button: draw a rectangle with dark border, then draw two lines, one vertical line and one horizontal line. When TreeViewItem is expanded, the vertical line will hide:

class="code-keyword"><!-- Toggle Button -->
<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
                <Grid Width="15" Height="13" SnapsToDevicePixels="True">
<!-- Rectangle 9x9 pixels -->
                    <Rectangle Width="9" Height="9" 
                    Stroke="#919191" SnapsToDevicePixels="true">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,2" StartPoint="0.5,0">
                                <GradientStop Color="White" Offset="0"/>
                                <GradientStop Color="Silver" Offset="0.5"/>
                                <GradientStop Color="LightGray" Offset="1"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
<!-- Vertical line inside rectangle -->
                    <Rectangle x:Name="ExpandPath" Width="1" 
                    Height="5" Stroke="Black" SnapsToDevicePixels="true"/>
<!-- Horizontal line inside rectangle -->
                    <Rectangle Width="5" Height="1" 
                    Stroke="Black" SnapsToDevicePixels="true"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter Property="Visibility"  
                        TargetName="ExpandPath" Value="Collapsed"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>  

In the above code, you can see a trigger, it will make the vertical line inside toggle button hide if item is expanded, or show if its children collapsed.

Then, you need to draw vertical and horizontal connecting lines between nodes: You need to redesignTreeViewItem control. Add these connecting lines:

 <!-- Horizontal line -->
<Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" 
Stroke="#DCDCDC" SnapsToDevicePixels="True"/>
<!-- Vertical line -->
<Rectangle x:Name="VerLn" Width="1" Stroke="#DCDCDC" 
Margin="0,0,1,0" Grid.RowSpan="2" SnapsToDevicePixels="true" 
Fill="White"/>

to your TreeViewItem template like this:

<!-- TreeViewItem -->
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TreeViewItem}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="19" Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>

                    <!-- Connecting Lines -->
                    <!-- Horizontal line -->
                    <Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" Stroke="#DCDCDC" SnapsToDevicePixels="True"/>
                    <!-- Vertical line -->
                    <Rectangle x:Name="VerLn" Width="1" 
                    Stroke="#DCDCDC" Margin="0,0,1,0" Grid.RowSpan="2" 
                    SnapsToDevicePixels="true" Fill="White"/>
                    <!-- Insert Toggle Button -->
                    <ToggleButton Margin="-1,0,0,0" x:Name="Expander" 
                    Style="{StaticResource ExpandCollapseToggleStyle}" 
                    IsChecked="{Binding Path=IsExpanded, 
                    RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
                    <Border Name="Bd" Grid.Column="1" 
                    Background="{TemplateBinding Background}" 
                    BorderBrush="{TemplateBinding BorderBrush}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                        <ContentPresenter x:Name="PART_Header" 
                        ContentSource="Header" 
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                        MinWidth="20"/>
                    </Border>
                    <ItemsPresenter x:Name="ItemsHost" Grid.Row="1" 
                    Grid.Column="1" Grid.ColumnSpan="2"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style> 

Then, you need put the class TreeViewLineConverter to your namespace. This class will change the connecting lines if the item is the last in the list:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace TreeViewEx
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    class TreeViewLineConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
        {
            TreeViewItem item = (TreeViewItem)value;
            ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
            return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;
        }

        public object ConvertBack(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
        {
            return false;
        }
    }
} 

Insert your namespace to your XAML, i.e.:

<Window x:Class="TreeViewEx.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TreeViewEx"/> 

Add this line to Window.Resources:

<local:TreeViewLineConverter x:Key="LineConverter"/>  

Add trigger to TreeViewItem template, this trigger changes the connecting lines if the item is the last in the list:

<!-- This trigger changes the connecting lines if the item is the last in the list -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, 
Converter={StaticResource LineConverter}}" Value="true">
    <Setter TargetName="VerLn" Property="Height" Value="9"/>
    <Setter TargetName="VerLn" Property="VerticalAlignment" Value="Top"/>
</DataTrigger> 

The TreeView will have WinForms style now. You can add more trigger to control behavior of TreeView if you want. The full trigger can be found in the attached file.

ToDo

In WinForms TreeView, the connecting line is a dotted line. To make these lines dotted, change:

<!-- Connecting Lines -->
<Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" 
Stroke="#DCDCDC" SnapsToDevicePixels="True"/>
<Rectangle x:Name="VerLn" Width="1" Stroke="#DCDCDC" 
Margin="0,0,1,0" Grid.RowSpan="2" SnapsToDevicePixels="true" 
Fill="White"/> 

To:

<!-- Connecting Lines -->
<Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" 
Stroke="Blue" StrokeDashCap="Square" StrokeDashArray="0,2" 
StrokeDashOffset="1" SnapsToDevicePixels="True"/>
<Rectangle x:Name="VerLn" Width="1"  Stroke="Blue" 
StrokeDashCap="Square" StrokeDashArray="0,2" Margin="0,0,1,0" 
Grid.RowSpan="2" SnapsToDevicePixels="true" Fill="White"/> 

But it is not pretty, as you see. As I'm a newbie in WPF, I don't know to style these lines perfectly.

Reference

This is the code I referenced before I wrote my own:

  • Social MSDN: Show TreeView nodes connected with dotted line

 

发表评论
用户名: 匿名