WPF桌面端开发16-自定义组件及全局样式设置

样式生效范围

根据生效范围从大到小依次为

  • Application.Resources(所有页面生效)
  • Window.Resources(当前页面生效)
  • 组件内设置(当前组件生效)

Resources

1
2
3
4
5
6
7
8
9
<Window.Resources>
<Style x:Key="BigFontButtonStyle">
<Setter Property="Control.FontSize" Value="18"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid >
<Button Style="{StaticResource BigFontButtonStyle}" />
</Grid>

或者

1
2
3
4
5
6
<Window.Resources>
<Style x:Key="BigFontButtonStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Window.Resources>

组件内设置

1
2
3
4
5
6
7
<TextBlock Text="组件样式">
<TextBlock.Style>
<Style>
<Setter Property="TextBlock.FontSize" Value="36" />
</Style>
</TextBlock.Style>
</TextBlock>

全部生效和引用生效

全部生效

1
2
3
4
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="30" />
<Setter Property="FontWeight" Value="Bold" />
</Style>

注意

只要不设置x:Key,那么这个样式就会对所生效范围的所有组件生效,要只对某个生效就要设置x:Key

全部生效的尽量不要设置太基础的组件,比如如果设置了TextBlock,所有的Button的文字样式也会变化。

设置x:Key后必须引用才能生效

1
2
3
4
<Style x:Key="ZTextBlock" TargetType="TextBlock">
<Setter Property="FontSize" Value="30" />
<Setter Property="FontWeight" Value="Bold" />
</Style>

引用

1
2
3
4
<TextBlock
Margin="10"
Style="{StaticResource MTextBlock}"
Text="123" />

样式资源的合并

我们可以定义这样的文件StyleDefault.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="ZTextBlock" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#333333" />
</Style>

<Style x:Key="ZTextBox" TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#333333" />
<Setter Property="Background" Value="#F5F7F9" />
<Setter Property="BorderBrush" Value="#DDDDDD" />
</Style>
</ResourceDictionary>

在使用的时候进行合并

OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
9
10
11
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:ZView">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/StyleDefault.xaml" />
</ResourceDictionary.MergedDictionaries>

<!--对所有组件生效-->
<Style BasedOn="{StaticResource ZTextBox}" TargetType="TextBox" />
<Style BasedOn="{StaticResource MyButton}" TargetType="Button" />
</ResourceDictionary>

Application中引用

1
2
3
4
5
6
7
8
9
10
11
12
13
<Application
x:Class="SchoolClient.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Wins/Z.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/OverwrideDefaultControlStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

样式和模板

设置样式的时候我们可以设置样式和模板。

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
<Style
x:Key="SimpleButton"
BasedOn="{x:Null}"
TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource NormalBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource NormalBorderBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Grid">
<Border
x:Name="Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PressedBorderBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

自定义组件

项目下添加Resources文件夹,添加以下文件

简单的按钮示例

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
<Window.Resources>
<Style
x:Key="JianButton"
BasedOn="{x:Null}"
TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Name="ZBorder"
Width="34"
Height="34"
BorderBrush="#2D8CF0"
BorderThickness="1"
CornerRadius="17">
<Image
Width="14"
Height="14"
Source="/Images/Login/jianhao.png" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ZBorder" Property="Background" Value="#E2F0FF" />
</Trigger>

<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ZBorder" Property="Background" Value="#bdddff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>

使用

1
<Button Style="{StaticResource JianButton}" />

自定义Button

/Resources/StyleButton.xaml

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
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MyButton" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="#2D8CF0" />
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ClipToBounds="True"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>

<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.6" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

/Resources/OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleButton.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style BasedOn="{StaticResource MyButton}" TargetType="Button" />
</ResourceDictionary>

自定义圆角Button

Button实现圆角很简单只需Button ContentTemplate修改样式模板就可以实现了。

但是这样无法达到复用,比如另一个按钮设计的不需要圆角样式又用的同一套怎么办?

当然可以在把样式复制下然后改一个样式名字修改下样式就可以了。

但是这样两份样式几乎一样,只不过一个圆角一个不是。

所以我们可以通过自定义Button控件给Button新增一个依赖属性完成这个功能。

添加属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Windows;
using System.Windows.Controls;

namespace ColorPicker.Views
{
internal class ZRoundButton : Button
{
#region 属性
public static readonly DependencyProperty BorderRadiusProperty = DependencyProperty.Register("BorderRadius", typeof(int), typeof(ZRoundButton), new FrameworkPropertyMetadata());

public int BorderRadius
{
get { return (int)GetValue(BorderRadiusProperty); }
set { SetValue(BorderRadiusProperty, value); }
}
#endregion 属性
}
}

