WPF的TabControl样式模板处理

旧地址:http://blog.canself.com/wpftabcontrol/

在WPF中,想要改变TabControl的样子要比在Winform中方便很多,但往往也有很多种方式处理。

首先,我们进行常规的处理方式,下面介绍两种:

第一种是直接修改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
<Style x:Key="TabItemStyle_Normal" TargetType="{x:Type TabItem}">
<Style.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="#8C8E94"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
<ContentPresenter x:Name="Content" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Height" Value="40"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Background" Value="Blue"/>
</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
<Style x:Key="TabItemStyle_Normal2" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="#8C8E94"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Padding="{TemplateBinding Padding}" Background="Gray">
<ContentPresenter x:Name="Content" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="Bd" Value="LightYellow"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Background" TargetName="Bd" Value="LightBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="200"/>
</Style>

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<TabControl TabStripPlacement="Left" BorderThickness="1,1,5,1">
<TabItem Header="常规1" Style="{DynamicResource TabItemStyle_Normal}">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="常规2" Style="{DynamicResource TabItemStyle_Normal}">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="常规3" Style="{DynamicResource TabItemStyle_Normal2}" >
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="常规4" Style="{DynamicResource TabItemStyle_Normal2}" >
<Grid Background="#FFE5E5E5"/>
</TabItem>
</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
<Style x:Key="TabItemStyle_Special" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="#8C8E94"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true">
<Border x:Name="first" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" Visibility="Visible">
<TextBlock x:Name="Content1" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Text="{TemplateBinding Header}" Foreground="White"/>
</Border>
<Border x:Name="second" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}" Visibility="Collapsed">
<TextBlock x:Name="Content2" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Text="{TemplateBinding Header}" Foreground="White"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="first">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#EAF6FD" Offset="0.15"/>
<GradientStop Color="#D9F0FC" Offset=".5"/>
<GradientStop Color="#BEE6FD" Offset=".5"/>
<GradientStop Color="#A7D9F5" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Visibility" TargetName="first" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="second" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Background" TargetName="first" Value="#F9F9F9"/>
<Setter Property="Visibility" TargetName="first" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="second" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="200"/>
</Style>

使用:

1
2
3
4
5
6
7
8
<TabControl Grid.Column="1" TabStripPlacement="Right" BorderThickness="5,1,1,1">
<TabItem Header="特殊1" Style="{DynamicResource TabItemStyle_Special}" Background="Blue" Foreground="Green">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="特殊2" Style="{DynamicResource TabItemStyle_Special}" Background="Yellow" Foreground="Red">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>

下图是测试结果图:其中常规1、2使用样式修改;常规3、4使用模板修改;特殊1、2为特殊方式处理。其中包含两个效果【MouseOver和Selected】


Windows Form中的TabControl重绘

旧地址:http://blog.canself.com/drawtabcontrol/

最近整理自己工作以来的旧项目,将其中的一些技术点整理出来。这个tabcontrol重绘相关的项目是自己毕业不久就做的一个,针对这个项目后面还有wpf版,暂且不提,暂时先看这个。

下面是软件的主界面,当然这个重绘的还不够完全,针对tabcontrol边框的处理还不好。

可以看出,也有一定效果的。😉

下面说说步骤,看看代码:

1、首先就是设置tabcontrol的drawmode属性,使其重绘有效。

1
this.tabc_draw.DrawMode = TabDrawMode.OwnerDrawFixed;

2、写tabcontrol的drawitem事件。

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
void tabc_draw_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;

TabPage changedpage = tabc_draw.TabPages[e.Index];//当前处理标签
Rectangle backrect = tabc_draw.GetTabRect(e.Index);//标签背景区域
Brush backbrush;//标签背景色
Brush fontbrush;//标签字体颜色
Font tabFont;//标签字体
Pen borderpen;//边框颜色

//TabControl绘制
Brush backtabcontrol = new SolidBrush(Color.Black);
g.FillRectangle(backtabcontrol, this.tabc_draw.ClientRectangle.X + 100, this.tabc_draw.ClientRectangle.Y, this.tabc_draw.ClientRectangle.Size.Width, this.tabc_draw.ItemSize.Height);
backtabcontrol.Dispose();

