控件模板
顾名思义就是在原有的控件上进行模版修改成自己需要的样式
把ProgressBar修改为一个水液面的进度条
<Window x:Class="XH.CustomLesson.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XH.CustomLesson"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<SolidColorBrush x:Key="ProgressBar.Progress" Color="#FF06B025"/>
<SolidColorBrush x:Key="ProgressBar.Background" Color="#FFE6E6E6"/>
<SolidColorBrush x:Key="ProgressBar.Border" Color="#FFBCBCBC"/>
<Style x:Key="ProgressBarStyle" TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground" Value="{StaticResource ProgressBar.Progress}"/>
<Setter Property="Background" Value="{StaticResource ProgressBar.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ProgressBar.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid x:Name="TemplateRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Determinate"/>
<VisualState x:Name="Indeterminate">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0" Value="0.25"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)">
<EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5"/>
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
<EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5"/>
<Rectangle x:Name="PART_Track"/>
<Grid x:Name="PART_Indicator" ClipToBounds="True" HorizontalAlignment="Left">
<Border x:Name="Indicator" Background="Transparent">
<Canvas>
<Canvas.LayoutTransform>
<RotateTransform Angle="90" />
</Canvas.LayoutTransform>
<Path Data="M0 0
A70 70 0 0 0 50 0
A70 70 0 0 1 100 0
L 100 100 0 100" Fill="Orange">
<Path.RenderTransform>
<TranslateTransform X="-30" x:Name="tt" />
</Path.RenderTransform>
</Path>
<Path Data="M0 0
A70 70 0 0 0 50 0
A70 70 0 0 1 100 0
L 100 100 0 100" Fill="#9f90">
<Path.RenderTransform>
<TranslateTransform X="0" x:Name="tt_2" />
</Path.RenderTransform>
</Path>
<Path Data="M0 0
A70 70 0 0 0 50 0
A70 70 0 0 1 100 0
L100 100 0 100" Fill="#9f80">
<Path.RenderTransform>
<TranslateTransform X="-50" x:Name="tt_3" />
</Path.RenderTransform>
</Path>
</Canvas>
</Border>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="LayoutTransform" TargetName="TemplateRoot">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsIndeterminate" Value="true">
<Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/>
</Trigger>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation RepeatBehavior="Forever" Duration="0:0:1" From="0" To="-50" Storyboard.TargetName="tt" Storyboard.TargetProperty="X"/>
<DoubleAnimation RepeatBehavior="Forever" BeginTime="0:0:0.3" Duration="0:0:1.3" From="0" To="-50" Storyboard.TargetName="tt_2" Storyboard.TargetProperty="X"/>
<DoubleAnimation RepeatBehavior="Forever" BeginTime="0:0:0.6" Duration="0:0:1.6" From="-50" To="0" Storyboard.TargetName="tt_3" Storyboard.TargetProperty="X"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ProgressBar Style="{DynamicResource ProgressBarStyle}"
BorderThickness="0"
Height="200" Width="50" Orientation="Vertical"
Value="450" Maximum="750" Minimum="0"/>
</Grid>
</Window>
想要弧度更大,修改对应的path即可:
UserControl 用户控件
案例:日期时间选择器 DatePicker
XAML代码:
<UserControl x:Class="XH.CustomLesson.Controls.DateTimePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XH.CustomLesson.Controls"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="200">
<UserControl.Resources>
<Style TargetType="RepeatButton" x:Key="ButtonUpStyle">
<Setter Property="Height" Value="18"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="Transparent">
<Path Data="M838.116 732.779 877.7 693.195 511.979 327.549 146.3 693.195 185.883 732.779 512.003 406.652Z"
Fill="#999" Stretch="Uniform" Margin="6"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="RepeatButton" x:Key="ButtonDownStyle">
<Setter Property="Height" Value="18"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="Transparent">
<Path Data="M185.884 327.55 146.3 367.133 512.021 732.779 877.7 367.133 838.117 327.55 511.997 653.676Z"
Fill="#999" Stretch="Uniform" Margin="6"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button" x:Key="ButtonCancelStyle">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="#EEE">
<Path Data="M557.3 512l329.3-329.4a32 32 0 1 0-45.2-45.2L512 466.7 182.6 137.4a32 32 0 1 0-45.2 45.2L466.7 512 137.4 841.4a31.9 31.9 0 0 0 0 45.2 31.9 31.9 0 0 0 45.2 0L512 557.3l329.4 329.3a31.9 31.9 0 0 0 45.2 0 31.9 31.9 0 0 0 0-45.2z"
Fill="#999" Stretch="Uniform" HorizontalAlignment="Center" Margin="5"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button" x:Key="ButtonAcceptStyle">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="#EEE">
<Path Data="M892.064 261.888a31.936 31.936 0 0 0-45.216 1.472L421.664 717.248l-220.448-185.216a32 32 0 1 0-41.152 48.992l243.648 204.704a31.872 31.872 0 0 0 20.576 7.488 31.808 31.808 0 0 0 23.36-10.112L893.536 307.136a32 32 0 0 0-1.472-45.248z"
Fill="#999" Stretch="Uniform" HorizontalAlignment="Center" Margin="5"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CalendarCalendarDayButtonStyle1" TargetType="{x:Type CalendarDayButton}">
<Setter Property="MinWidth" Value="10"/>
<Setter Property="MinHeight" Value="10"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarDayButton}">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0.5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0.5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation Duration="0" Storyboard.TargetName="NormalText" To=".35" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="SelectedBackground" To=".75" Storyboard.TargetProperty="Opacity"/>
<ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FFFFFFFF" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CalendarButtonFocusStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="CalendarButtonFocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DayButtonFocusVisual" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="CalendarButtonUnfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DayButtonFocusVisual" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ActiveStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Active"/>
<VisualState x:Name="Inactive">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FF777777" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DayStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="RegularDay"/>
<VisualState x:Name="Today">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="TodayBackground" To="1" Storyboard.TargetProperty="Opacity"/>
<ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FFFFFFFF" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="BlackoutDayStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="NormalDay"/>
<VisualState x:Name="BlackoutDay">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="Blackout" To=".2" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="TodayBackground" Fill="Gray" Opacity="0" RadiusX="1" RadiusY="1"/>
<Rectangle x:Name="SelectedBackground" Fill="#409EFE" Opacity="0" RadiusX="1" RadiusY="1"/>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
<Rectangle x:Name="HighlightBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1"/>
<ContentPresenter x:Name="NormalText" TextElement.Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,1,5,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Path x:Name="Blackout" Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z" Fill="#FF000000" HorizontalAlignment="Stretch" Margin="3" Opacity="0" RenderTransformOrigin="0.5,0.5" Stretch="Fill" VerticalAlignment="Stretch"/>
<Rectangle x:Name="DayButtonFocusVisual" IsHitTestVisible="false" RadiusX="1" RadiusY="1" Stroke="#FF45D6FA" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CalendarCalendarItemStyle1" TargetType="{x:Type CalendarItem}">
<Setter Property="Margin" Value="0,3,0,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarItem}">
<ControlTemplate.Resources>
<DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}">
<TextBlock Foreground="#FF333333" FontFamily="Verdana" FontWeight="Bold" FontSize="9.5" HorizontalAlignment="Center" Margin="0,6,0,6" Text="{Binding}" VerticalAlignment="Center"/>
</DataTemplate>
</ControlTemplate.Resources>
<Grid x:Name="PART_Root">
<Grid.Resources>
<SolidColorBrush x:Key="DisabledColor" Color="#A5FFFFFF"/>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="PART_DisabledVisual" To="1" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1">
<Border BorderBrush="#FFFFFFFF" BorderThickness="0" CornerRadius="1">
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="PreviousButtonTemplate" TargetType="{x:Type Button}">
<Grid Cursor="Hand">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="path" To="#FF73A9D8" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="path" To=".5" Storyboard.TargetProperty="(Shape.Fill).(Brush.Opacity)"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="Transparent">
<Path x:Name="path" Data="M671.968176 911.99957c-12.287381 0-24.576482-4.67206-33.951566-14.047144L286.048434 545.984249c-18.751888-18.719204-18.751888-49.12028 0-67.872168L638.016611 126.111222c18.751888-18.751888 49.12028-18.751888 67.872168 0 18.751888 18.719204 18.751888 49.12028 0 67.872168l-318.016611 318.047574L705.888778 830.047574c18.751888 18.751888 18.751888 49.12028 0 67.872168C696.544658 907.32751 684.255557 911.99957 671.968176 911.99957z"
Fill="#FF333333" HorizontalAlignment="Center" VerticalAlignment="Center"
Height="10" Width="6" Stretch="Fill" Margin="10,0"/>
</Grid>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="NextButtonTemplate" TargetType="{x:Type Button}">
<Grid Cursor="Hand">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="path" To="#FF73A9D8" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="path" To=".5" Storyboard.TargetProperty="(Shape.Fill).(Brush.Opacity)"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="Transparent">
<Path x:Name="path" Data="M761.055557 532.128047c0.512619-0.992555 1.343475-1.823411 1.792447-2.848649 8.800538-18.304636 5.919204-40.703346-9.664077-55.424808L399.935923 139.743798c-19.264507-18.208305-49.631179-17.344765-67.872168 1.888778-18.208305 19.264507-17.375729 49.631179 1.888778 67.872168l316.960409 299.839269L335.199677 813.631716c-19.071845 18.399247-19.648112 48.767639-1.247144 67.872168 9.407768 9.791372 21.984142 14.688778 34.560516 14.688778 12.000108 0 24.000215-4.479398 33.311652-13.439914l350.048434-337.375729c0.672598-0.672598 0.927187-1.599785 1.599785-2.303346 0.512619-0.479935 1.056202-0.832576 1.567101-1.343475C757.759656 538.879828 759.199462 535.391265 761.055557 532.128047z"
Fill="#FF333333" HorizontalAlignment="Right" VerticalAlignment="Center"
Height="10" Stretch="Fill" Width="6" Margin="10,0"/>
</Grid>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="HeaderButtonTemplate" TargetType="{x:Type Button}">
<Grid Cursor="Hand" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="buttonContent" To="#FF73A9D8" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="buttonContent" To=".5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="buttonContent" ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" TextElement.Foreground="#FF333333"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="1,9" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="PART_HeaderButton" Grid.Column="0" Focusable="False" FontWeight="Bold" FontSize="14" HorizontalAlignment="Left"
VerticalContentAlignment="Center"
Grid.Row="0" Template="{StaticResource HeaderButtonTemplate}" VerticalAlignment="Center" Margin="10,5"/>
<Button x:Name="PART_PreviousButton" Grid.Column="1" Focusable="False" HorizontalAlignment="Center"
Template="{StaticResource PreviousButtonTemplate}" Margin="0,5"/>
<Button x:Name="PART_NextButton" Grid.Column="2" Focusable="False" HorizontalAlignment="Right"
Template="{StaticResource NextButtonTemplate}" Margin="0,5"/>
<Grid x:Name="PART_MonthView" Grid.ColumnSpan="3" HorizontalAlignment="Center" Margin="6,-1,6,6" Grid.Row="1" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
</Grid>
<Grid x:Name="PART_YearView" Grid.ColumnSpan="3" HorizontalAlignment="Center" Margin="6,-3,7,6" Grid.Row="1" Visibility="Hidden">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
</Grid>
</Grid>
</Border>
</Border>
<Rectangle x:Name="PART_DisabledVisual" Fill="{StaticResource DisabledColor}" Opacity="0" RadiusX="2" RadiusY="2" Stroke="{StaticResource DisabledColor}" Stretch="Fill" StrokeThickness="1" Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="PART_DisabledVisual" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Year">
<Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/>
<Setter Property="Visibility" TargetName="PART_YearView" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Decade">
<Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/>
<Setter Property="Visibility" TargetName="PART_YearView" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" IsReadOnly="True" Name="textBox" VerticalContentAlignment="Center"
Text="{Binding CurrentDateTime,RelativeSource={RelativeSource AncestorType=UserControl},StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}"/>
<ToggleButton Grid.Column="1" x:Name="toggleButton" Background="AliceBlue">
<ToggleButton.Content>
<local:DateTimePickerIcon />
</ToggleButton.Content>
</ToggleButton>
<!--AllowsTransparency:控件包含透明内容-->
<Popup StaysOpen="False" IsOpen="{Binding ElementName=toggleButton,Path=IsChecked}"
PlacementTarget="{Binding ElementName=textBox}" AllowsTransparency="True"
HorizontalOffset="0" Name="popup">
<Border Background="#F7F9FA" Width="auto" Height="auto" Margin="3">
<Border.Effect>
<DropShadowEffect BlurRadius="10" Color="Gray" ShadowDepth="0" Opacity="0.3" />
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Calendar x:Name="calendar"
BorderThickness="0"
Background="Transparent"
CalendarItemStyle="{StaticResource CalendarCalendarItemStyle1}"
CalendarDayButtonStyle="{StaticResource CalendarCalendarDayButtonStyle1}"/>
<Grid Grid.Row="1" Margin="10,5,10,10">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Click="BtnHourUp_Click"/>
<RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Grid.Column="2" Click="BtnMinuteUp_Click"/>
<RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Grid.Column="4" Click="BtnSecondUp_Click"/>
<RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Click="BtnHourDown_Click"/>
<RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Grid.Column="2" Click="BtnMinuteDown_Click"/>
<RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Grid.Column="4" Click="BtnSecondDown_Click"/>
<TextBox Grid.Row="1" Name="tb_hour" TextChanged="tb_hour_TextChanged" Text="{Binding HourInt,RelativeSource={RelativeSource AncestorType=UserControl}}"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/>
<TextBlock Text=":" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="3"/>
<TextBox Grid.Row="1" Grid.Column="2" Name="tb_minute" TextChanged="tb_minute_TextChanged" Text="{Binding MinuteInt,RelativeSource={RelativeSource AncestorType=UserControl}}"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/>
<TextBlock Text=":" Grid.Row="1" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="3"/>
<TextBox Grid.Row="1" Grid.Column="4" Name="tb_second" TextChanged="tb_second_TextChanged" Text="{Binding SecondInt,RelativeSource={RelativeSource AncestorType=UserControl}}"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/>
<Button Content="×" Style="{StaticResource ButtonCancelStyle}" Click="Button_Click_1" BorderThickness="0" Grid.Row="1" Grid.Column="5" />
<Button Content="√" Style="{StaticResource ButtonAcceptStyle}" BorderThickness="0" Grid.Row="1" Grid.Column="6" Click="Button_Click"/>
</Grid>
</Grid>
</Border>
</Popup>
</Grid>
</UserControl>
图标XAML:
<UserControl x:Class="XH.CustomLesson.Controls.DateTimePickerIcon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XH.CustomLesson.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Path Data="M47.93344 167.1936h-0.98816v248.83712h933.248V355.31264c0.04096-1.00352 0.29696-1.9456 0.29696-2.95936V177.00864c0-1.01376-0.256-1.95584-0.29696-2.95936v-6.85568h-0.6912c-4.80256-33.50016-33.3312-59.3408-68.16256-59.3408H116.096c-34.82624 0.00512-63.36 25.84064-68.16256 59.3408z" Fill="#F38181" />
<Path Data="M979.5072 856.8064h0.98816V404.9152H47.24224v60.71296c-0.04096 1.00352-0.29696 1.9456-0.29696 2.95424v378.40384c0 1.01376 0.256 1.95584 0.29696 2.95424v6.85568h0.6912c4.80256 33.50016 33.3312 59.3408 68.16256 59.3408h795.24352c34.83136 0.00512 63.36512-25.8304 68.16768-59.33056z" Fill="#E6E4E2" />
<Path Data="M489.54368 646.2208c-4.83328 5.80608-9.02144 9.98912-19.98336 19.65568-6.12352 5.80608-12.5696 11.60704-18.688 17.40288-19.65568 18.37056-23.20896 22.89152-27.71456 38.03136h77.6704v43.19232H365.4656v-18.37056c0-25.13408 6.44096-44.14976 23.5264-62.848 11.92448-13.2096 25.7792-24.81152 38.99904-37.05856 19.01568-17.40288 22.88128-22.23616 22.88128-37.70368v-16.75776c0-4.51584 0-20.95104-17.40288-20.62848-11.60704 0-15.79008 6.76352-17.40288 11.60192-0.64512 1.93536-0.96768 4.51072-0.96768 9.344v31.90784h-47.69792v-29.32736c0-17.0752 0.96768-32.22528 14.50496-45.11744 9.02144-8.704 24.81664-16.75776 52.85376-16.75776 26.42944 0 41.25184 8.05888 50.2784 15.47264 2.2528 1.93024 9.02144 7.7312 12.5696 16.4352 2.89792 7.0912 3.8656 14.8224 3.8656 30.61248-0.00512 19.33312 0.64 34.79552-11.9296 50.91328zM654.87872 742.90688c-3.2256 5.16096-8.05888 9.02656-9.67168 10.31168-18.688 15.47264-42.86464 15.15008-50.2784 15.15008-25.45152 0-40.92928-8.05888-49.3056-15.15008-6.44608-5.4784-10.31168-11.60192-13.21984-19.33312-3.8656-11.27936-3.8656-22.56384-3.8656-34.16064v-103.45984c0-4.19328 0-8.704 0.32768-12.89216 0.31744-5.15072 1.28512-19.33312 11.60192-31.2576 8.704-10.63936 23.84896-19.01568 53.17632-19.01568 23.20896 0 53.17632 5.4784 63.16544 29.97248 2.90816 6.76352 3.87584 12.24192 3.87584 26.42944v15.79008h-47.05792v-11.92448c0-4.51584 0.64512-19.66592-16.75776-19.66592-19.33824 0-19.01568 16.11776-19.01568 21.59616v42.21952c6.44608-6.44608 14.50496-14.8224 34.80576-14.8224 27.71456 0 41.57952 13.85472 46.09024 24.81152 2.2528 5.80608 3.2256 9.67168 3.2256 20.95104v37.38624c-0.00512 12.89728 0.32256 25.78432-7.09632 37.06368z m-41.5744-65.41824c0-4.83328 1.6128-23.53152-17.72032-23.53152-4.83328 0-8.38656 0.65024-11.92448 3.54816-6.44608 5.4784-6.12864 13.85472-6.12864 21.26848v27.71456c0 5.80608-1.28512 21.91872 18.37056 21.91872 6.12352 0 9.02656-1.6128 11.60704-3.54816 5.79584-4.83328 6.12352-12.89216 6.12352-27.39712-0.00512-6.43584-0.00512-13.2096-0.32768-19.97312z" Fill="#5B5144" />
<Path Data="M455.91552 325.95456V239.50848l-18.54464 86.44608h-25.52832l-18.55488-86.44608v86.44608h-25.35424V205.81376h38.79936l17.87392 88.14592 17.86368-88.14592h39.31136v120.1408h-25.86624zM550.05696 325.95456l-4.08064-27.40224h-22.29248l-4.25472 27.40224H491.008l24.33536-120.1408h38.79936l24.32512 120.1408h-28.41088z m-14.97088-101.08416l-8.16128 53.43744h16.16384l-8.00256-53.43744zM629.56032 283.75552v42.19904h-28.42112v-42.19904l-28.59008-77.93664h28.59008l14.62784 53.0944 14.63808-53.0944h29.10208l-29.94688 77.93664z" Fill="#FFFFFF" />
</Grid>
</Viewbox>
</UserControl>
效果:
C#逻辑代码:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace XH.CustomLesson.Controls
{
/// <summary>
/// DateTimePicker.xaml 的交互逻辑
/// </summary>
public partial class DateTimePicker : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public event EventHandler<DateTime> SeletedChanged;
private int hourInt = DateTime.Now.Hour;
public int HourInt
{
get { return hourInt; }
set
{
hourInt = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HourInt"));
}
}
private int minuteInt = DateTime.Now.Minute;
public int MinuteInt
{
get { return minuteInt; }
set
{
minuteInt = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MinuteInt"));
}
}
private int secondInt = DateTime.Now.Second;
public int SecondInt
{
get { return secondInt; }
set
{
secondInt = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SecondInt"));
}
}
public DateTime CurrentDateTime
{
get { return (DateTime)GetValue(CurrentDateTimeProperty); }
set
{
SetValue(CurrentDateTimeProperty, value);
}
}
// Using a DependencyProperty as the backing store for CurrentDateTime. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentDateTimeProperty =
DependencyProperty.Register(
"CurrentDateTime",
typeof(DateTime), typeof(DateTimePicker),
new PropertyMetadata(DateTime.Now,
new PropertyChangedCallback(OnCurentDateTimeChanged)));
private static void OnCurentDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as DateTimePicker).Refresh();
}
private void Refresh()
{
this.calendar.SelectedDate = this.CurrentDateTime;
this.calendar.DisplayDate = this.CurrentDateTime; // 确保日历显示正确的月份
HourInt = this.CurrentDateTime.Hour;
MinuteInt = this.CurrentDateTime.Minute;
SecondInt = this.CurrentDateTime.Second;
}
public DateTimePicker()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// 把日历和时间合并
int year = calendar.SelectedDate.Value.Year;
int month = calendar.SelectedDate.Value.Month;
int day = calendar.SelectedDate.Value.Day;
int.TryParse(this.tb_hour.Text.Trim(), out int hour);
int.TryParse(this.tb_minute.Text.Trim(), out int minute);
int.TryParse(this.tb_second.Text.Trim(), out int second);
CurrentDateTime = new DateTime(year, month, day, hour, minute, second);
this.popup.IsOpen = false;
SeletedChanged?.Invoke(this, CurrentDateTime);
}
private void BtnHourUp_Click(object sender, RoutedEventArgs e)
{
var hour_str = string.IsNullOrEmpty(this.tb_hour.Text) ? "0" : this.tb_hour.Text;
HourInt = int.Parse(hour_str);
HourInt++;
HourInt %= 24;
//this.tb_hour.Text = hourInt.ToString();
}
private void BtnHourDown_Click(object sender, RoutedEventArgs e)
{
var hour_str = string.IsNullOrEmpty(this.tb_hour.Text) ? "0" : this.tb_hour.Text;
HourInt = int.Parse(hour_str);
HourInt--;
HourInt = (HourInt + 24) % 24;
}
private void BtnMinuteDown_Click(object sender, RoutedEventArgs e)
{
var minute_str = string.IsNullOrEmpty(this.tb_minute.Text) ? "0" : this.tb_minute.Text;
MinuteInt = int.Parse(minute_str);
MinuteInt--;
MinuteInt = (MinuteInt + 60) % 60;
}
private void BtnMinuteUp_Click(object sender, RoutedEventArgs e)
{
var minute_str = string.IsNullOrEmpty(this.tb_minute.Text) ? "0" : this.tb_minute.Text;
MinuteInt = int.Parse(minute_str);
MinuteInt++;
MinuteInt %= 60;
}
private void BtnSecondUp_Click(object sender, RoutedEventArgs e)
{
var second_str = string.IsNullOrEmpty(this.tb_second.Text) ? "0" : this.tb_second.Text;
SecondInt = int.Parse(second_str);
SecondInt++;
SecondInt %= 60;
}
private void BtnSecondDown_Click(object sender, RoutedEventArgs e)
{
var second_str = string.IsNullOrEmpty(this.tb_second.Text) ? "0" : this.tb_second.Text;
SecondInt = int.Parse(second_str);
SecondInt--;
SecondInt = (SecondInt + 60) % 60;
}
private void tb_hour_TextChanged(object sender, TextChangedEventArgs e)
{
HourInt = int.Parse(tb_hour.Text);
if (HourInt >= 24 || HourInt < 0)
HourInt = 0;
}
private void tb_minute_TextChanged(object sender, TextChangedEventArgs e)
{
MinuteInt = int.Parse(tb_minute.Text);
if (MinuteInt >= 60 || MinuteInt < 0)
MinuteInt = 0;
}
private void tb_second_TextChanged(object sender, TextChangedEventArgs e)
{
SecondInt = int.Parse(tb_second.Text);
if (SecondInt >= 60 || SecondInt < 0)
SecondInt = 0;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.popup.IsOpen = false;
}
}
}
使用自定义控件代码:
<c:DateTimePicker HorizontalAlignment="Center"
SeletedChanged="DateTimePicker_SeletedChanged" VerticalAlignment="Top"
Width="200" CurrentDateTime="{Binding Current,RelativeSource={RelativeSource AncestorType=Window}}" />
CustomControl 自定义控件
案例:自定义数值控件
XAML代码:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:XH.CustomLesson.Controls"
xmlns:local="clr-namespace:XH.CustomLesson">
<Style TargetType="{x:Type c:NumericBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:NumericBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBox Name="PART_Value" VerticalAlignment="Center" Margin="3,5" BorderThickness="0"
Foreground="{TemplateBinding Foreground}"/>
<UniformGrid Rows="2" Grid.Column="1">
<RepeatButton Content="+" Background="Transparent"
BorderThickness="1,0,0,0" Name="PART_IncreaseButton"
BorderBrush="#DDD"/>
<RepeatButton Content="-" Background="Transparent"
BorderThickness="1,1,0,0" Name="PART_DecreaseButton"
BorderBrush="#DDD"/>
</UniformGrid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
C#逻辑代码:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
namespace XH.CustomLesson.Controls
{
/// <summary>
/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
///
/// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:XH.CustomLesson.Controls"
///
///
/// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:XH.CustomLesson.Controls;assembly=XH.CustomLesson.Controls"
///
/// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
/// 并重新生成以避免编译错误:
///
/// 在解决方案资源管理器中右击目标项目,然后依次单击
/// "添加引用"->"项目"->[浏览查找并选择此项目]
///
///
/// 步骤 2)
/// 继续操作并在 XAML 文件中使用控件。
///
/// <MyNamespace:NumericBox/>
///
/// </summary>
///
[TemplatePart(Name = "PART_Vlaue", Type = typeof(TextBox))]
public class NumericBox : Control
{
TextBox txtValue = new TextBox();
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(int),
typeof(NumericBox),
new PropertyMetadata(0, new PropertyChangedCallback(OnValueChanged)));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var nb = (d as NumericBox);
if (nb.txtValue == null) return;
if (nb.Value > 30)
nb.txtValue.Foreground = Brushes.Red;
else if(nb.Value >0 && nb.Value < 30)
nb.txtValue.Foreground = Brushes.Black;
else if (nb.Value < 0)
nb.txtValue.Foreground = Brushes.Orange;
}
static NumericBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericBox), new FrameworkPropertyMetadata(typeof(NumericBox)));
}
// 应用模板
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// 获取模板中的事件
txtValue = base.GetTemplateChild("PART_Value") as TextBox;
var btnIncrease = base.GetTemplateChild("PART_IncreaseButton") as RepeatButton;
var btnDecrease = base.GetTemplateChild("PART_DecreaseButton") as RepeatButton;
if (txtValue != null)
{
// 建立对象中的Value属性和模板中的TextBox控件的Text属性的绑定
Binding binding = new Binding("Value");
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.RelativeSource = new RelativeSource() { AncestorType = typeof(NumericBox), Mode = RelativeSourceMode.FindAncestor };
txtValue.SetBinding(TextBox.TextProperty, binding);
}
if (btnIncrease != null)
btnIncrease.Click += BtnIncrease_Click;
if (btnDecrease != null)
btnDecrease.Click += BtnDecrease_Click;
}
private void BtnDecrease_Click(object sender, RoutedEventArgs e)
{
this.Value--;
}
private void BtnIncrease_Click(object sender, RoutedEventArgs e)
{
this.Value++;
}
}
}
使用部分代码:
<c:NumericBox VerticalAlignment="Bottom" Width="200" BorderBrush="#ddd"
BorderThickness="1" Margin="20"/>
UserControl与CustomControl区别
- 自定义控件:注重控件对象的功能,必须遵守WPF的控件规则
-
- 完全自己实现一个控件 继承现有控件进行功能扩展,并且添加新功能 WPF的控件要求
- 后台代码(控制逻辑)和Generic.Xaml(样式 模板)进行组合
- 支持模板重写
- 继承Control
- 用户控件:注重复合控件组合使用,非常灵活,可以根据控件开发人员自己的意愿进行功能处理
-
- 多个现有控件的集合,组成一个可复用的控件组
- XAML和后台代码组成 绑定非常紧密
- 不支持模板重写、样式
- 继承UserControl
案例
工业仪表
XAML代码:
<UserControl x:Class="XH.CustomLesson.Controls.Instrument"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XH.CustomLesson.Controls"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400">
<Grid>
<Border Name="border" Background="#FF030A28">
<Border.Effect>
<DropShadowEffect BlurRadius="20" Opacity="0.5" ShadowDepth="0" Direction="0" Color="#FF3CAFFF"/>
</Border.Effect>
<Grid>
<Path Stroke="#333CAFFF" StrokeThickness="10" Name="circle" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<RotateTransform Angle="-45"/>
</Path.RenderTransform>
</Path>
<Canvas x:Name="canvasPlate" RenderTransformOrigin="0.5,0.5" Margin="0">
<Canvas.RenderTransform>
<RotateTransform Angle="-45"/>
</Canvas.RenderTransform>
</Canvas>
<Path Data="" Name="plateBorder" Stroke="#FF3CAFFF" StrokeThickness="3" RenderTransformOrigin="0.5,0.5"
Width="{Binding ElementName=border,Path=Width}"
Height="{Binding ElementName=border,Path=Height}">
<Path.RenderTransform>
<RotateTransform Angle="-45"/>
</Path.RenderTransform>
</Path>
<Path Data="M200 205,360 200,200 195,195 200 200 205" Fill="Red" RenderTransformOrigin="0.5,0.5" Name="pointer">
<Path.RenderTransform>
<RotateTransform Angle="135" x:Name="rtPointer"/>
</Path.RenderTransform>
</Path>
<Border Width="60" Height="60" CornerRadius="30" Background="#FF030A28">
<Border.Effect>
<DropShadowEffect BlurRadius="20" Opacity="0.3" ShadowDepth="0" Direction="0" Color="#FF3CAFFF"/>
</Border.Effect>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center">
<Run Text="{Binding Value,RelativeSource={RelativeSource AncestorType=UserControl}}"
FontSize="20"/>
<Run Text="m³/H" FontSize="8"/>
</TextBlock>
<TextBlock Text="NATURAL GAS" Foreground="#FF8CBEF0" VerticalAlignment="Center" HorizontalAlignment="Center"
FontSize="6"/>
</StackPanel>
</Border>
</Grid>
</Border>
</Grid>
</UserControl>
C#代码:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace XH.CustomLesson.Controls
{
/// <summary>
/// Instrument.xaml 的交互逻辑
/// </summary>
public partial class Instrument : UserControl
{
// 当前值
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(Instrument),
new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));
// 最小刻度
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(Instrument),
new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));
// 最大刻度
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(Instrument),
new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));
间隔
//public double Interval
//{
// get { return (double)GetValue(IntervalProperty); }
// set { SetValue(IntervalProperty, value); }
//}
//public static readonly DependencyProperty IntervalProperty =
// DependencyProperty.Register("Interval", typeof(double), typeof(Instrument), new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));
// 大刻度的个数
public int ScaleCount
{
get { return (int)GetValue(ScaleCountProperty); }
set { SetValue(ScaleCountProperty, value); }
}
public static readonly DependencyProperty ScaleCountProperty =
DependencyProperty.Register("ScaleCount", typeof(int), typeof(Instrument),
new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));
// 刻度的厚度
public double ScaleThickness
{
get { return (double)GetValue(ScaleThicknessProperty); }
set { SetValue(ScaleThicknessProperty, value); }
}
public static readonly DependencyProperty ScaleThicknessProperty =
DependencyProperty.Register("ScaleThickness", typeof(double), typeof(Instrument),
new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));
// 刻度的颜色
public Brush ScaleBrush
{
get { return (Brush)GetValue(ScaleBrushProperty); }
set { SetValue(ScaleBrushProperty, value); }
}
public static readonly DependencyProperty ScaleBrushProperty =
DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Instrument),
new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));
// 指针的颜色
public Brush PointerBrush
{
get { return (Brush)GetValue(PointerBrushProperty); }
set { SetValue(PointerBrushProperty, value); }
}
public static readonly DependencyProperty PointerBrushProperty =
DependencyProperty.Register("PointerBrush", typeof(Brush), typeof(Instrument),
new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));
// 刻度字体大小
public new double FontSize
{
get { return (double)GetValue(FontSizeProperty); }
set { SetValue(FontSizeProperty, value); }
}
public static new readonly DependencyProperty FontSizeProperty =
DependencyProperty.Register("FontSize", typeof(double), typeof(Instrument),
new PropertyMetadata(9.0, new PropertyChangedCallback(OnPropertyChanged)));
public Instrument()
{
InitializeComponent();
SetCurrentValue(MinimumProperty, 0d);
SetCurrentValue(MaximumProperty, 100d);
//SetCurrentValue(IntervalProperty, 10d);
SizeChanged += (se, ev) => { Refresh(); };
}
static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
=> (d as Instrument).Refresh();
private void Refresh()
{
// 圆
this.border.Width = Math.Min(RenderSize.Width, RenderSize.Height);
this.border.Height = Math.Min(RenderSize.Width, RenderSize.Height);
this.border.CornerRadius = new CornerRadius(this.border.Width / 2);
// 半径
double radius = this.border.Width / 2;
this.canvasPlate.Children.Clear();
if (ScaleCount <= 0 || radius <= 0) return;
// 画边
string borderPathData = $"M4,{radius}A{radius - 4} {radius - 4} 0 1 1 {radius} {this.border.Height - 4}";
// 将字符串转换成Geometry
var converter = TypeDescriptor.GetConverter(typeof(Geometry));
//this.plateBorder.Data = (Geometry)converter.ConvertFrom(borderPathData);
this.plateBorder.Data = PathGeometry.Parse(borderPathData);
// 计算刻度
double label = this.Minimum;
double interval = 0;
double step = 270.0 / (this.Maximum - this.Minimum);
// 计算小刻度
for (int i = 0; i < this.Maximum - this.Minimum; i++)
{
//添加刻度线
Line lineScale = new Line();
// 角度需要转换弧度
lineScale.X1 = radius - (radius - 13) * Math.Cos(step * i * Math.PI / 180);
lineScale.Y1 = radius - (radius - 13) * Math.Sin(step * i * Math.PI / 180);
lineScale.X2 = radius - (radius - 8) * Math.Cos(step * i * Math.PI / 180);
lineScale.Y2 = radius - (radius - 8) * Math.Sin(step * i * Math.PI / 180);
lineScale.Stroke = this.ScaleBrush;
lineScale.StrokeThickness = this.ScaleThickness;
this.canvasPlate.Children.Add(lineScale);
}
// 计算大刻度
do
{
//添加刻度线
Line lineScale = new Line();
lineScale.X1 = radius - (radius - 20) * Math.Cos(interval * step * Math.PI / 180);
lineScale.Y1 = radius - (radius - 20) * Math.Sin(interval * step * Math.PI / 180);
lineScale.X2 = radius - (radius - 8) * Math.Cos(interval * step * Math.PI / 180);
lineScale.Y2 = radius - (radius - 8) * Math.Sin(interval * step * Math.PI / 180);
lineScale.Stroke = this.ScaleBrush;
lineScale.StrokeThickness = this.ScaleThickness;
this.canvasPlate.Children.Add(lineScale);
TextBlock txtScale = new TextBlock();
txtScale.Text = label.ToString("0");
txtScale.Width = 34;
txtScale.TextAlignment = TextAlignment.Center;
txtScale.Foreground = new SolidColorBrush(Colors.White);
txtScale.RenderTransform = new RotateTransform() { Angle = 45, CenterX = 17, CenterY = 8 };
txtScale.FontSize = this.FontSize;
Canvas.SetLeft(txtScale, radius - (radius - 34) * Math.Cos(interval * step * Math.PI / 180) - 17);
Canvas.SetTop(txtScale, radius - (radius - 34) * Math.Sin(interval * step * Math.PI / 180) - 8);
this.canvasPlate.Children.Add(txtScale);
interval += (this.Maximum - this.Minimum) / this.ScaleCount;
label += (this.Maximum - this.Minimum) / this.ScaleCount;
} while (interval <= this.Maximum - this.Minimum);
// 修改指针
string sData = "M{0} {1},{2} {0},{0} {3},{3} {0},{0} {1}";
sData = string.Format(sData, radius, radius + 2, this.border.Width - radius / 10, radius - 4);
converter = TypeDescriptor.GetConverter(typeof(Geometry));
this.pointer.Data = (Geometry)converter.ConvertFrom(sData);
this.pointer.Fill = this.PointerBrush;
//DoubleAnimation da = new DoubleAnimation((Value - Minimum) * step + 135, new Duration(TimeSpan.FromMilliseconds(200)));
//this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);
this.rtPointer.Angle = (Value - Minimum) * step + 135;
// 修改圆 M100 200 A100 100 0 1 1 200 300
// 厚度
double thickness = radius / 2;
this.circle.StrokeThickness = thickness;
double startX = radius - thickness / 2;
double startY = radius;
double endX = radius - (radius - thickness / 2) * Math.Cos((Value - Minimum) * step * Math.PI / 180);
double endY = radius - (radius - thickness / 2) * Math.Sin((Value - Minimum) * step * Math.PI / 180);
int isLarge = 1;
if ((Value - Minimum) * step < 180)
isLarge = 0;
sData = $"M{startX},{startY}A{radius / 2} {radius / 2} 0 1 1 {endX} {endY}";
sData = $"M{thickness / 2},{radius}A{radius - thickness / 2} {radius - thickness / 2} 0 {isLarge} 1 {endX} {endY}";
//sData = string.Format(sData, radius * 0.5, radius, radius * 1.5);
this.circle.Data = (Geometry)converter.ConvertFrom(sData);
this.circle.Visibility = Visibility.Visible;
if (this.border.Width < 200)
this.circle.Visibility = Visibility.Collapsed;
}
}
}
使用代码:
<c:Instrument Height="200" Width="200" Maximum="100" Value="25" Minimum="0"
ScaleCount="10" ScaleThickness="0.5" ScaleBrush="White"
PointerBrush="Red" FontSize="9"/>
效果展示:
各种常见开关
自定义控件:代码:
<Style TargetType="{x:Type c:Switch}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:Switch}">
<Grid>
<Border Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
Visibility="Collapsed" Name="dropdown" Margin="-23">
<Border.Background>
<RadialGradientBrush>
<GradientStop Color="Transparent" Offset="1"/>
<GradientStop Color="#5500D787" Offset="0.7"/>
<GradientStop Color="Transparent" Offset="0.59"/>
</RadialGradientBrush>
</Border.Background>
</Border>
<Border Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
BorderBrush="DarkGreen" BorderThickness="5"
CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
Background="Gray" Name="bor">
<Border Background="#FF00C88C" Margin="2" Name="bor1"
Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard >
<ColorAnimation To="White" Duration="0:0:0.5"
Storyboard.TargetName="bor1"
Storyboard.TargetProperty="Background.Color"/>
<ColorAnimation To="#FF32FAC8" Duration="0:0:0.5"
Storyboard.TargetName="bor"
Storyboard.TargetProperty="BorderBrush.Color"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="dropdown"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard >
<ColorAnimation Storyboard.TargetName="bor1"
Storyboard.TargetProperty="Background.Color"/>
<ColorAnimation Storyboard.TargetName="bor"
Storyboard.TargetProperty="BorderBrush.Color"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="dropdown"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
C#代码:
public class Switch :ToggleButton
{
static Switch()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Switch), new FrameworkPropertyMetadata(typeof(Switch)));
}
}
使用场景:
<UniformGrid Rows="1" HorizontalAlignment="Center">
<c:Switch Height="60" IsChecked="False" Margin="0 0 20 0" />
<c:Switch Height="60" IsChecked="True" Margin="0 0 20 0"/>
<c:Switch Height="60" IsChecked="False" Style="{StaticResource RotarySwitchStyle}" Margin="0 0 20 0"/>
<c:Switch Height="60" IsChecked="True" Style="{StaticResource RotarySwitchStyle}" Margin="0 0 20 0"/>
<c:Switch Height="60" IsChecked="False" Style="{StaticResource ButtonSwitchStyle}" Margin="0 0 20 0"/>
<c:Switch Height="60" IsChecked="True" Style="{StaticResource ButtonSwitchStyle}" Margin="0 0 20 0"/>
<ToggleButton Height="60" Style="{StaticResource Button2SwitchStyle}" Margin="0 0 20 0"/>
</UniformGrid>
其他按钮自定义样式:其实都是ToggleButton的自定义模板
<Style TargetType="c:Switch" x:Key="RotarySwitchStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="c:Switch">
<Grid>
<Border Background="#FF3C3C3C"
Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/>
<Border BorderBrush="Black" BorderThickness="1" Margin="8"
Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"
CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/>
<Border Width="12" CornerRadius="6" Background="#FF3C3C3C"
RenderTransformOrigin="0.5,0.5">
<Border.Effect>
<DropShadowEffect BlurRadius="14" Color="Black" Opacity="0.9" Direction="0"
ShadowDepth="0"/>
</Border.Effect>
<Border.RenderTransform>
<RotateTransform Angle="-30" x:Name="rt"/>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Background="White" Margin="3,3" CornerRadius="4"/>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="30" Duration="0:0:0.2"
Storyboard.TargetName="rt"
Storyboard.TargetProperty="Angle"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetName="rt"
Storyboard.TargetProperty="Angle"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="c:Switch" x:Key="ButtonSwitchStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="c:Switch">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border x:Name="borWidth"/>
<Border Width="{Binding ElementName=borWidth,Path=ActualWidth}"
Height="{Binding ElementName=borWidth,Path=ActualHeight}"
Grid.ColumnSpan="2"
Background="#FF3C3C3C" CornerRadius="3">
<Grid>
<Border Background="#FFA24F3F" Margin="6"/>
<Grid Margin="6,18,6,6" Name="grid">
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Name="lgb">
<GradientStop Color="#FF4B4B4B" Offset="0"/>
<GradientStop Color="#FF863424" Offset="0.7"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border>
<Border.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Black" Offset="1" x:Name="gs1"/>
<GradientStop Color="Transparent" Offset="0" x:Name="gs2"/>
</LinearGradientBrush>
</Border.OpacityMask>
<Grid TextBlock.FontSize="16" Margin="0,3">
<TextBlock Text="I" VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="White"/>
<TextBlock Text="O" VerticalAlignment="Bottom" HorizontalAlignment="Center" Foreground="White"/>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation To="6,6,6,18"
Duration="0:0:0.2"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="Margin"/>
<DoubleAnimation To="0" Duration="0:0:0.2"
Storyboard.TargetName="gs1"
Storyboard.TargetProperty="Offset"/>
<DoubleAnimation To="1" Duration="0:0:0.2"
Storyboard.TargetName="gs2"
Storyboard.TargetProperty="Offset"/>
<PointAnimation To="0,1" Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="StartPoint"/>
<PointAnimation To="0,0" Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="EndPoint"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.2"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="Margin"/>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetName="gs1"
Storyboard.TargetProperty="Offset"/>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetName="gs2"
Storyboard.TargetProperty="Offset"/>
<PointAnimation Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="StartPoint"/>
<PointAnimation Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="EndPoint"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ToggleButton" x:Key="Button2SwitchStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border x:Name="borWidth"/>
<Border Width="{Binding ElementName=borWidth,Path=ActualWidth}"
Height="{Binding ElementName=borWidth,Path=ActualHeight}"
Grid.ColumnSpan="2"
Background="#FF3C3C3C" CornerRadius="3">
<Grid>
<Border Background="#FFA24F3F" Margin="6"/>
<Grid Margin="6,18,6,6" Name="grid">
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Name="lgb">
<GradientStop Color="#FF4B4B4B" Offset="0"/>
<GradientStop Color="#FF863424" Offset="0.7"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border>
<Border.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Black" Offset="1" x:Name="gs1"/>
<GradientStop Color="Transparent" Offset="0" x:Name="gs2"/>
</LinearGradientBrush>
</Border.OpacityMask>
<Grid TextBlock.FontSize="16" Margin="0,3">
<TextBlock Text="I" VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="White"/>
<TextBlock Text="O" VerticalAlignment="Bottom" HorizontalAlignment="Center" Foreground="White"/>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation To="6,6,6,18"
Duration="0:0:0.2"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="Margin"/>
<DoubleAnimation To="0" Duration="0:0:0.2"
Storyboard.TargetName="gs1"
Storyboard.TargetProperty="Offset"/>
<DoubleAnimation To="1" Duration="0:0:0.2"
Storyboard.TargetName="gs2"
Storyboard.TargetProperty="Offset"/>
<PointAnimation To="0,1" Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="StartPoint"/>
<PointAnimation To="0,0" Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="EndPoint"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.2"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="Margin"/>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetName="gs1"
Storyboard.TargetProperty="Offset"/>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetName="gs2"
Storyboard.TargetProperty="Offset"/>
<PointAnimation Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="StartPoint"/>
<PointAnimation Duration="0:0:0.2"
Storyboard.TargetName="lgb"
Storyboard.TargetProperty="EndPoint"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
显示效果: