今天我们开始制作我们的按钮,主要的效果就是一个按钮正常状态、鼠标滑过、按下三态显示不同的图片。
首先我们需要给扩展按钮添加三个属性,分别是正常状态图片,鼠标滑过图片,按钮按下图片。
先贴出ButtonEx类
public class ButtonEx : Button { static ButtonEx() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ButtonEx), new FrameworkPropertyMetadata(typeof(ButtonEx))); } [CategoryAttribute("自定义属性"),DescriptionAttribute("获取或设置默认的背景图片")] public ImageSource NormalImage { get { return (ImageSource)GetValue(NormalImageProperty); } set { SetValue(NormalImageProperty, value); } } // Using a DependencyProperty as the backing store for NormalImage. This enables animation, styling, binding, etc... public static readonly DependencyProperty NormalImageProperty = DependencyProperty.Register("NormalImage", typeof(ImageSource), typeof(ButtonEx), null); [CategoryAttribute("自定义属性"),DescriptionAttribute("获取或设置鼠标滑过时的背景图片")] public ImageSource MouseOverImage { get { return (ImageSource)GetValue(MouseOverImageProperty); } set { SetValue(MouseOverImageProperty, value); } } // Using a DependencyProperty as the backing store for MouseOverImage. This enables animation, styling, binding, etc... public static readonly DependencyProperty MouseOverImageProperty = DependencyProperty.Register("MouseOverImage", typeof(ImageSource), typeof(ButtonEx), null); [CategoryAttribute("自定义属性"),DescriptionAttribute("获取或设置鼠按钮按下时的背景图片")] public ImageSource PressImage { get { return (ImageSource)GetValue(PressImageProperty); } set { SetValue(PressImageProperty, value); } } // Using a DependencyProperty as the backing store for PressImage. This enables animation, styling, binding, etc... public static readonly DependencyProperty PressImageProperty = DependencyProperty.Register("PressImage", typeof(ImageSource), typeof(ButtonEx), null); [Browsable(false)] public new Brush Background { get { return base.Background; } set { base.Background = value; } } [Browsable(false)] public new Brush BorderBrush { get { return base.BorderBrush; } set { base.BorderBrush = value; } } }
我们这里定义了主要的三个属性
下面通过xaml来定义样式
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfCustomControlLibrary1"> <Style TargetType="{x:Type local:ButtonEx}"> <!--Setter是一个设置器,用来设置该Style要对TargetType的哪些属性或对象进行设置,所以这里设置了ButtonEx属性NormalImage属性设置了一张图片--> <Setter Property="NormalImage" Value="/WpfCustomControlLibrary1;component/Images/button_normal.png"></Setter> <Setter Property="MouseOverImage" Value="/WpfCustomControlLibrary1;component/Images/button_hover.png"></Setter> <Setter Property="PressImage" Value="/WpfCustomControlLibrary1;component/Images/button_pushed.png"></Setter> <Setter Property="Width" Value="72"/> <Setter Property="Height" Value="28"/> <!--Template属性决定了将来ButtonEx的样式,该属性是ControlTemplate类型的--> <Setter Property="Template"> <Setter.Value> <!--实例化一个ControlTemplate实体,赋值给Template属性--> <ControlTemplate TargetType="{x:Type local:ButtonEx}"> <Grid> <!--用于指定控件处于特定状态时如何更改控件的外观,这是一组外观变化--> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <!--设置状态变化所需要的时间--> <VisualStateGroup.Transitions> <!--需要声明从什么状态变为另一种状态及状态变化所需要的时间--> <VisualTransition From="Noraml" To="MouseOver" GeneratedDuration="00:00:0.15" /> <VisualTransition From="MouseOver" To=" Normal" GeneratedDuration="00:00:0.15"/> <VisualTransition From="Pressed" To="MouseOver" GeneratedDuration="00:00:0.15"/> </VisualStateGroup.Transitions> <!--定义状态,自然状态,一个状态下需要几个特性,需要使用动画板来控制--> <VisualState x:Name="Normal"> <!--故事板能够用TargetProperty和TargetName属性指向一个特定的属性和特定的元素, 故事版在动画和希望应用动画的属性之间架起了一座桥梁,同一个故事版中放置几个动画, 并且每个动画可以用于不同的元素和属性--> <!--一个控制板将属性和动画联系在一起,当为自然状态下,将自然状态下的图片Opacity属性设置为1,然后将鼠标滑过和按下状态Opacity设置成0, 注意:一定要将后两种状态Opacity设置成0,不然有可能是1,这样可能得到我们不想要的效果--> <Storyboard> <!--动画有两种,一种是在一个开始值和结束值之间以逐步增加的方式(被称为线性插值过程)改变属性的动画, 以及从一个值突然变成另一个值的动画,第一种很好理解,第二种都是使用关键帧动画的技术,多数以 "类型名+AnimationUsingKeyFrames"的形式命名的,下面使用的就是这种动画类型--> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Normal" Storyboard.TargetProperty="(Opacity)"> <!--获取或设置应到达关键帧的目标 System.Windows.Media.Animation.DoubleKeyFrame.Value 的时间。获取或设置关键帧的目标值。--> <EasingDoubleKeyFrame KeyTime="0" Value="1"></EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_MouseOver" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"></EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pressed" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"></EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> <!--鼠标按下状态--> <VisualState x:Name="Pressed"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pressed" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="1"> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Normal" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_MouseOver" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"></EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_MouseOver" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="1"></EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Normal" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pressed" Storyboard.TargetProperty="Opacity"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!--这里放了一张图片元素,所以正常情况下,NormalImage属性图片会显示到按钮上--> <Image Source="{TemplateBinding NormalImage}" Name="PART_Normal"></Image> <Image Source="{TemplateBinding PressImage}" Name="PART_Pressed"></Image> <Image Source="{TemplateBinding MouseOverImage}" Name="PART_MouseOver"></Image> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> </Border> <!--绑定了ButtonEx的Content属性--> <ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
所有的难以理解的都加上注释了