定义样式

/Resources/StyleZRoundButton.xaml

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
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SchoolClient.Views">
<Style x:Key="ZRoundButtonStyle" TargetType="{x:Type local:ZRoundButton}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{Binding Path=BorderRadius, RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

/Resources/OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
9
10
11
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ColorPicker.Views">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleZRoundButton.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style BasedOn="{StaticResource ZRoundButtonStyle}" TargetType="local:ZRoundButton" />
</ResourceDictionary>

全局引用

Application中添加引用

1
2
3
4
5
6
7
8
9
<Application
x:Class="SchoolClient.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Wins/Welcome.xaml">
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/Resources/OverwrideDefaultControlStyles.xaml" />
</Application.Resources>
</Application>

使用

定义好这个属性就可以在控件中使用了

1
2
3
4
5
6
7
8
9
10
<view:ZRoundButton
BorderRadius="23"
Width="300"
Height="46"
HorizontalAlignment="Center"
Background="#4597FF"
Content="关闭"
Cursor="Hand"
FontSize="20"
Foreground="White"/>

其中主要是BorderRadius="5"用来调整圆角。

我们再看看以前要实现就需要以下的代码,是不是感觉比以前简便多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Button
Width="300"
Height="46"
Content="关闭"
Cursor="Hand"
FontSize="20"
Foreground="White">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border
BorderBrush="{TemplateBinding Control.BorderBrush}"
BorderThickness="0"
CornerRadius="23">
<Border.Background>#4597FF</Border.Background>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding ContentControl.Content}" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>

自定义ListBoxItem

/Resources/StyleListBoxItem.xaml

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
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ListBoxItemContainerStyle1" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
Name="Border"
Padding="0,0,0,0"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<ControlTemplate x:Key="ListBoxTemplate" TargetType="{x:Type ListBox}">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<WrapPanel
IsItemsHost="True"
Orientation="Horizontal"
ScrollViewer.CanContentScroll="True" />
</ScrollViewer>
</ControlTemplate>
</ResourceDictionary>

/Resources/OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleListBoxItem.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style BasedOn="{StaticResource ListBoxItemContainerStyle1}" TargetType="ListBoxItem" />
</ResourceDictionary>

使用

1
2
3
4
5
6
7
8
9
<ListBox
x:Name="toolbar_list"
Margin="10,0,10,0"
Background="#f3f3f3"
BorderThickness="0"
ItemContainerStyle="{StaticResource ListBoxItemContainerStyle1}"
ItemTemplate="{StaticResource UserItemTemp}"
ItemsSource="{Binding userList}"
Template="{StaticResource ListBoxTemplate}" />

报错

System.Windows.Data Error: 4 : Cannot find source for binding with reference ‘RelativeSource FindAncestor, AncestorType=’System.Windows.Controls.ItemsControl’, AncestorLevel=’1’’. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is ‘ComboBoxItem’ (Name=’’); target property is ‘HorizontalContentAlignment’ (type ‘HorizontalAlignment’)

原因是ListBoxItem必须包含下面的两个属性

1
2
3
4
5
6
7

<Style
x:Key="ZItemContainerStyle"
TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top"/>
</Style>

and use it:

1
<ListView ItemContainerStyle="{StaticResource ZItemContainerStyle}"/>

内部裁剪的Border

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
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace ZJClassTool.Views
{
public class ZClippingBorder : Border
{
private object _oldClip;

protected override void OnRender(DrawingContext dc)
{
OnApplyChildClip();
base.OnRender(dc);
}

public override UIElement Child
{
get => base.Child;
set
{
if (Child != value)
{
if (Child != null)
{
Child.SetValue(ClipProperty, _oldClip);
}

if (value != null)
{
_oldClip = value.ReadLocalValue(ClipProperty);
}
else
{
// If we dont set it to null we could leak a Geometry object
_oldClip = null;
}

base.Child = value;
}
}
}

protected virtual void OnApplyChildClip()
{
UIElement child = Child;
if (child != null)
{
double top = Math.Max(CornerRadius.TopLeft, CornerRadius.TopRight);
double bottom = Math.Max(CornerRadius.BottomLeft, CornerRadius.BottomRight);
double max = Math.Max(top, bottom);
Size size = RenderSize;
double width = size.Width - (BorderThickness.Left + BorderThickness.Right);
double height = size.Height - (BorderThickness.Top + BorderThickness.Bottom);
Geometry result = new RectangleGeometry(new Rect(0, 0, width, height), max, max);
double halfWidth = width / 2;
double halfHeight = height / 2;

if (CornerRadius.TopLeft == 0)
{
result = new CombinedGeometry(
GeometryCombineMode.Union,
result,
new RectangleGeometry(new Rect(0, 0, halfWidth, halfHeight))
);
}

if (CornerRadius.TopRight == 0)
{
result = new CombinedGeometry(GeometryCombineMode.Union, result, new RectangleGeometry
(new Rect(halfWidth, 0, halfWidth, halfHeight)));
}

if (CornerRadius.BottomLeft == 0)
{
result = new CombinedGeometry
(GeometryCombineMode.Union, result, new RectangleGeometry
(new Rect(0, halfHeight, halfWidth, halfHeight)));
}
if (CornerRadius.BottomRight == 0)
{
result = new CombinedGeometry
(
GeometryCombineMode.Union,
result,
new RectangleGeometry(new Rect(halfWidth, halfHeight, halfWidth, halfHeight))
);
}
child.Clip = result;
}
}
}
}

