好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

一、前言

程序中经常会用到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,定义方法我就不重复赘述了。大家可以通过这个链接跳转查看: http://HdhCmsTestzzvips测试数据/article/226264.html 。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>

效果如下:

总结

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

原文链接:http://HdhCmsTestcnblogs测试数据/xiaomingg/p/8870825.html

dy("nrwz");

查看更多关于WPF如何自定义TabControl控件样式示例详解的详细内容...

  阅读:56次