WPF 自定义TreeView控件样式,仿QQ联系人列表
一、前言
TreeView控件在项目中使用比较频繁,普通的TreeView并不能满足我们的需求。因此我们需要滴对TreeView进行改造。下面的内容将介绍仿QQ联系人TreeView样式及TreeView数据绑定方法。
二、TreeView仿QQ联系人列表
准确的说不是仿QQ联系人列表,这个TreeView样式作为组织架构来使用更好。废话不多说,先看效果:
2.1、基本思路
像这种联系人列表一般涉及到多层级数据,而且有很多数据是需要动态更新的,如果通过手动一条条增加数据反而更复杂,而且不方便。因此为了绑定数据方便我们使用分层模板HierarchicalDataTemplate。
分层模板中存在两种样式,一种是分组样式,一种是人员样式。不管是分组还是人员绑定的都是对象,这样我们在对象中添加一个属性来辨别是否为分组-IsGrouping。
默认的TreeView控件四周会有边距,因此需要设置下TreeView的样式。另外鼠标经过和鼠标选中的背景色需要变化,因此还需要设置TreeViewItem的样式。
根据思路,我们需要设置三个样式,TreeView样式,TreeViewItem样式,HierarchicalDataTemplate分层模板样式。另外为了自动计算下一级的边距,我们需要添加一个转换器IndentConverter。还需要一个转换器需要将布尔类型的IsGrouping转换为Visibility,还需要一个转换器来对Visibility取反。
这样三个样式,三个转换器。就可以实现我们上面的效果,另外还可以进行动态数据绑定。
2.2、样式代码
HierarchicalDataTemplate分层模板样式代码
<HierarchicalDataTemplate x:Key="ItemNode" ItemsSource="{Binding Children,Mode=TwoWay}">
<Grid Background="Transparent">
<Grid.Resources>
<convert:BoolToVisible x:Key="boolToVisible"/>
<convert:VisibleToReverse x:Key="visibleToReverse"/>
</Grid.Resources>
<Grid MinHeight="30" x:Name="userinfo" Background="Transparent" Margin="-5 0 0 0" Visibility="{Binding Visibility,ElementName=groupinginfo,Converter={StaticResource visibleToReverse}}">
<Grid Height="50" x:Name="grid">
<Border Background="#62acf9" Width="40" Height="40" CornerRadius="4" HorizontalAlignment="Left" Margin="0 0 0 0">
<TextBlock Text="{Binding SurName}" FontSize="23" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<TextBlock Text="{Binding Name}" Margin="50 7 0 0" FontSize="13"/>
<TextBlock Text="{Binding Info}" Foreground="#808080" Margin="50 30 0 0"/>
<TextBlock Text="{Binding Count,StringFormat={}{0}人}" Foreground="#808080" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0 0 5 0"/>
</Grid>
</Grid>
<StackPanel MinHeight="25" x:Name="groupinginfo" Orientation="Horizontal" Background="Transparent" HorizontalAlignment="Left" Visibility="{Binding IsGrouping,Converter={StaticResource boolToVisible}}"> <TextBlock Text="{Binding DisplayName}" Margin="3 0" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
</HierarchicalDataTemplate>
TreeViewItem样式代码
<Style x:Key="DefaultTreeViewItem" TargetType="{x:Type TreeViewItem}">
<Setter Property="MinHeight" Value="25" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="Margin" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ControlTemplate.Resources>
<convert:IndentConverter x:Key="indentConverter"/>
</ControlTemplate.Resources>
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Name="itemBackground" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<Grid Background="Transparent">
<Grid x:Name="ItemRoot" Margin="{Binding Converter={StaticResource indentConverter},RelativeSource={RelativeSource TemplatedParent}}" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> <ToggleButton x:Name="Expander" HorizontalAlignment="Left" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="Transparent" Height="16" Padding="5" Width="16">
<Path x:Name="ExpandPath" Data="M0,0 L0,6 L6,0 z" Fill="#66645e" Stroke="#66645e">
<Path.RenderTransform>
<RotateTransform Angle="135" CenterY="3" CenterX="3"/>
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterY="3" CenterX="3"/>
</Setter.Value>
</Setter>
<Setter Property="Fill" TargetName="ExpandPath" Value="#66645e"/>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#66645e"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="ExpandPath" Value="#66645e"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#66645e"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#66645e"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#66645e"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<ContentPresenter Grid.Column="1" x:Name="PART_Header" ContentSource="Header"
HorizontalAlignment="Stretch" > </ContentPresenter>
</Grid>
</Grid> </Border>
<ItemsPresenter x:Name="ItemsHost" Grid.Row="1"/>
</Grid> <ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsGrouping}" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
</DataTrigger>
<Trigger Property="HasItems" Value="False">
<Setter Property="Visibility" TargetName="Expander" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsExpanded" Value="False">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</Trigger> <Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="itemBackground" Value="#FAE388"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="False"/>
<Condition SourceName="itemBackground" Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value=" #fceeb9" TargetName="itemBackground"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TreeView样式代码
<Style x:Key="DefaultTreeView" TargetType="{x:Type TreeView}">
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
<Setter Property="ItemContainerStyle" Value="{StaticResource DefaultTreeViewItem}"></Setter>
<Setter Property="Padding" Value="0"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Margin="0"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
2.3、转换器代码
public class IndentConverter : IValueConverter
{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double colunwidth = ;
double left = 0.0; UIElement element = value as TreeViewItem;
while (element.GetType() != typeof(TreeView))
{
element = (UIElement)VisualTreeHelper.GetParent(element);
if (element.GetType() == typeof(TreeViewItem))
left += colunwidth;
}
return new Thickness(left, , , );
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
} } public class BoolToVisible : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
return Visibility.Visible;
else
return Visibility.Collapsed;
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
} public class VisibleToReverse : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((Visibility)value == Visibility.Visible)
return Visibility.Collapsed;
else
return Visibility.Visible;
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
2.4、引用示例
<TreeView x:Name="TreeViewOrg" BorderThickness="1" BorderBrush="#BBB" Background="Transparent" Width="280" Height="500" Margin="10" ItemTemplate="{StaticResource ItemNode}" Style="{StaticResource DefaultTreeView}">
</TreeView>
2.5、初始化数据源及绑定对象
public MainWindow()
{
InitializeComponent();
OrgList = new ObservableCollection<OrgModel>()
{
new OrgModel()
{
IsGrouping=true,
DisplayName="单位名称(3/7)",
Children=new ObservableCollection<OrgModel>()
{
new OrgModel(){
IsGrouping=true,
DisplayName="未分组联系人(2/4)",
Children=new ObservableCollection<OrgModel>()
{
new OrgModel(){
IsGrouping=false,
SurName="刘",
Name="刘棒",
Info="我要走向天空!",
Count=
}
}
}
},
} };
TreeViewOrg.ItemsSource = OrgList;
} public ObservableCollection<OrgModel> OrgList { get; set; } public class OrgModel
{
public bool IsGrouping { get; set; }
public ObservableCollection<OrgModel> Children { get; set; }
public string DisplayName { get; set; }
public string SurName { get; set; }
public string Name { get; set; }
public string Info { get; set; }
public int Count { get; set; }
}
所有代码已经上传到github:https://github.com/cmfGit/WpfDemo.git
WPF 自定义TreeView控件样式,仿QQ联系人列表的更多相关文章
- WPF自定义分页控件,样式自定义,简单易用
WPF自定义分页控件 做了许久伸手党,终于有机会贡献一波,搜索一下WPF分页控件,还是多,但是不太通用,主要就是样式问题,这个WPF很好解决,还有一个就是分页控件嘛,只关心几个数字的变动就行了,把页码 ...
- WPF 自定义TabControl控件样式
一.前言 程序中经常会用到TabControl控件,默认的控件样式很普通.而且样式或功能不一定符合我们的要求.比如:我们需要TabControl的标题能够居中.或平均分布:或者我们希望TabContr ...
- wpf 自定义RadioButton控件样式
实现的效果为: 我感觉来自定义RadioButton样式和定义button空间的样式差不多,只是类型不同而已. 接下来分析一下样式代码: <!--自定义单选按钮样式--> & ...
- WPF 自定义DataGrid控件样式
内容转自https://www.cnblogs.com/xiaogangqq123/archive/2012/05/07/2487166.html 一.DataGrid基本样式(一) 小刚已经把Dat ...
- 动手分析安卓仿QQ联系人列表TreeView控件
因项目需要需要用到仿QQ联系人列表的控件样式,于是网上找到一个轮子(https://github.com/TealerProg/TreeView),工作完成现在简单分析一下这个源码. 一. 需要用 ...
- WPF Calendar 日历控件 样式自定义
原文:WPF Calendar 日历控件 样式自定义 粗略的在代码上做了些注释 blend 生成出来的模版 有的时候 会生成 跟 vs ui界面不兼容的代码 会导致可视化设计界面 报错崩溃掉 但是确不 ...
- arcgis api for js共享干货系列之二自定义Navigation控件样式风格
arcgis api for js默认的Navigation控件样式风格如下图: 这样的风格不能说不好,各有各的爱好,审美观,这里也不是重点,这里的重点是如何自定义一套自己喜欢的样式风格呢:自己自定义 ...
- arcgis api 3.x for js 共享干货系列之二自定义 Navigation 控件样式风格(附源码下载)
0.内容概览 自定义 Navigation 控件样式风格 源码下载 1.内容讲解 arcgis api 3.x for js 默认的Navigation控件样式风格如下图:这样的风格不能说不好,各有各 ...
- WPF设置全局控件样式
原文:WPF设置全局控件样式 方法: 在资源文件APP.XAML中添加如下资源 <Application x:Class="_360UI.App" xmlns="h ...
随机推荐
- RabbitMQ的安装和配置
在Windows下进行rabbitMQ的安装 第一步:软件安装 如果安装rabbitMQ首先安装基于erlang语言支持的OTP软件,然后在下载rabbitMQ软件进行安装(安装过程都是下一步,在此不 ...
- 总结linux路由技术
Linux系统的route命令用于显示和操作IP路由表,要实现两个不同的网段之间的通信,需要一台连接两个网络的路由器,或者同时连接位于两个网络的网关来实现. 在Linux系统中,设置路由通常是为了解决 ...
- 目前微服务/REST的最佳技术栈
服务端 日期 编程语言 Web Framework DbAccess/ORM 数据库 2017-09-07 Node.js 8.4 Koa 2.3 sequelize 4.8 MySQL 2017-0 ...
- LeetCode-101.对称二叉树
链接:https://leetcode-cn.com/problems/symmetric-tree/description/ 给定一个二叉树,检查它是否是它自己的镜像(即,围绕它的中心对称). 例如 ...
- Sublime Text3下使用Python,REPL的安装与快捷键设置方法
前提条件:连接外网 1.安装管理插件(CTRL+SHIFT+P),找到Package Control:install package一项,回车后继续选择SublimeREPL插件,进行安装: ...
- 设置如何远程连接mysql数据库
安装好mysql5.6.37后,默认情况下,只允许本地登录,禁止远程登录. 可以现在本地安装好连接工具,比如sqlyog或者navicat 登陆后,切换至mysql数据库 执行下面2条语句 '; FL ...
- 第四十六条:for-each循环优先于传统的for循环
for(Elements e : list) { //doSomeThing-- }
- nyoj 疯牛
疯牛 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小 ...
- 策略模式(Stratety)
namespace StrategyPattern //策略模式 { /// <summary> /// 定义所以支持的算法的公共接口 /// </summary> abstr ...
- Python 列表嵌套多种实现方式
#coding=utf-8 list=[] for i in range(1,101): list.append(i) # print(list) tempList=[] newList=[] whi ...