调用方式

引用

1
xmlns:util="clr-namespace:ZJClassTool.Utils"

使用

1
2
3
4
5
6
<Views:ZClippingBorder
Background="#fafafa"
BorderBrush="#409DFE"
BorderThickness="2"
CornerRadius="10">
</Views:ZClippingBorder>

自定义滚动条

/Resources/StyleScrolllview.xaml

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
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- ScrollViewer 滚动条 -->
<Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Grid>
<Rectangle
Fill="#90000000"
RadiusX="5"
RadiusY="5" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="HorizontalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="false" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Opacity" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Fill="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="VerticalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="false" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Opacity" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Fill="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="for_scrollbar" TargetType="{x:Type ScrollBar}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
<Setter Property="Stylus.IsFlicksEnabled" Value="false" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Margin" Value="0,1,1,6" />
<Setter Property="Width" Value="10" />
<Setter Property="MinWidth" Value="10" />
<Setter Property="Opacity" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg" SnapsToDevicePixels="true">
<Track
x:Name="PART_Track"
IsDirectionReversed="true"
IsEnabled="{TemplateBinding IsMouseOver}">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageUpCommand}" Style="{StaticResource VerticalScrollBarPageButton}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageDownCommand}" Style="{StaticResource VerticalScrollBarPageButton}" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumb}" />
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Margin" Value="1,0,6,1" />
<Setter Property="Height" Value="10" />
<Setter Property="MinHeight" Value="10" />
<Setter Property="Width" Value="Auto" />
<Setter Property="Opacity" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg" SnapsToDevicePixels="true">
<Track x:Name="PART_Track" IsEnabled="{TemplateBinding IsMouseOver}">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageLeftCommand}" Style="{StaticResource HorizontalScrollBarPageButton}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageRightCommand}" Style="{StaticResource HorizontalScrollBarPageButton}" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumb}" />
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>

<!-- ScrollViewer -->
<Style x:Key="for_scrollviewer" TargetType="{x:Type ScrollViewer}">
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<Grid Background="{TemplateBinding Background}">
<ScrollContentPresenter
Margin="{TemplateBinding Padding}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}" />
<ScrollBar
x:Name="PART_VerticalScrollBar"
HorizontalAlignment="Right"
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
Style="{StaticResource for_scrollbar}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar
x:Name="PART_HorizontalScrollBar"
VerticalAlignment="Bottom"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
Style="{StaticResource for_scrollbar}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="ScrollChanged">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="PART_VerticalScrollBar"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0:0:1" />
<DoubleAnimation
BeginTime="0:0:1"
Storyboard.TargetName="PART_VerticalScrollBar"
Storyboard.TargetProperty="Opacity"
To="0.5"
Duration="0:0:1" />
<DoubleAnimation
Storyboard.TargetName="PART_HorizontalScrollBar"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0:0:1" />
<DoubleAnimation
BeginTime="0:0:1"
Storyboard.TargetName="PART_HorizontalScrollBar"
Storyboard.TargetProperty="Opacity"
To="0.5"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

全局样式设置

/Resources/OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
9
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleScrolllview.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style BasedOn="{StaticResource for_scrollbar}" TargetType="ScrollBar" />
<Style BasedOn="{StaticResource for_scrollviewer}" TargetType="ScrollViewer" />
</ResourceDictionary>

自定义ComboBox

