当前位置: 移动技术网 > IT编程>开发语言>c# > WPF如何自定义TabControl控件样式示例详解

WPF如何自定义TabControl控件样式示例详解

2019年07月18日  | 移动技术网IT编程  | 我要评论

一、前言

程序中经常会用到tabcontrol控件,默认的控件样式很普通。而且样式或功能不一定符合我们的要求。比如:我们需要tabcontrol的标题能够居中、或平均分布;或者我们希望tabcontrol的标题能够进行关闭。要实现这些功能我们需要对tabcontrol的样式进行定义。

二、实现tabcontrol的标题平均分布

默认的tabcontrol标题是使用tabpanel容器包含的。要想实现tabcontrol标题头平均分布,需要把tabpanel替换成uniformgrid;

替换后的tabcontrol样式如下:

<style x:key="tabcontrolstyle" targettype="{x:type tabcontrol}">
  <setter property="padding" value="2"/>
  <setter property="horizontalcontentalignment" value="center"/>
  <setter property="verticalcontentalignment" value="center"/>
  <setter property="background" value="white"/>
  <setter property="borderbrush" value="#ffacacac"/>
  <setter property="borderthickness" value="1"/>
  <setter property="foreground" value="{dynamicresource {x:static systemcolors.controltextbrushkey}}"/>
  <setter property="template">
  <setter.value>
   <controltemplate targettype="{x:type tabcontrol}">
   <grid x:name="templateroot" cliptobounds="true" snapstodevicepixels="true" keyboardnavigation.tabnavigation="local">
    <grid.columndefinitions>
    <columndefinition x:name="columndefinition0"/>
    <columndefinition x:name="columndefinition1" width="0"/>
    </grid.columndefinitions>
    <grid.rowdefinitions>
    <rowdefinition x:name="rowdefinition0" height="auto"/>
    <rowdefinition x:name="rowdefinition1" height="*"/>
    </grid.rowdefinitions>
    <uniformgrid x:name="headerpanel" rows="1" background="transparent" grid.column="0" isitemshost="true" margin="0" grid.row="0" keyboardnavigation.tabindex="1" panel.zindex="1"/>
    <line x1="0" x2="{binding actualwidth, relativesource={relativesource self}}" stroke="white" strokethickness="0.1" verticalalignment="bottom" margin="0 0 0 1" snapstodevicepixels="true"/>
    <border x:name="contentpanel" borderbrush="{templatebinding borderbrush}" borderthickness="{templatebinding borderthickness}" background="{templatebinding background}" grid.column="0" keyboardnavigation.directionalnavigation="contained" grid.row="1" keyboardnavigation.tabindex="2" keyboardnavigation.tabnavigation="local">
    <contentpresenter x:name="part_selectedcontenthost" contenttemplate="{templatebinding selectedcontenttemplate}" content="{templatebinding selectedcontent}" contentstringformat="{templatebinding selectedcontentstringformat}" contentsource="selectedcontent" margin="0" snapstodevicepixels="{templatebinding snapstodevicepixels}"/>
    </border>
   </grid>
   <controltemplate.triggers>
    <trigger property="tabstripplacement" value="bottom">
    <setter property="grid.row" targetname="headerpanel" value="1"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="auto"/>
    </trigger>
    <trigger property="tabstripplacement" value="left">
    <setter property="grid.row" targetname="headerpanel" value="0"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="grid.column" targetname="headerpanel" value="0"/>
    <setter property="grid.column" targetname="contentpanel" value="1"/>
    <setter property="width" targetname="columndefinition0" value="auto"/>
    <setter property="width" targetname="columndefinition1" value="*"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="0"/>
    </trigger>
    <trigger property="tabstripplacement" value="right">
    <setter property="grid.row" targetname="headerpanel" value="0"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="grid.column" targetname="headerpanel" value="1"/>
    <setter property="grid.column" targetname="contentpanel" value="0"/>
    <setter property="width" targetname="columndefinition0" value="*"/>
    <setter property="width" targetname="columndefinition1" value="auto"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="0"/>
    </trigger>
    <trigger property="isenabled" value="false">
    <setter property="textelement.foreground" targetname="templateroot" value="{dynamicresource {x:static systemcolors.graytextbrushkey}}"/>
    </trigger>
   </controltemplate.triggers>
   </controltemplate>
  </setter.value>
  </setter>
 </style>

即使这样设置了,tabcontrol的标题还是很丑,这个时候就需要通过设置tabitem来更改标题样式了。

tabitem样式如下:

