当前位置: 移动技术网 > IT编程>开发语言>c# > WPF自定义TreeView控件样式实现QQ联系人列表效果

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

2019年07月18日  | 移动技术网IT编程  | 我要评论
一、前言 treeview这个控件对于我来说是用得比较多的,以前做的小聊天软件(好友列表)、音乐播放器(播放列表)、类库展示器(树形类结构)等都用的是treeview

一、前言

treeview这个控件对于我来说是用得比较多的,以前做的小聊天软件(好友列表)、音乐播放器(播放列表)、类库展示器(树形类结构)等都用的是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 = 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、引用示例

 <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=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; }
  }

总结

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网