服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - WPF自定义TreeView控件样式实现QQ联系人列表效果

WPF自定义TreeView控件样式实现QQ联系人列表效果

2022-02-23 13:29小明GG C#

TreeView控件在项目中使用比较频繁,下面这篇文章主要给大家介绍了关于WPF自定义TreeView控件样式实现QQ联系人列表效果的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。

一、前言

treeview这个控件对于我来说是用得比较多的,以前做的小聊天软件(好友列表)、音乐播放器(播放列表)、类库展示器(树形类结构)等都用的是treeview,普通的treeview并不能满足我们的需求。因此我们需要滴对treeview进行改造。下面的内容将介绍仿qq联系人treeview样式及treeview数据绑定方法。

二、treeview仿qq联系人列表

准确的说不是仿qq联系人列表,这个treeview样式作为组织架构来使用更好。废话不多说,先看效果:

WPF自定义TreeView控件样式实现QQ联系人列表效果

 2.1、基本思路

像这种联系人列表一般涉及到多层级数据,而且有很多数据是需要动态更新的,如果通过手动一条条增加数据反而更复杂,而且不方便。因此为了绑定数据方便我们使用分层模板hierarchicaldatatemplate。

分层模板中存在两种样式,一种是分组样式,一种是人员样式。不管是分组还是人员绑定的都是对象,这样我们在对象中添加一个属性来辨别是否为分组-isgrouping。

默认的treeview控件四周会有边距,因此需要设置下treeview的样式。另外鼠标经过和鼠标选中的背景色需要变化,因此还需要设置treeviewitem的样式。

根据思路,我们需要设置三个样式,treeview样式,treeviewitem样式,hierarchicaldatatemplate分层模板样式。另外为了自动计算下一级的边距,我们需要添加一个转换器indentconverter。还需要一个转换器需要将布尔类型的isgrouping转换为visibility,还需要一个转换器来对visibility取反。

这样三个样式,三个转换器。就可以实现我们上面的效果,另外还可以进行动态数据绑定。

2.2、样式代码

hierarchicaldatatemplate分层模板样式代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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样式代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<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样式代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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、转换器代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class indentconverter : ivalueconverter
 {
  public object convert(object value, type targettype, object parameter, cultureinfo culture)
  {
   double colunwidth = 10;
   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, 0, 0, 0);
  }
 
  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、引用示例

?
1
2
<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、初始化数据源及绑定对象

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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=3
        }
       }
      }
     },
    }
 
   };
   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; }
  }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/xiaomingg/p/8765802.html

延伸 · 阅读

精彩推荐
  • C#C#直线的最小二乘法线性回归运算实例

    C#直线的最小二乘法线性回归运算实例

    这篇文章主要介绍了C#直线的最小二乘法线性回归运算方法,实例分析了给定一组点,用最小二乘法进行线性回归运算的实现技巧,具有一定参考借鉴价值,需要...

    北风其凉8912021-10-18
  • C#C#基础之泛型

    C#基础之泛型

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能。接下来通过本文给大家介绍c#基础之泛型,感兴趣的朋友一起学习吧...

    方小白7732021-12-03
  • C#聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题,新手速来围观,一个通俗易懂的例子帮助大家更好的理解C#接口问题,感兴趣的小伙伴们可以参考一下...

    zenkey7072021-12-03
  • C#Unity3D UGUI实现缩放循环拖动卡牌展示效果

    Unity3D UGUI实现缩放循环拖动卡牌展示效果

    这篇文章主要为大家详细介绍了Unity3D UGUI实现缩放循环拖动展示卡牌效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    诗远3662022-03-11
  • C#C# 后台处理图片的几种方法

    C# 后台处理图片的几种方法

    本篇文章主要介绍了C# 后台处理图片的几种方法,非常具有实用价值,需要的朋友可以参考下。...

    IT小伙儿10162021-12-08
  • C#c#学习之30分钟学会XAML

    c#学习之30分钟学会XAML

    一个界面程序的核心,无疑就是界面和后台代码,而xaml就是微软为构建应用程序界面而创建的一种描述性语言,也就是说,这东西是搞界面的...

    C#教程网8812021-12-10
  • C#C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    这篇文章主要介绍了C#实现的文件操作封装类,结合完整实例形式分析了C#封装文件的删除,移动,复制,重命名等操作相关实现技巧,需要的朋友可以参考下...

    Rising_Sun3892021-12-28
  • C#浅谈C# winForm 窗体闪烁的问题

    浅谈C# winForm 窗体闪烁的问题

    下面小编就为大家带来一篇浅谈C# winForm 窗体闪烁的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网7962021-12-21