<style x:key="tabitemstyle" targettype="{x:type tabitem}">
  <setter property="foreground" value="white"/>
  <setter property="background" value="transparent"/>
  <setter property="borderbrush" value="#ffacacac"/>
  <setter property="margin" value="0"/>
  <setter property="horizontalcontentalignment" value="stretch"/>
  <setter property="verticalcontentalignment" value="stretch"/>
  <setter property="template">
  <setter.value>
   <controltemplate targettype="{x:type tabitem}">
   <grid x:name="templateroot" snapstodevicepixels="true" background="transparent">
    <textblock x:name="txt" visibility="visible" verticalalignment="center" horizontalalignment="center" text="{templatebinding header}" tooltip="{templatebinding header}" foreground="{templatebinding foreground}" texttrimming="characterellipsis" />
   </grid>
   <controltemplate.triggers>
    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding ismouseover, relativesource={relativesource self}}" value="true"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>
    </multidatatrigger.conditions>
    
    <setter property="foreground" targetname="txt" value="#fffea1"/>
    </multidatatrigger>
    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="left"/>
    </multidatatrigger.conditions>
    <setter property="opacity" targetname="templateroot" value="0.56"/>
    </multidatatrigger>
    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="bottom"/>
    </multidatatrigger.conditions>
    <setter property="opacity" targetname="templateroot" value="0.56"/>
    </multidatatrigger>
    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="right"/>
    </multidatatrigger.conditions>
    <setter property="opacity" targetname="templateroot" value="0.56"/>
    </multidatatrigger>
    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>
    </multidatatrigger.conditions>
    <setter property="opacity" targetname="templateroot" value="0.56"/>
    </multidatatrigger>

    <multidatatrigger>
    <multidatatrigger.conditions>
     <condition binding="{binding isselected, relativesource={relativesource self}}" value="true"/>
     <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>
    </multidatatrigger.conditions>
    <setter property="panel.zindex" value="1"/>
    <setter property="foreground" targetname="txt" value="#fffea1"/>
    </multidatatrigger>
   </controltemplate.triggers>
   </controltemplate>
  </setter.value>
  </setter>
 </style>

至此,样式已经设置完毕,引用示例:

<grid background="#858586">
  <tabcontrol style="{staticresource tabcontrolstyle}" width="300" height="200" background="transparent" borderbrush="transparent" borderthickness="0">
   <tabitem style="{staticresource tabitemstyle}" cursor="hand" header="音乐电台" height="38" >
   <grid background="#33ffffff">
    <textblock text="音乐电台" verticalalignment="center" horizontalalignment="center"/>
   </grid>
   </tabitem>
   <tabitem style="{staticresource tabitemstyle}" cursor="hand" header="mv电台" height="38" >
   <grid background="#33ffffff">
    <textblock text="mv电台" verticalalignment="center" horizontalalignment="center"/>
   </grid>
   </tabitem>
  </tabcontrol>
  </grid>

效果如下:

三、实现tabcontrol标题居中显示(不平均分布)

同理需要更改tabcontrol的样式和tabitem的样式。需要把使用tabpanel作为标题的容器,设置horizontalalignment为center;

tabcontrol的样式如下:

