WPF实现完美的树形结构和右键菜单(上)

要想做出完美的树形结构和右键菜单必须要注意一下几个方面

一:TreeView的样式

二:数据的展示和数据绑定

三:数据的的组织和生成(递归)

看下图效果:

首先来看TreeView的样式的实现:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:cw="clr-namespace:Wistron.Framerwork.FrameCommon.WPFExtension;assembly=Wistron.Framerwork.FrameCommon">
    <SolidColorBrush x:Key="NormalForegroundBrush" Color="#999999"/>
    <SolidColorBrush x:Key="HoverForegroundBrush" Color="#424242"/>
    <SolidColorBrush x:Key="SelectedForegroundBrush" Color="#000000"/>

    <!-- 悬停状态的画刷 -->
    <SolidColorBrush x:Key="HoverBackgroundBrushKey" Color="#f0f2f5" />
    <!-- 选中(激活)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedActiveBackgroundBrushKey" Color="#e2e5eb" />
    <!-- 选中(悬停)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedHoverBackgroundBrushKey" Color="#e2e5eb" />
    <!-- 选中(失效)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedInactiveBackgroundBrushKey" Color="#e2e5eb" />
    <!--前面小三角样式-->
    <Style x:Key="ExpandCollapseToggleStyle"
           TargetType="{x:Type ToggleButton}">
        <Setter Property="Focusable"
                Value="False" />
        <Setter Property="Width"
                Value="13" />
        <Setter Property="Height"
                Value="13" />
        <Setter Property="Foreground" Value="{DynamicResource NormalForegroundBrush }"/>
        <Setter Property="Template">
            <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
            <Grid Width="13" Height="13"  Background="Transparent">
            <Path x:Name="ExpandPath"
              HorizontalAlignment="Left"
              VerticalAlignment="Center"
              Margin="0"
              Fill="{TemplateBinding Foreground}"
             Data="M 4 0 L 8 4 L 4 8 Z"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="MetroTreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="{DynamicResource NormalForegroundBrush }"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <ControlTemplate.Resources>
                        <!-- 计算节点缩进的转换器 -->
                        <cw:IndentConverter Indent="5" MarginLeft="5" x:Key="IndentConverter" />
                    </ControlTemplate.Resources>
                    <StackPanel>
                        <Border x:Name="Border"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                Padding="{TemplateBinding Padding}"
                                SnapsToDevicePixels="True">
                            <Grid Margin="{Binding Converter={StaticResource IndentConverter}, RelativeSource={RelativeSource TemplatedParent}}">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition MinWidth="12" Width="Auto" />
                                    <ColumnDefinition />
                                </Grid.ColumnDefinitions>
                                <ToggleButton x:Name="Expander"
                                              Style="{StaticResource ExpandCollapseToggleStyle}"
                                              IsChecked="{Binding Path=IsExpanded,RelativeSource={RelativeSource TemplatedParent}}"
                                              ClickMode="Press" Width="Auto" HorizontalAlignment="Left"   VerticalAlignment="Center"
                                              Height="Auto" Margin="0,0,0,0" />
                                <ContentPresenter x:Name="PART_Header"
                                                  Grid.Column="1"
                                                  ContentSource="Header"
                                                  VerticalAlignment="{TemplateBinding VerticalAlignment}"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Grid>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost">
                         </ItemsPresenter>
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="False">
                            <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
                        </Trigger>
                        <Trigger Property="HasItems" Value="False">
                            <Setter TargetName="Expander" Property="Visibility" Value="Hidden" />
                        </Trigger>
                        <!-- 选中(激活)-->
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Border" Property="Background"
                                    Value="{StaticResource SelectedActiveBackgroundBrushKey}" />
                            <Setter  Property="Foreground"
                                    Value="{StaticResource  SelectedForegroundBrush}" />
                            <Setter TargetName="Expander"  Property="Foreground"
                                    Value="{StaticResource  SelectedForegroundBrush}" />
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="True" />
                                <Condition Property="Selector.IsSelectionActive" Value="False" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Border" Property="Background"
                                    Value="{StaticResource SelectedInactiveBackgroundBrushKey}" />
                            <Setter  Property="Foreground"
                                    Value="{StaticResource SelectedForegroundBrush}" />
                            <Setter TargetName="Expander"  Property="Foreground"
                                    Value="{StaticResource  SelectedForegroundBrush}" />
                        </MultiTrigger>
                        <Trigger SourceName="Border" Property="IsMouseOver" Value="True">
                            <Setter TargetName="Border" Property="Background"
                                    Value="{StaticResource HoverBackgroundBrushKey}" />
                            <Setter  Property="Foreground"
                                    Value="{StaticResource  HoverForegroundBrush}" />
                             <Setter TargetName="Expander"  Property="Foreground"
                                    Value="{StaticResource  HoverForegroundBrush}" />
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="True" />
                                <Condition SourceName="Border" Property="IsMouseOver" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Border" Property="Background"
                                    Value="{StaticResource SelectedHoverBackgroundBrushKey}" />
                            <Setter  Property="Foreground"
                                    Value="{StaticResource  SelectedForegroundBrush}" />
                            <Setter TargetName="Expander"  Property="Foreground"
                                    Value="{StaticResource  SelectedForegroundBrush}" />
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Foreground"
                                    Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="MetroTreeViewStyle"
           TargetType="{x:Type TreeView}">
        <Setter Property="BorderBrush"
                Value="{DynamicResource BlackBrush}" />
        <!-- default to 0 -->
        <Setter Property="BorderThickness"
                Value="0" />
        <Setter Property="SnapsToDevicePixels"
                Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeView}">
                    <Border Name="Border"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <ScrollViewer>
                            <ItemsPresenter />
                        </ScrollViewer>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled"
                                 Value="False">
                            <Setter TargetName="Border"
                                    Property="BorderBrush"
                                    Value="{DynamicResource GrayBrush9}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemContainerStyle"
                Value="{StaticResource MetroTreeViewItemStyle}" />
    </Style>

