如何将 WPF TreeView 样式设置为 WinForms TreeView? [英] How to make WPF TreeView style as WinForms TreeView?

查看:36
本文介绍了如何将 WPF TreeView 样式设置为 WinForms TreeView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

WPF 默认的 TreeView 非常好,我仍然希望它的每个子元素都有线连接,就像 Windows 窗体 TreeView.我已经在互联网上搜索并提供了一些示例,但它设计得不够好.

如何使用 WPF 实现它?

解决方案

让我来回答我自己的问题.

代码

您需要做的只是一个 XAML 文件和背后的代码:

首先你需要画切换按钮:从三角形按钮到加减按钮:画一个黑色边框的矩形,然后画两条线,一条竖线,一条横线.当 TreeViewItem 展开时,垂直线会隐藏:

<Style x:Key=ExpandCollapseToggleStyle"TargetType=切换按钮"><Setter 属性 =Focusable"值=假"/><Setter 属性 =模板"><Setter.Value><ControlTemplate TargetType="ToggleButton"><网格宽度=15"高度=13"SnapsToDevicePixels=真"><!-- 矩形 9x9 像素--><矩形宽度=9"高度=9"中风=#919191"SnapsToDevicePixels=真"><矩形.填充><LinearGradientBrush EndPoint=0.5,2"起点=0.5,0"><GradientStop Color=白色"偏移=0"/><GradientStop Color=银色"偏移=0.5"/><GradientStop Color=LightGray"偏移=1"/></LinearGradientBrush></矩形填充></矩形><!-- 矩形内的垂直线--><矩形 x:Name="ExpandPath";宽度=1"高度=5"笔画=黑色"SnapsToDevicePixels=真"/><!-- 矩形内的水平线--><矩形宽度=5"高度=1"笔画=黑色"SnapsToDevicePixels=真"/></网格><ControlTemplate.Triggers><触发器属性=IsChecked"值=真"><Setter 属性 =可见性";目标名称=扩展路径"值=折叠"/></触发器></ControlTemplate.Triggers></控制模板></Setter.Value></Setter></风格>

在上面的代码中,您可以看到一个触发器,它会在项目展开时隐藏切换按钮内的垂直线,或者如果其子项折叠则显示.

然后,你需要在节点之间绘制垂直和水平连接线:你需要重新设计TreeViewItem控件.添加这些连接线:

<矩形 x:Name=HorLn";边距=9,1,0,0"高度=1"中风=#DCDCDC"SnapsToDevicePixels=真"/><!-- 竖线--><矩形 x:Name=VerLn";宽度=1"中风=#DCDCDC"边距=0,0,1,0"Grid.RowSpan=2"SnapsToDevicePixels=真"填充=白色"/>

到您的 TreeViewItem 模板,如下所示:

<Style x:Key="{x:Type TreeViewItem}";TargetType={x:Type TreeViewItem}"><Setter 属性 =模板"><Setter.Value><ControlTemplate TargetType="{x:Type TreeViewItem}"><网格><Grid.ColumnDefinitions><ColumnDefinition MinWidth=19"宽度=自动"/><ColumnDefinition Width=自动"/><ColumnDefinition Width=*"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height=自动"/><行定义/></Grid.RowDefinitions><!-- 连接线--><!-- 水平线--><矩形 x:Name=HorLn";边距=9,1,0,0"高度=1"中风=#DCDCDC"SnapsToDevicePixels=真"/><!-- 竖线--><矩形 x:Name=VerLn";宽度=1"中风=#DCDCDC"边距=0,0,1,0"Grid.RowSpan=2"SnapsToDevicePixels=真"填充=白色"/><!-- 插入切换按钮--><ToggleButton Margin="-1,0,0,0";x:Name=扩展器"Style="{StaticResource ExpandCollapseToggleStyle}";IsChecked={绑定路径=IsExpanded,RelativeSource={RelativeSource TemplatedParent}}";ClickMode=按"/><边界名称=Bd";Grid.Column=1"背景={模板绑定背景}";BorderBrush="{TemplateBinding BorderBrush}";BorderThickness={TemplateBinding BorderThickness}";Padding="{TemplateBinding Padding}";SnapsToDevicePixels=真"><ContentPresenter x:Name="PART_Header";内容源=标题"Horizo​​ntalAlignment="{TemplateBinding Horizo​​ntalContentAlignment}";MinWidth=20"/></边框><ItemsPresenter x:Name=ItemsHost"Grid.Row=1"Grid.Column=1"Grid.ColumnSpan=2"/></网格></控制模板></Setter.Value></Setter></风格>