<style x:key="tabcontrolwithunderlinestyle" targettype="{x:type tabcontrol}">
 <setter property="padding" value="2"/>
 <setter property="horizontalcontentalignment" value="center"/>
 <setter property="verticalcontentalignment" value="center"/>
 <setter property="background" value="white"/>
 <setter property="borderbrush" value="#ffacacac"/>
 <setter property="borderthickness" value="1"/>
 <setter property="foreground" value="{dynamicresource {x:static systemcolors.controltextbrushkey}}"/>
 <setter property="template">
  <setter.value>
  <controltemplate targettype="{x:type tabcontrol}">
   <grid x:name="templateroot" cliptobounds="true" snapstodevicepixels="true" keyboardnavigation.tabnavigation="local">
   <grid.columndefinitions>
    <columndefinition x:name="columndefinition0"/>
    <columndefinition x:name="columndefinition1" width="0"/>
   </grid.columndefinitions>
   <grid.rowdefinitions>
    <rowdefinition x:name="rowdefinition0" height="auto"/>
    <rowdefinition x:name="rowdefinition1" height="*"/>
   </grid.rowdefinitions>
   <tabpanel x:name="headerpanel" horizontalalignment="center" background="transparent" grid.column="0" isitemshost="true" margin="0" grid.row="0" keyboardnavigation.tabindex="1" panel.zindex="1"/>
   <line x1="0" x2="{binding actualwidth, relativesource={relativesource self}}" stroke="gray" strokethickness="0.1" verticalalignment="bottom" margin="0 0 0 1" snapstodevicepixels="true"/>
   <border x:name="contentpanel" borderbrush="{templatebinding borderbrush}" borderthickness="{templatebinding borderthickness}" background="{templatebinding background}" grid.column="0" keyboardnavigation.directionalnavigation="contained" grid.row="1" keyboardnavigation.tabindex="2" keyboardnavigation.tabnavigation="local">
    <contentpresenter x:name="part_selectedcontenthost" contenttemplate="{templatebinding selectedcontenttemplate}" content="{templatebinding selectedcontent}" contentstringformat="{templatebinding selectedcontentstringformat}" contentsource="selectedcontent" margin="0" snapstodevicepixels="{templatebinding snapstodevicepixels}"/>
   </border>
   </grid>
   <controltemplate.triggers>
   <trigger property="tabstripplacement" value="bottom">
    <setter property="grid.row" targetname="headerpanel" value="1"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="auto"/>
   </trigger>
   <trigger property="tabstripplacement" value="left">
    <setter property="grid.row" targetname="headerpanel" value="0"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="grid.column" targetname="headerpanel" value="0"/>
    <setter property="grid.column" targetname="contentpanel" value="1"/>
    <setter property="width" targetname="columndefinition0" value="auto"/>
    <setter property="width" targetname="columndefinition1" value="*"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="0"/>
   </trigger>
   <trigger property="tabstripplacement" value="right">
    <setter property="grid.row" targetname="headerpanel" value="0"/>
    <setter property="grid.row" targetname="contentpanel" value="0"/>
    <setter property="grid.column" targetname="headerpanel" value="1"/>
    <setter property="grid.column" targetname="contentpanel" value="0"/>
    <setter property="width" targetname="columndefinition0" value="*"/>
    <setter property="width" targetname="columndefinition1" value="auto"/>
    <setter property="height" targetname="rowdefinition0" value="*"/>
    <setter property="height" targetname="rowdefinition1" value="0"/>
   </trigger>
   <trigger property="isenabled" value="false">
    <setter property="textelement.foreground" targetname="templateroot" value="{dynamicresource {x:static systemcolors.graytextbrushkey}}"/>
   </trigger>
   </controltemplate.triggers>
  </controltemplate>
  </setter.value>
 </setter>
 </style>

tabitem样式如下:

<style x:key="tabitemexwithunderlinestyle" targettype="{x:type tabitem}">
   <setter property="foreground" value="white"/>
   <setter property="background" value="transparent"/>
   <setter property="borderbrush" value="#ffacacac"/>
   <setter property="margin" value="0"/>
   <setter property="horizontalcontentalignment" value="stretch"/>
   <setter property="verticalcontentalignment" value="stretch"/>
   <setter property="template">
    <setter.value>
     <controltemplate targettype="{x:type tabitem}">
      <grid x:name="templateroot" snapstodevicepixels="true" background="transparent">
       <border x:name="_underline" borderbrush="#37aefe" borderthickness="0" margin="{templatebinding margin}"/>
       <grid>
        <textblock x:name="txt" visibility="visible" verticalalignment="center" horizontalalignment="center" text="{templatebinding header}" tooltip="{templatebinding header}" foreground="{templatebinding foreground}" texttrimming="characterellipsis" />
       </grid>
      </grid>
      <controltemplate.triggers>
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding ismouseover, relativesource={relativesource self}}" value="true"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>
        </multidatatrigger.conditions>

        <setter property="foreground" targetname="txt" value="#37aefe"/>
       </multidatatrigger>
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="left"/>
        </multidatatrigger.conditions>
        <setter property="opacity" targetname="templateroot" value="0.56"/>
       </multidatatrigger>
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="bottom"/>
        </multidatatrigger.conditions>
        <setter property="opacity" targetname="templateroot" value="0.56"/>
       </multidatatrigger>
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="right"/>
        </multidatatrigger.conditions>
        <setter property="opacity" targetname="templateroot" value="0.56"/>
       </multidatatrigger>
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding isenabled, relativesource={relativesource self}}" value="false"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>
        </multidatatrigger.conditions>
        <setter property="opacity" targetname="templateroot" value="0.56"/>
       </multidatatrigger>
       
       <multidatatrigger>
        <multidatatrigger.conditions>
         <condition binding="{binding isselected, relativesource={relativesource self}}" value="true"/>
         <condition binding="{binding tabstripplacement, relativesource={relativesource findancestor, ancestorlevel=1, ancestortype={x:type tabcontrol}}}" value="top"/>        </multidatatrigger.conditions>
        <setter property="panel.zindex" value="1"/>
        <setter property="foreground" targetname="txt" value="#37aefe"/>
        <setter property="borderthickness" targetname="_underline" value="0 0 0 2"/>
       </multidatatrigger>
      </controltemplate.triggers>
     </controltemplate>
    </setter.value>
   </setter>
  </style>