</ResourceDictionary>

上面引用了的一个缩进方法 这个事非常重要的,第一关系到父节点和子节点的缩进长度,第二关系到选择 和鼠标放上去的样式是否是整列。引用的缩进代码如下

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

namespace Wistron.Framerwork.FrameCommon.WPFExtension
{
    /// <summary>
    /// 计算 <see cref="System.Windows.Controls.TreeViewItem"/> 的缩进的转换器。
    /// </summary>
    [ValueConversion(typeof(TreeViewItem), typeof(Thickness))]
    public sealed class IndentConverter : IValueConverter
    {
        /// <summary>
        /// 获取或设置缩进的像素个数。
        /// </summary>
        public double Indent { get; set; }
        /// <summary>
        /// 获取或设置初始的左边距。
        /// </summary>
        public double MarginLeft { get; set; }
        /// <summary>
        /// 转换值。
        /// </summary>
        /// <param name="value">绑定源生成的值。</param>
        /// <param name="targetType">绑定目标属性的类型。</param>
        /// <param name="parameter">要使用的转换器参数。</param>
        /// <param name="culture">要用在转换器中的区域性。</param>
        /// <returns>转换后的值。如果该方法返回 <c>null</c>,则使用有效的 <c>null</c> 值。</returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            TreeViewItem item = value as TreeViewItem;
            if (item == null)
            {
                return new Thickness(0);
            }
            return new Thickness(this.MarginLeft + this.Indent * item.GetDepth(), 0, 0, 0);
        }
        /// <summary>
        /// 转换值。
        /// </summary>
        /// <param name="value">绑定目标生成的值。</param>
        /// <param name="targetType">要转换到的类型。</param>
        /// <param name="parameter">要使用的转换器参数。</param>
        /// <param name="culture">要用在转换器中的区域性。</param>
        /// <returns>转换后的值。如果该方法返回 <c>null</c>,则使用有效的 <c>null</c> 值。</returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

TreeView的样式几个重要方面就是选择颜色,鼠标放上去的颜色,还有选择鼠标放上去的颜色,在样式文件里表的一清二楚。

TreeView的样式就大功告成了。

时间: 2024-12-25 11:58:56

WPF实现完美的树形结构和右键菜单(上)的相关文章

WPF实现完美的树形结构和右键菜单(下)

上篇讲了TreeView的样式 这篇讲TreeView的数据绑定与邮件菜单的实现 看下图: 先来看看TreeView的数据绑定 <TreeView x:Name="TrvList" Grid.Row="1" Margin="4 8 0 0" VerticalAlignment="Stretch" ContextMenu="{DynamicResource ContractContextMenu}" I

winrar在右键菜单上加上:打包自动加上日期时间标签【图文教程】 - imsoft.cnblogs

说明:  注册表HKEY_CURRENT_USER\Software\WinRAR\Profiles\0找到GenerateArcName修改0为1,修改GenerateMask为你想要的日期式(默认yyyymmddhhnnss)HKEY_CURRENT_USER\Software\WinRAR\Profiles为WINRAR的备份配置0 1 2 3 4是四种方式,0为默认设置,修改0下面的值后就能在使用右键菜单   添加到"xxx.rar"(T) 后自动在文件名后加入指定格式的日期.

桌面支持--WIN7任务栏上EXCEL的图标右键菜单上没有了最近打开的文档目录

WIN7任务栏上EXCEL的图标右键菜单上没有了最近打开的文档目录 解决办法: 删除以下文件夹内的所有文件,并重启,然后将要固定的文件夹重新拖到任务栏"附到windows资源管理器"即可 %APPDATA%\Microsoft\Windows\Recent\AutomaticDestinations    "最近" %APPDATA%\Microsoft\Windows\Recent\CustomDestinations        "已固定"

QStandardItemModel角色控制及QTreeView加入不同的右键菜单

1.概述 QTreeView最长用的一个功能就是作为导航栏,像vs里的项目结构树,word的文档结构图,资源管理器的文档结构,等等都是利用树形结构组织的,在前面已经讲述了Qt中使用标准化项目模型QStandardItemModel对树形控件节点的操作.但有时候,光有节点显示还是不够的,还须要和用户进行交互,如右键点击不同条目会出现不同菜单,这时就须要知道各个节点相应的功能. 在MFC里,树形控件CTreeCtrl是通过SetItemData函数来对节点设置一个指针的值,这个值能够是个指针或者DW

QStandardItemModel角色控制及QTreeView添加不同的右键菜单

1.概述 QTreeView最长用的一个功能就是作为导航栏,像vs里的项目结构树,word的文档结构图,资源管理器的文档结构,等等都是利用树形结构组织的,在前面已经讲述了Qt中使用标准化项目模型QStandardItemModel对树形控件节点的操作.但有时候,光有节点显示还是不够的,还需要和用户进行交互,如右键点击不同条目会出现不同菜单,这时就需要知道各个节点对应的功能. 在MFC里,树形控件CTreeCtrl是通过SetItemData函数来对节点设置一个指针的值,这个值可以是个指针或者DW

VS2013在右键菜单添加命令插件开发

一.选择Visual Studio Package模板建立插件项目 由于此功能需要在右键菜单上添加命令,所以选择Visual Studio Package模板,根据模板向导步骤插件项目,在Select VSPackage Options步骤的时候选择Menu Command选项,如图-1所示: 图-1 接下来是设置命令的名称,如图-2所示 图-2 修改Command name的值,将其设置为我们要添加到右键菜单时的名称.Command ID可选择是否修改,值是一个十六进制数,由于标识我们的添加的

VS2013点击右键菜单命令添加xml元素插件开发

一.选择Visual Studio Package模板建立插件项目 由于此功能需要在右键菜单上添加命令,所以选择Visual Studio Package模板,根据模板向导步骤插件项目,在Select VSPackage Options步骤的时候选择Menu Command选项,如图-1所示: 图-1 接下来是设置命令的名称,如图-2所示 图-2 修改Command name的值,将其设置为我们要添加到右键菜单时的名称.Command ID可选择是否修改,值是一个十六进制数,由于标识我们的添加的

MyEclipse建立树形结构包

温馨提示:本文是一个java菜鸟对其他新手朋友在新建java包时所遇问题的解释,高手请绕道哦~~~~ 随便一个java项目中免不了有多层嵌套的包: 对一个过了计算机一级的孩子来说,建立如上几个嵌套的树状java包肯定都不在话下吧? 说来可笑,昨天晚上,在MyEclipse中建立这几个包浪费了老子半个小时! 别笑我!我相信不少人当初用的时间比我还多!哈哈~~开个玩笑~~ 以本文开头那个项目的包结构为例,我的思路是,①先建立顶层包com,②再在com包下建立第二层包jypt,③再在jypt包下面建立

设计模式完结(8)-- 组合模式---树形结构的处理

树形结构的处理--组合模式(一) 组合模式为处理树形结构提供了一种较为完美的解决方案,它描述了如何将容器和叶子进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待 容器和叶子. 所以:抽象类    叶子类   容器类 abstract class Component { public abstract void add(Component c); //增加成员 public abstract void remove(Component c); //删除成员 public abstra