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

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.tuohang.net/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#c#学习之30分钟学会XAML

    c#学习之30分钟学会XAML

    一个界面程序的核心,无疑就是界面和后台代码,而xaml就是微软为构建应用程序界面而创建的一种描述性语言,也就是说,这东西是搞界面的...

    C#教程网8812021-12-10
  • C#浅谈C# winForm 窗体闪烁的问题

    浅谈C# winForm 窗体闪烁的问题

    下面小编就为大家带来一篇浅谈C# winForm 窗体闪烁的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网7962021-12-21
  • C#C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    这篇文章主要介绍了C#实现的文件操作封装类,结合完整实例形式分析了C#封装文件的删除,移动,复制,重命名等操作相关实现技巧,需要的朋友可以参考下...

    Rising_Sun3892021-12-28
  • C#Unity3D UGUI实现缩放循环拖动卡牌展示效果

    Unity3D UGUI实现缩放循环拖动卡牌展示效果

    这篇文章主要为大家详细介绍了Unity3D UGUI实现缩放循环拖动展示卡牌效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    诗远3662022-03-11
  • C#C#直线的最小二乘法线性回归运算实例

    C#直线的最小二乘法线性回归运算实例

    这篇文章主要介绍了C#直线的最小二乘法线性回归运算方法,实例分析了给定一组点,用最小二乘法进行线性回归运算的实现技巧,具有一定参考借鉴价值,需要...

    北风其凉8912021-10-18
  • C#C#基础之泛型

    C#基础之泛型

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能。接下来通过本文给大家介绍c#基础之泛型,感兴趣的朋友一起学习吧...

    方小白7732021-12-03
  • C#聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题,新手速来围观,一个通俗易懂的例子帮助大家更好的理解C#接口问题,感兴趣的小伙伴们可以参考一下...

    zenkey7072021-12-03
  • C#C# 后台处理图片的几种方法

    C# 后台处理图片的几种方法

    本篇文章主要介绍了C# 后台处理图片的几种方法,非常具有实用价值,需要的朋友可以参考下。...

    IT小伙儿10162021-12-08