示例代码: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:

<!-- 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节点之间有连线的更多相关文章

  1. wpf中,一个简单的自定义treeview

    首先创建一个自定义控件,在里面定义好treeview的样式,将本来的三角形的图标变为加号的图标,并且添加节点之间的连线. <UserControl x:Class="TreeViewE ...

  2. WPF进阶技巧和实战03-控件(4-基于范围的控件及日期控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  3. WPF进阶技巧和实战03-控件(3-文本控件及列表控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  4. 使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等

    原文:使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等      WPF预设有Aero, Classic, Luna, Royale主题, WPF程序会根据 ...

  5. WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮

    原文:WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮 在边框中加入一些元素,在应用程序的界面设计中,已经开始流行起来.特别是在浏览器(Crome,IE,Firefox,Opera)中都有应用. ...

  6. WPF实用指南二:移除窗体的图标

    原文:WPF实用指南二:移除窗体的图标 WPF没有提供任何功能来移除窗体上的icon图标.一般的做法是设置一个空白的图标,如下图1: 这种做法在窗体边框与标题之间仍然会保留一片空白. 比较好的做法是使 ...

  7. WPF如何实现TreeView节点重命名

    我们经常看到一些软件比如酷狗音乐,在对列表右键进行重命名的时候,当前列表会泛白并且进入可编辑状态,当我们更改完成后就会并进入非编辑状态,这些具体是怎么实现的呢?下面的方法也许会提供一些思路,下面的Tr ...

  8. WPF 之 TreeView节点重命名

    下面的TreeView节点是通过数据双向绑定的方式,绑定到TextBlock控件和TextBox控件的Text属性上,并且让两者绑定相同的属性,同时使TextBox控件刚好完全覆盖TextBlock控 ...

  9. WPF实用知识点

    1.一个基本的WPF程序, 需要引入的程序集WindowsBase, PresentationCore, PresentationFramework using System; using Syste ...

随机推荐

  1. (转)selenuim-webdriver注解之@FindBy、@FindBys、@FindAll的区别

    selenium-webdriver中获取页面元素的方式有很多,使用注解获取页面元素是其中一种途径, 方式有3种:@FindBy.@FindBys.@FindAll.下文对3中类型的区别和使用场景进行 ...

  2. c++ 覆盖、重载与隐藏

    成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生 ...

  3. VBA中常用技巧

    常量定义 Public Const i as Integer = 1 自定义类型 Type mytype i   as Integer b  as  Boolean s  as  String end ...

  4. sql server convert 日期

    ),) --2016/11 ),) --2016-11-03 17:46:47

  5. eclipse中java项目的build path详解

    BuildPath中只支持加入jar文件,具体方法如下:在eclips里在工程名上右键->build path->contigure bud path->java build pat ...

  6. phpredis中文文档 [转]

    phpredis是php的一个扩展,效率是相当高有链表排序功能,对创建内存级的模块业务关系 很有用;以下是redis官方提供的命令使用技巧: 下载地址如下: https://github.com/ow ...

  7. asp.net 跨域服务器 上传文件

    最近一个项目遇到问题,公司局域网中,在F域下有个服务器Fa,我们的项目就部署在Fa.项目里面有个功能,需要把生成的文件(.doc,.xls,.pdf)保存到O域的一台文件共享服务器Ob.在原有的网络环 ...

  8. Log

    Public Shared Sub WriteLog(ByVal FormID As String, ByVal ex1 As Exception) 'log信息 Dim loginfo As Str ...

  9. JavaScript-事件坐标

    事件坐标: 1.参照屏幕左上角e.screenX,e.screenY 2.参照文档显示区左上角:e.clientX||e.x , e.clientY||e.y 3.参照所在父元素的左上角:e.offs ...

  10. <转>简单之美——系统设计黄金法则

    作者: 包云岗  发布时间: 2012-05-19 13:06  阅读: 3036 次  推荐: 1   原文链接   [收藏] 最近多次看到系统设计与实现的文章与讨论,再加上以前读过的其他资料以及自 ...