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

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

服务器之家 - 编程语言 - C# - WPF如何自定义TabControl控件样式示例详解

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

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

这篇文章主要给大家介绍了关于WPF如何自定义TabControl控件样式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

一、前言

程序中经常会用到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

延伸 · 阅读

精彩推荐
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28