1. 程式人生 > >[WPF實用技巧]如何使WPF的TreeView節點之間有連線

[WPF實用技巧]如何使WPF的TreeView節點之間有連線

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:

<!-- 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:

相關推薦

[WPF實用技巧]如何使WPF的TreeView節點之間連線

Introduction WPF default TreeView is very good, but many people still want it to have lines join each of its child elements, like Windo

線性佈局中如何使實現元件之間間隔

在研究android的Contacts原始碼的時候,遇到了一個佈局檔案,是用LinearLayout進行佈局的,先將程式碼貼上。 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr

程式設計師面試金典: 9.4樹與圖 4.2給定向圖,設計一個演算法,找出兩個節點之間是否存在一條路徑。

#include <iostream> #include <stdio.h> #include <vector> #include <queue> using namespace std; /* 問題:給定有向圖,設計一個

Qml實用技巧:將樣式style從物件中獨立出來,可使多個按鈕載入同一個樣式

需求         多個按鈕使用同一個樣式 原理         寫成元件形式(在或不在當前檔案中),需要樣式時,Button載入style即可 程式碼 Item { Rectangle {

【老鳥分享】Linux命令行終端提示符多種實用技巧

linux 技巧 系統管理員 1.Linux命令行提示符簡介眾所周知,Linux命令行是系統管理員管理Linux的重要手段,我們管理Linux,首先要面對的就是Linux命令行提示符。Linux命令行結尾的提示符有“#”和“$”兩種不同的符號,如下所示: [[email prot

Allegro實用技巧之模塊復用(轉)

塊選擇 提示 好的 create mod 文件 實用技巧 lin app 需求分析:使用Allegro軟件進行PCB Layout設計時,當電路圖中有很多路相同的模塊,使用模塊復用的的操作方法,可以顯著提高工作效率,同時也可以使PCB布局在整體上顯得美觀。下面來講述這個方法

使用FlashPaper在線轉換.doc為.swf_實用技巧

except compute cef sum true 高級 文件中 電子 paper https://yq.aliyun.com/ziliao/160044?spm=5176.8246799.0.0.JBbqjY 摘要: 本文講的是使用FlashPaper在線轉換

電刷和碳刷兩者之間什麽區別和聯系?

href jcs 範圍 clas .com 用途 兩個 jce 交流電 一般來說電刷與碳刷是一樣的,只是說到電刷的範圍還比較廣義一些。碳刷只能是由碳粒組成或含有碳的成份。而電刷可能根本不含有碳的成分。比如小型的剃須刀就有用兩片銅片當電刷的。而大部分電刷是由碳或含有碳的成分。

ASP.NET中共有哪幾種類型的控件?其中,HTML控件、HTML服務器控件和WEB服務器控件之間什麽區別

web服務 編程 用戶 控制 什麽 lin bsp 兼容性 check ASP.NET的控件包括WEB服務器控件、WEB用戶控件、WEB自定義控件、HTML服務器控件和HTML控件。HTML控件、HTML服務器控件和WEB服務器控件之間的區別如下所示。q HTML

Java8 日期和時間實用技巧

ron 定義 com 閏年 上下 代碼 添加 sta date 新的日期API ZoneId: 時區ID,用來確定Instant和LocalDateTime互相轉換的規則 Instant: 用來表示時間線上的一個點 LocalDate: 表示沒有時區的日期, Loca

題目:判斷101-200之間多少個素數,並輸出所有素數

[] bool ole enum print 輸出 static ber while 1 public class PrimeNumber{//100-200直接有多少素數 2 public static void main(String[] args){

Everything實用技巧隨手記

ron 正則表達 目錄 add alt 通配符 exclude 搜索 添加 Everything是一款非常好用的即時搜索軟件,針對文件名目錄名搜索,並且支持通配符、正則表達式,勝過windows自帶搜索N倍。 在使用中有些許不便,比如搜索結果中出現很多快

好用不需多說的微信公眾號實用技巧,一起來叨叨!

新媒體至此軍訓之際,太陽大大當空照,火熱的陽光真是好!小編的心情也是非常的好,想一想那麽多嗮黑了,餓瘦了的小學妹們,終於可以顯的我好白好白啦(不是白胖白胖)!白白瘦瘦的我現在比較容易緊張,一緊張我就...喜歡裝逼...裝逼我就想到了微信,想到了微信就忍不住和大家叨叨幾個超級牛逼的技巧(⊙o⊙) 牛逼的技巧一:

JQuery實用技巧--學會你也是大神(1)——插件的制作技巧

index 小圖標 定義 query rip 使用 scroll 簡單實用 default 前 言 JRedu 學習之前,首先我們需要知道什麽是JQuery?  JQuery是一個優秀的javascript框架。  JQuery是繼Prototype之後又一個優秀的

響應式設計的5個css實用技巧

mda ota .html tk1 tmx htm cool http lec mongodb30%E6%AD%A3%E5%BC%8F%E7%89%88%E5%8F%91%E5%B8%83 http://www.zcool.com.cn/collection/ZMTY4O

數據挖掘與機器學習之間什麽聯系?

簡單 影響 意義 數據管理 多人 機器學習 管理 -s 很多   談到對數據進行分析利用,很多人會想到“數據挖掘”(data mining),這裏簡單探討一下數據挖掘和機器學習的聯系。   數據挖掘領域是在二十世紀九十年代左右形成,他收到很多學科的影響,其中數據庫、機器學習

Unicode與ASCiI之間什麽區別?java當中的轉義字符 Character類的使用 String類的使用

charat and pac sca sdi change con 輸入 ack ASCII碼 稱為 美國標準信息交換碼 (American standard code of Information Interchange) 其中一共有多少個碼?2的7次冪 128個 Un

Windows10實用技巧-固定快捷方式到磁貼菜單方式

.net font 功能 win 但是 情況下 直接 ram soft 快捷方式固定到磁貼 Win10的開始菜單中的磁貼功能比較不錯,可以在不清理桌面上其他軟件的情況下直接喚醒需要的應用。 但是比較麻煩的是一些應用或快捷方式並不能直接固定到上面。 後來發現所有Wind

實用技巧(掉進去又爬出來的坑兒)

not protoc obj json splay 不顯示圖片 sub 我們 bject 1.將字符型的字段轉化為整形進行排序 1 # Django實現將字符型的字段轉化為整形進行排序 2 # mysql數據庫(不同的數據

C#之WinForm WebBrowser實用技巧匯總

聯動 統計 密碼 change 學習 dddddd all bottom finished 本文實例匯總了C#中WinForm WebBrowser常見的實用技巧,對於C#程序開發來說有不錯的借鑒價值。分別敘述如下: 方法1:獲取狀態欄信息void webBrowser1