引用示例:

<grid background="#858586">
    <tabcontrol style="{staticresource tabcontrolwithunderlinestyle}" foreground="black" width="300" height="200" background="transparent" borderbrush="transparent" borderthickness="0">
     <tabitem style="{staticresource tabitemexwithunderlinestyle}" cursor="hand" header="音乐电台" height="38" width="70" margin="5 0">
      <grid background="#33ffffff">
       <textblock text="音乐电台" verticalalignment="center" horizontalalignment="center"/>
      </grid>
     </tabitem>
     <tabitem style="{staticresource tabitemexwithunderlinestyle}" cursor="hand" header="mv电台" height="38" width="70" margin="5 0">
      <grid background="#33ffffff">
       <textblock text="mv电台" verticalalignment="center" horizontalalignment="center"/>
      </grid>
     </tabitem>
    </tabcontrol>
   </grid>

效果如下:

四、带关闭按钮的tabcontrol

带关闭按钮的tabcontrol其实就是就是扩展tabitem,需要新建wpf自定义控件,命名为tabitemclose吧;

c#代码如下:

public class tabitemclose : tabitem
 {
  static tabitemclose()
  {
   defaultstylekeyproperty.overridemetadata(typeof(tabitemclose), new frameworkpropertymetadata(typeof(tabitemclose)));
  }

  private static void onpropertychanged(dependencyobject d, dependencypropertychangedeventargs e)
  {
   d.setvalue(e.property, e.newvalue);
  }

  /// <summary>
  /// 是否可以关闭
  /// </summary>
  public bool iscanclose
  {
   get { return (bool)getvalue(iscancloseproperty); }
   set { setvalue(iscancloseproperty, value); }
  }

  public static readonly dependencyproperty iscancloseproperty =
   dependencyproperty.register("iscanclose", typeof(bool), typeof(tabitemclose), new propertymetadata(true, onpropertychanged));

  /// <summary>
  /// 关闭的图标
  /// </summary>
  public imagesource closeicon
  {
   get { return (imagesource)getvalue(closeiconproperty); }
   set { setvalue(closeiconproperty, value); }
  }

  public static readonly dependencyproperty closeiconproperty =
   dependencyproperty.register("closeicon", typeof(imagesource), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));



  /// <summary>
  /// 正常背景色
  /// </summary>
  public solidcolorbrush normalbackground
  {
   get { return (solidcolorbrush)getvalue(normalbackgroundproperty); }
   set { setvalue(normalbackgroundproperty, value); }
  }

  public static readonly dependencyproperty normalbackgroundproperty =
   dependencyproperty.register("normalbackground", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));

  /// <summary>
  /// 悬浮背景色
  /// </summary>
  public solidcolorbrush overbackgound
  {
   get { return (solidcolorbrush)getvalue(overbackgoundproperty); }
   set { setvalue(overbackgoundproperty, value); }
  }

  public static readonly dependencyproperty overbackgoundproperty =
   dependencyproperty.register("overbackgound", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));


  /// <summary>
  /// 选中背景色
  /// </summary>
  public solidcolorbrush selectedbackgound
  {
   get { return (solidcolorbrush)getvalue(selectedbackgoundproperty); }
   set { setvalue(selectedbackgoundproperty, value); }
  }

  public static readonly dependencyproperty selectedbackgoundproperty =
   dependencyproperty.register("selectedbackgound", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));


  /// <summary>
  /// 默认前景色
  /// </summary>
  public solidcolorbrush normalforeground
  {
   get { return (solidcolorbrush)getvalue(normalforegroundproperty); }
   set { setvalue(normalforegroundproperty, value); }
  }

  public static readonly dependencyproperty normalforegroundproperty =
   dependencyproperty.register("normalforeground", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));

  /// <summary>
  /// 悬浮前景色
  /// </summary>
  public solidcolorbrush overforeground
  {
   get { return (solidcolorbrush)getvalue(overforegroundproperty); }
   set { setvalue(overforegroundproperty, value); }
  }

  public static readonly dependencyproperty overforegroundproperty =
   dependencyproperty.register("overforeground", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));

  /// <summary>
  /// 选中前景色
  /// </summary>
  public solidcolorbrush selectedforeground
  {
   get { return (solidcolorbrush)getvalue(selectedforegroundproperty); }
   set { setvalue(selectedforegroundproperty, value); }
  }

  public static readonly dependencyproperty selectedforegroundproperty =
   dependencyproperty.register("selectedforeground", typeof(solidcolorbrush), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));
  /// <summary>
  /// 控件圆角
  /// </summary>
  public cornerradius cornerradius
  {
   get { return (cornerradius)getvalue(cornerradiusproperty); }
   set { setvalue(cornerradiusproperty, value); }
  }
  public static readonly dependencyproperty cornerradiusproperty =
   dependencyproperty.register("cornerradius", typeof(cornerradius), typeof(tabitemclose), new propertymetadata(new cornerradius(0), onpropertychanged));
  /// <summary>
  /// 前置logo
  /// </summary>
  public imagesource logoicon
  {
   get { return (imagesource)getvalue(logoiconproperty); }
   set { setvalue(logoiconproperty, value); }
  }
  public static readonly dependencyproperty logoiconproperty =
   dependencyproperty.register("logoicon", typeof(imagesource), typeof(tabitemclose), new propertymetadata(null, onpropertychanged));
  /// <summary>
  /// 前置logo宽度
  /// </summary>
  public double logoiconwidth
  {
   get { return (double)getvalue(logoiconwidthproperty); }
   set { setvalue(logoiconwidthproperty, value); }
  }
  public static readonly dependencyproperty logoiconwidthproperty =
   dependencyproperty.register("logoiconwidth", typeof(double), typeof(tabitemclose), new propertymetadata(double.parse("0"), onpropertychanged));
  /// <summary>
  /// 前置logo高度
  /// </summary>
  public double logoiconheigth
  {
   get { return (double)getvalue(logoiconheigthproperty); }
   set { setvalue(logoiconheigthproperty, value); }
  }
  public static readonly dependencyproperty logoiconheigthproperty =
   dependencyproperty.register("logoiconheigth", typeof(double), typeof(tabitemclose), new propertymetadata(double.parse("0"), onpropertychanged));
  /// <summary>
  /// logopadding
  /// </summary>
  public thickness logopadding
  {
   get { return (thickness)getvalue(logopaddingproperty); }
   set { setvalue(logopaddingproperty, value); }
  }

  public static readonly dependencyproperty logopaddingproperty =
   dependencyproperty.register("logopadding", typeof(thickness), typeof(tabitemclose), new propertymetadata(new thickness(0), onpropertychanged));
  /// <summary>
  /// 关闭item事件
  /// </summary>
  public event routedeventhandler closeitem
  {
   add { addhandler(closeitemevent, value); }
   remove { removehandler(closeitemevent, value); }
  }
  public static readonly routedevent closeitemevent =
   eventmanager.registerroutedevent("closeitem", routingstrategy.bubble, typeof(routedeventhandler), typeof(tabitemclose));
  /// <summary>
  /// 关闭项的右键菜单
  /// </summary>
  public contextmenu itemcontextmenu { get; set; }

  border itemborder;
  public override void onapplytemplate()
  {
   base.onapplytemplate();
   itemborder = template.findname("_bordertop", this) as border;
   if (itemcontextmenu != null)
   {
    itemborder.contextmenu = itemcontextmenu;
   }
  }
 }