/Resources/StyleComboBox.xaml

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
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- ComBoBox项鼠标经过背景色 -->
<SolidColorBrush x:Key="ComboBoxMouseOverBackground" Color="#f0f0f0" />
<!-- Combox右侧下拉按钮 -->
<Style x:Key="ComboxStyleBtn" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<!-- 下拉按钮内部背景色 -->
<Border
x:Name="Back"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="1">
<!-- 下拉按钮内边框 -->
<Label
Name="PathFill"
Height="30"
HorizontalAlignment="Right"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Content="ˇ"
FontSize="30" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Back" Property="Background" Value="Transparent" />
<Setter TargetName="Back" Property="BorderBrush" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Combox -->
<Style x:Key="ComboBoxStyle" TargetType="ComboBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<!-- ComBoxItem -->
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="MinHeight" Value="32" />
<Setter Property="MinWidth" Value="60" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border
Name="_back"
Background="Transparent"
BorderBrush="#f3f3f3"
BorderThickness="0,0,0,0">
<ContentPresenter Margin="10,0,10,0" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="_back" Property="Background" Value="{StaticResource ComboBoxMouseOverBackground}" />
</Trigger>
<!-- 下拉框背景色 -->
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="_back" Property="Background" Value="{StaticResource ComboBoxMouseOverBackground}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<!-- 文字区域背景和边线样式 -->
<TextBox
Grid.Column="0"
Padding="10,0,0,0"
VerticalAlignment="Center"
Background="Transparent"
BorderBrush="#c0c0c0"
BorderThickness="0"
Foreground="Black"
IsReadOnly="{TemplateBinding IsReadOnly}"
Text="{TemplateBinding Text}" />
<Border
Grid.Column="0"
BorderBrush="#c0c0c0"
BorderThickness="0.6"
CornerRadius="1,0,0,1" />
<!-- 右侧下拉button设置 -->
<Border BorderThickness="0">
<ToggleButton
BorderBrush="Black"
BorderThickness="3"
ClickMode="Press"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ComboxStyleBtn}" />
</Border>
<!-- 弹出popup整体设置 -->
<Popup
x:Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid
x:Name="DropDown"
Width="{TemplateBinding ActualWidth}"
MaxHeight="200"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
BorderBrush="#e8e8e8"
BorderThickness="1,0,1,1" />
<ScrollViewer
Margin="1"
CanContentScroll="True"
HorizontalScrollBarVisibility="Disabled"
SnapsToDevicePixels="True"
VerticalScrollBarVisibility="Auto">
<!-- StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True -->
<StackPanel
Background="White"
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
<ComboBox
x:Name="cmbClass"
Grid.Row="0"
Padding="10,0,10,0"
VerticalContentAlignment="Center"
BorderThickness="1"
Cursor="Hand"
DisplayMemberPath="Value"
FontSize="16"
ItemsSource="{Binding bookList}"
SelectedValuePath="Key"
SelectionChanged="cmbClass_SelectionChanged"
Style="{StaticResource ComboBoxStyle}" />

WPF全局样式设置

/Resources/OverwrideDefaultControlStyles.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:SchoolClient.Views">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/StyleButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/StyleZRoundButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/StyleListBoxItem.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/StyleScrolllview.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/StyleComboBox.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style BasedOn="{StaticResource MyButton}" TargetType="Button" />
<Style BasedOn="{StaticResource ZRoundButtonStyle}" TargetType="local:ZRoundButton" />
<Style BasedOn="{StaticResource for_scrollbar}" TargetType="ScrollBar" />
<Style BasedOn="{StaticResource ListBoxItemContainerStyle1}" TargetType="ListBoxItem" />
<Style BasedOn="{StaticResource for_scrollviewer}" TargetType="ScrollViewer" />
</ResourceDictionary>

Application中引用

1
2
3
4
5
6
7
8
9
<Application
x:Class="SchoolClient.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Wins/Welcome.xaml">
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/Resources/OverwrideDefaultControlStyles.xaml" />
</Application.Resources>
</Application>

启动页不唯一怎么办?

我们知道设置启动页有两种方式

  • 添加窗口 生成操作 设置为 ApplicationDefinition
  • 添加cs代码文件,Main方法中运行窗口

但是用以下代码的方式创建窗口,设置的全局样式是不生效的,只有通过StartupUri="Wins/Welcome.xaml"设置启动页才能使全局样式生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public partial class MyApp : Application
{
public static LoadDialog myloading;

[STAThread]
private static void Main()
{
StopSameProcess();
new MyApp();
}

public MyApp()
{
Run(new LoginWindow());
}
}

但是通过StartupUri只能设置唯一的启动页,怎么办呢?

我们可以添加一个欢迎页面作为中间页面,这个页面再决定跳转到那个页面,这样设置的全局样式就生效了。