服务器之家

服务器之家 > 正文

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

时间:2022-02-23 13:28     来源/作者:小明GG

一、前言

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

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

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

替换后的tabcontrol样式如下:

?
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
<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样式如下:

?
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
<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>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

效果如下:

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

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

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

tabcontrol的样式如下:

?
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
<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样式如下:

?
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
<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>

引用示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

效果如下:

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

四、带关闭按钮的tabcontrol

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

c#代码如下:

?
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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设置样式

?
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
<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的图标

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

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

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

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

引用示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

效果如下:

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

总结

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

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

标签:

相关文章

热门资讯

蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整
蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整 2021-08-24
2022年最旺的微信头像大全 微信头像2022年最新版图片
2022年最旺的微信头像大全 微信头像2022年最新版图片 2022-01-10
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
返回顶部