然后您需要将类 TreeViewLineConverter 放入您的命名空间.如果项目是列表中的最后一个,该类将更改连接线:

使用系统;使用 System.Windows;使用 System.Windows.Controls;使用 System.Windows.Data;命名空间 TreeViewEx{公共部分类 MainWindow : 窗口{公共主窗口(){初始化组件();}}类 TreeViewLineConverter : IValueConverter{公共对象转换(对象值,类型目标类型,对象参数,System.Globalization.CultureInfo 文化){TreeViewItem item = (TreeViewItem)value;ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);返回 ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;}公共对象 ConvertBack(对象值,类型目标类型,对象参数,System.Globalization.CultureInfo 文化){返回假;}}}

将您的命名空间插入您的 XAML,即:

将此行添加到 Window.Resources:

添加触发器到 TreeViewItem 模板,如果 item 是列表中的最后一个,这个触发器会改变连接线:

<!-- 如果该项是列表中的最后一项,此触发器会更改连接线 --><DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineConverter}}";值=真"><Setter TargetName="VerLn";属性=高度"值=9"/><Setter TargetName="VerLn";属性=垂直对齐"值=顶部"/></数据触发器>

TreeView 现在将具有 WinForms 样式.如果需要,您可以添加更多触发器来控制 TreeView 的行为.完整的触发器可以在附件中找到.

待办事项

在 WinForms TreeView 中,连接线是虚线.要使这些线成为虚线,请更改:

<矩形 x:Name=HorLn";边距=9,1,0,0"高度=1"中风=#DCDCDC"SnapsToDevicePixels=真"/><矩形 x:Name=VerLn";宽度=1"中风=#DCDCDC"边距=0,0,1,0"Grid.RowSpan=2"SnapsToDevicePixels=真"填充=白色"/>

致:

<矩形 x:Name=HorLn";边距=9,1,0,0"高度=1"笔画=蓝色"StrokeDashCap=方形"StrokeDashArray=0,2"StrokeDashOffset=1"SnapsToDevicePixels=真"/><矩形 x:Name=VerLn";宽度=1"笔画=蓝色"StrokeDashCap=方形"StrokeDashArray=0,2"边距=0,0,1,0"Grid.RowSpan=2"SnapsToDevicePixels=真"填充=白色"/>

但正如你所见,它并不漂亮.由于我是 WPF 的新手,我不知道如何完美地设计这些线条.

问题!

在TreeView中添加TreeViewItem时出现竖线问题:

您可能建议我更改垂直线的大小,但如果您也更改字体大小,则不起作用.

源代码

你可以在这里下载我的源代码:
https://www.codeproject.com/Tips/673071/WPF-TreeView-with-WinForms-Style-Fomat

参考

这是我在编写自己的代码之前参考的代码:Social MSDN:显示用虚线连接的TreeView节点>

WPF default TreeView is very good, I still want it have lines joint each its child element, like Windows Forms TreeView. I have searched on internet and have some example, but it did not designed well enough.

How can I achieve it with WPF?

解决方案

Let me answer my own question.

                     

Code

All you need to do is a 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 above code, you can see a trigger, it will make the vertical line inside toggle button hide if item is expand, or show if its children collapsed.

Then, you need draw vertical and horizontal connecting lines between nodes: You need redesign TreeViewItem 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 changes 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, ie:

<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 behavie of TreeView if you want. The full trigger can found on attached file.

ToDo

In WinForms TreeView, the connecting lines is a dotted lines. 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 line perfectly.

Problem!

There is a problem with vertical line when you add a TreeViewItem into TreeView:

                                             

You may suggest me change Vertical Line size, but if you change the font size, too, it will not work.

Source code

You can download my source code here:
https://www.codeproject.com/Tips/673071/WPF-TreeView-with-WinForms-Style-Fomat

Reference

This is the code I refereced before I wrote my own: Social MSDN: Show TreeView nodes connected with dotted lines

这篇关于如何将 WPF TreeView 样式设置为 WinForms TreeView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