这里面我们添加了很多扩展功能,包括右键菜单,图标显示和控件圆角,以及各种背景色属性。

然后为tabitemclose设置样式

<style targettype="{x:type local:tabitemclose}">
  <setter property="horizontalcontentalignment" value="stretch"/>
  <setter property="verticalcontentalignment" value="stretch"/>
  <setter property="foreground" value="#666666"/>
  <setter property="margin" value="0 0 0 0"/>
  <setter property="padding" value="0"/>
  <setter property="borderthickness" value="0"/>
  <setter property="closeicon" value="/images/close2.png"/>
  <setter property="normalbackground" value="white"/>
  <setter property="overbackgound" value="#33ca5100"/>
  <setter property="selectedbackgound" value="#ca5100"/>
  <setter property="normalforeground" value="#555558"/>
  <setter property="overforeground" value="white"/>
  <setter property="selectedforeground" value="white"/>
  <setter property="template">
   <setter.value>
    <controltemplate targettype="{x:type local:tabitemclose}">
     <border x:name="_bordertop" width="{templatebinding width}" maxwidth="{templatebinding maxwidth}" height="{templatebinding height}" cornerradius="{templatebinding cornerradius}" background="{templatebinding normalbackground}" borderthickness="{templatebinding borderthickness}" borderbrush="{templatebinding borderbrush}" tooltip="{templatebinding header}" >
      <dockpanel>
       <image x:name="_logo" dockpanel.dock="left" visibility="visible" margin="{templatebinding logopadding}" source="{templatebinding logoicon}" verticalalignment="center" horizontalalignment="center" stretch="uniform" width="{templatebinding logoiconwidth}" height="{templatebinding logoiconheigth}" />
       <grid name="_grid" snapstodevicepixels="true">
        <grid.columndefinitions>
         <columndefinition width="*" />
         <columndefinition x:name="_col_close" width="20" />
        </grid.columndefinitions>
        <border grid.columnspan="2" background="white" opacity="0"/>
        <textblock x:name="_txt" verticalalignment="center" texttrimming="characterellipsis" margin="3 0 3 0" foreground="{templatebinding normalforeground}" textalignment="center" horizontalalignment="center" text="{templatebinding header}" />
        <grid x:name="_gridclose" grid.column="1" >
         <border x:name="_borderbg" background="black" opacity="0" />
         <local:buttonex x:name="part_close_tabitem" horizontalalignment="center" verticalalignment="center" background="transparent" visibility="visible" icon="{templatebinding closeicon}" buttontype="icon" />
        </grid>
       </grid>
      </dockpanel>

     </border>
     <controltemplate.triggers>
      <trigger property="logoicon" value="{x:null}">
       <setter targetname="_logo" property="visibility" value="collapsed" />
      </trigger>
      <trigger property="iscanclose" value="false">
       <setter targetname="_gridclose" property="visibility" value="collapsed"/>
       <setter targetname="_col_close" property="width" value="0"/>
      </trigger>
      <trigger property="isselected" value="true">
       <setter targetname="_bordertop" property="background" value="{binding selectedbackgound,relativesource={relativesource templatedparent}}" />
       <setter targetname="_txt" property="foreground" value="{binding selectedforeground,relativesource={relativesource templatedparent}}"/>
      </trigger>
      <multitrigger>
       <multitrigger.conditions>
        <condition property="ismouseover" value="true"/>
        <condition property="isselected" value="false"/>
       </multitrigger.conditions>
       <setter targetname="_txt" property="foreground" value="{binding overforeground,relativesource={relativesource templatedparent}}"/>
       <setter targetname="_bordertop" property="background" value="{binding overbackgound,relativesource={relativesource templatedparent}}"/>
      </multitrigger>
     </controltemplate.triggers>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

