有时需要用三张图片(正常状态,鼠标移上,鼠标按下)来作为一个按钮的样式,虽然这种做法不好,应该用矢量的方式制作样式,但有的时候还是需要这样做的。
每次都修改按钮的样式来实现这个做法,既麻烦又会生成大段的XAML代码,不利于维护,抽出一个自定义图片按钮控件,只需传入三张图片的路径即可使用,显然是更好的做法,下面就演示一下如何编写这个控件,VS2015和Blend2015结合使用。
1. 首先,在VS中新建一个WPF自定义控件库,命名为WpfCustomControlLibrary,系统会自动生成一个CustomControl1类,并生成一个Themes文件夹,其中包含一个资源字典文件Generic.xaml。如果打开AssemblyInfo.cs文件,会看到包含如下代码,
class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">[assembly:ThemeInfo( ResourceDictionaryLocation.None, //主题特定资源词典所处位置 //(在页面、应用程序或任何主题特定资源词典中 // 未找到某个资源的情况下使用) ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 //(在页面、应用程序或任何主题特定资源词典中 // 未找到某个资源的情况下使用) )]
这段代码指明在Themes文件夹下的Generic.xaml资源字典中包含控件的默认样式,这正是WPF自定义控件库和一般程序集的区别。
2. 将CustomControl1类改为ImageButton
此时的初始代码如下,
public class ImageButton : Control { static ImageButton() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton))); } }
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfCustomControlLibrary"> <Style TargetType="{x:Type local:ImageButton}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ImageButton}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
3. 把ImageButton的基类改为Button。
4. 在ImageButton中加入三个依赖属性,如下
public static readonly DependencyProperty NormalImageProperty = DependencyProperty.RegisterAttached("NormalImage", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(null)); public ImageSource NormalImage { get { return (ImageSource)GetValue(NormalImageProperty); } set { SetValue(NormalImageProperty, value); } } public static readonly DependencyProperty MouseOverImageProperty = DependencyProperty.RegisterAttached("MouseOverImage", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(null)); public ImageSource MouseOverImage { get { return (ImageSource)GetValue(MouseOverImageProperty); } set { SetValue(MouseOverImageProperty, value); } } public static readonly DependencyProperty PressedImageProperty = DependencyProperty.RegisterAttached("PressedImage", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(null)); public ImageSource PressedImage { get { return (ImageSource)GetValue(PressedImageProperty); } set { SetValue(PressedImageProperty, value); } }
5. 新建一个WPF应用程序项目引用该自定义控件库,在一个页面中,加入ImageButton控件。选中ImageButton控件,点击美工板导航栏中的[ImageButton],在弹出的菜单中选择编辑模板-编辑副本,在弹出的对话框中输入ImageButtonStyle,选择该文档,点击确定。
6. 在模板编辑状态下,右键点击文档大纲面板中的[Border],选择更改布局类型-Grid,然后将Grid的背景清空。向Grid中加入三个Image控件,并重置布局。可从资产面板加入,可在资产面板的搜索栏中输入Image查找。将三个Image的Width和Height清空,将Stretch属性改为None。
7. 将三个Image的Source属性从上到下分别改为模板绑定NormalImage,PressedImage和MouseOverImage,修改方法为在属性面板中点击Source属性右边的小方块,选择模板绑定-NormalImage。把PressedImage和MouseOverImage的Image的Visibility属性改为Collapsed。
8. 在状态面板中,点击MouseOver,在文档大纲面板中,选择第一个Image控件,在属性面板中,将Visibility属性改为Collapsed。选择第三个也就是MouseOverImage的Image控件,在属性面板中,将Visibility属性改为Visible。
在状态面板中,点击Pressed,在文档大纲面板中,选择第一个Image控件,在属性面板中,将Visibility属性改为Collapsed。选择第二个也就是PressedImage的Image控件,在属性面板中,将Visibility属性改为Visible。
此时ImageButtonStyle的代码如下,
<Style TargetType="{x:Type local:ImageButton}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ImageButton}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="image"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="image1"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="image"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="image2"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Image x:Name="image" Source="{TemplateBinding NormalImage}" Stretch="None"/> <Image x:Name="image2" Source="{TemplateBinding PressedImage}" Stretch="None" Visibility="Collapsed"/> <Image x:Name="image1" Source="{TemplateBinding MouseOverImage}" Stretch="None" Visibility="Collapsed"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
9. 用这个Style中的ControlTemple部分替换自定义控件库中的Themes文件夹下的Generic.xaml文件中的ImageButton样式的ControlTemple部分。注意修改TargetType为{x:Type local:ImageButton}"。
10. 这时图片按钮控件已经完成了,在WPF应用程序项目中的一个页面上,从资产面板中加入ImageButton控件(选择项目分类)。选择ImageButton控件,在属性面板中可以看到,在杂项组下,存在NormalImage,MouseOverImage和PressedImage三个属性,可分别设置图片。
11. 把这三个属性设置三张合适的图片,图片按钮即可使用。