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 ...
随机推荐
- Vmware虚拟机不能使用键盘的解决方法
有个笔记本thinkpad T440要重装系统,但又怕前面的资料丢失,因此打算直接将整个物理机迁移到VCenter 6.5上去,比GHOST什么的方便多了,利用Vmware Convert工具直接在线 ...
- linux下tomcat无法访问问题(换一种说法:无法访问8080端口)
有时候linux下的tomcat其他机器无法访问,比如主机无法访问linux虚拟机的tomcat,这是因为tocat的端口,linux没有对外开放,所以只能localhost访问,但是别的机器访问不了 ...
- Spring MVC的handlermapping之RequestMappingHandlerMapping初始化
RequestMappingHandlerMapping:这个handlerMapping是基于注解的同样,先上类图: 通过类图可以看到,同样是继承父类 AbstractHandlerMapping来 ...
- (译文)开始学习Vue——构建你的第一个Vue应用
我们要构建如下组件:(最终代码在这里:https://codesandbox.io/s/38k1y8x375) 开始 Vue是支持单文件组件的,但是我们不准备这么做.你也可以构建一个全局的组件,通过V ...
- hibernate框架学习笔记5:缓存
缓存不止存在与程序中,电脑硬件乃至于生活中都存在缓存 目的:提高效率 比如IO流读写字节,如果没有缓存,读一字节写一字节,效率低下 hibernate中的一级缓存:提高操作数据库的效率 示例: 抽取的 ...
- Beta总结
45°炸 031502601 蔡鸿杰 031502604 陈甘霖 031502632 伍晨薇 一.写在Beta项目前 Beta 凡 事 预 则 立 二.GitHub传送门 Beta冲刺重要版本 三.用 ...
- Beta阶段敏捷冲刺报告-DAY2
Beta阶段敏捷冲刺报告-DAY2 Scrum Meeting 敏捷开发日期 2017.11.3 会议时间 13:00 会议地点 微信群 参会人员 项目组全体成员 会议内容 打包问题修复, 爬虫优化, ...
- SQL数据库开发中的一些经典代码
1.按姓氏笔画排序: Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as 2.数据库加密: ...
- scrapy crawl 源码修改 爬虫多开
import os from scrapy.commands import ScrapyCommand from scrapy.utils.conf import arglist_to_dict fr ...
- C# 封装miniblink 使用HTML/CSS/JS来构建.Net 应用程序界面和简易浏览器
MiniBlink的作者是 龙泉寺扫地僧 miniblink是什么? (抄了一下 龙泉寺扫地僧 写的简洁) Miniblink是一个全新的.追求极致小巧的浏览器内核项目,其基于chromium最新 ...