这里面使用了一个close的图标

tabcontrol的图标可设置可不设置,看自己需要。

这里面还用到了前面讲的控件buttonex,定义方法我就不重复赘述了。大家可以通过这个链接跳转查看:。buttonex.cs里面还要添加几个方法用来支持关闭tabitem:

protected override void onclick()
  {
   base.onclick();
   if (!string.isnullorempty(name) && name == "part_close_tabitem")
   {
    tabitemclose itemclose = findvisualparent<tabitemclose>(this);
    (itemclose.parent as tabcontrol).items.remove(itemclose);
    routedeventargs args = new routedeventargs(tabitemclose.closeitemevent, itemclose);
    itemclose.raiseevent(args);
   }
  }

  public static t findvisualparent<t>(dependencyobject obj) where t : class
  {
   while (obj != null)
   {
    if (obj is t)
     return obj as t;

    obj = visualtreehelper.getparent(obj);
   }
   return null;
  }

引用示例:

<grid background="#858586">
    <tabcontrol foreground="black" width="300" height="200" background="transparent" borderbrush="transparent" borderthickness="0">
     <local:tabitemclose cursor="hand" header="音乐电台" height="20" width="100">
      <grid background="#aaffffff">
       <textblock text="音乐电台" verticalalignment="center" horizontalalignment="center"/>
      </grid>
     </local:tabitemclose>
     <local:tabitemclose cursor="hand" header="mv电台" height="20" width="100">
      <grid background="#aaffffff">
       <textblock text="mv电台" verticalalignment="center" horizontalalignment="center"/>
      </grid>
     </local:tabitemclose>
    </tabcontrol>
   </grid>

效果如下:

总结

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网