if (e.State == DrawItemState.Selected)
{
backbrush = new SolidBrush(Color.Black);
fontbrush = new SolidBrush(Color.Yellow);
tabFont = new Font("宋体", 15, FontStyle.Bold, GraphicsUnit.Pixel);
borderpen = new Pen(Color.LightBlue);
}
else
{
backbrush = new SolidBrush(Color.White);
fontbrush = new SolidBrush(Color.Red);
tabFont = new Font("楷体", 15, FontStyle.Bold, GraphicsUnit.Pixel);
borderpen = new Pen(Color.DarkGreen);
}
//绘制标签背景
g.FillRectangle(backbrush, backrect);

//绘制标签字体
StringFormat _StringFlags = new StringFormat();
_StringFlags.Alignment = StringAlignment.Center;
_StringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(changedpage.Text, tabFont, fontbrush, backrect, new StringFormat(_StringFlags));
//绘制非标签原始名称【可依据e.State修改】 g.DrawString("呵呵", tabFont, fontbrush, backrect, new StringFormat(_StringFlags));

//绘制标签边框
//backrect.Offset(1, 1);
//backrect.Inflate(2, 2);
g.DrawRectangle(borderpen, backrect);

backbrush.Dispose();
tabFont.Dispose();
fontbrush.Dispose();
borderpen.Dispose();
}

注释都在代码里了,就不详述了。下面是最后的效果的【只是简单的实现,自己多写写,模仿下就可以写出好效果啦】

修改outlook中ost文件位置

旧地址:http://blog.canself.com/modifyostpath/

outlook2013没法直接修改ost文件位置,故修改注册表以使outlook可以配置ost文件目录。

修改注册表内容如下:

1
2
3
位置:HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Outlook
键:ForcePSTPath
值:D:\DataFiles\EmailFiles

以下是bat文件,可以直接下载双击使用:下载地址1下载地址2

其他解决方案网址:

运用组策略修改Outlook 2013默认的ost数据文件位置

如何修改Outlook2013数据文件(.ost)位置的方法

一些有用的DOS相关命令

旧地址:http://blog.canself.com/somedos/

驱动器格式转换:

1
convert x: /fs:ntfs

修改文件后缀名:

1
ren *.* *.jpg

一键清理bat内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@echo off
echo 正在清理系统垃圾文件,请稍等......
del /f /s /q %systemdrive%\*.tmp
del /f /s /q %systemdrive%\*._mp
del /f /s /q %systemdrive%\*.log
del /f /s /q %systemdrive%\*.gid
del /f /s /q %systemdrive%\*.chk
del /f /s /q %systemdrive%\*.old
del /f /s /q %systemdrive%\recycled\*.*
del /f /s /q %windir%\*.bak
del /f /s /q %windir%\prefetch\*.*
rd /s /q %windir%\temp & md %windir%\temp
del /f /q %userprofile%\cookies\*.*
del /f /q %userprofile%\recent\*.*
del /f /s /q "%userprofile%\Local Settings\Temporary Internet Files\*.*"
del /f /s /q "%userprofile%\Local Settings\Temp\*.*"
del /f /s /q "%userprofile%\recent\*.*"
echo 清理系统垃圾完成!
echo. & pause

解决Outlook 2013无法删除问题

旧地址:http://blog.canself.com/outlook2013_del_error/

问题描述:使用qq邮箱时,删除邮件【del或右键删除】,总是提示“无法执行操作,因为对象已被删除”。

原因:个人一直以为是自己倒腾outlook修改存放路径,经常添加删除账户导致的,但网上查询问题时,又感觉其他人好像不是这个原因——故无法确定原因。

解决:

初始解决方案【非根本方法】:自己瞎倒腾,彻底删除——直接按shift+delete。

最终解决方案【完全解决】:在视图里设置显示为对话——可以把勾选在去掉——问题已经解决。

参考网址:无法执行操作 因为对象已被删除