接触WPF也有两个多月了,有了一定的理论基础和项目经验,现在打算写一个系列,做出来一个WPF的控件库。一方面可以加强自己的水平,另一方面可以给正在学习WPF的同行一个参考。本人水平有限,难免有一些错误,望各位指出!

  先上图看看各种效果:

  这个Button是我继承系统Button后扩展的,主要实现了:可设置悬浮和按下时的背景,可改变形状,并可设置按钮按下后保持锁定状态等功能。

  这个Button我命名为XButton,扩展的所有属性我都会以X开头命名。好了,具体的东西看代码吧!

  先来Xaml的:

  

  1. <ResourceDictionary
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:ctrl="clr-namespace:KAN.WPF.XCtrl.Controls">
  5. <Style x:Key="{x:Type ctrl:XButton}" TargetType="{x:Type ctrl:XButton}">
  6. <Style.Resources>
  7. <ResourceDictionary Source="/KAN.WPF.Xctrl;component/Themes/CommonStyle.xaml"/>
  8. </Style.Resources>
  9. <Setter Property="FocusVisualStyle" Value="{StaticResource StyleFocusVisual}"/>
  10. <Setter Property="Background" Value="White"/>
  11. <Setter Property="BorderBrush" Value="Silver"/>
  12. <Setter Property="BorderThickness" Value="1"/>
  13. <Setter Property="Control.Template">
  14. <Setter.Value>
  15. <ControlTemplate TargetType="{x:Type ctrl:XButton}">
  16. <!--定义视觉树-->
  17. <Grid>
  18. <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
  19. <!--这里的Path就是用来实现各种外形的-->
  20. <Path x:Name="bdrButton"
  21. Data="{Binding XShape, RelativeSource={RelativeSource TemplatedParent}}"
  22. Stroke="{Binding XStrokeBrush, RelativeSource={RelativeSource TemplatedParent}}"
  23. StrokeThickness="{Binding XStrokeThickness, RelativeSource={RelativeSource TemplatedParent}}"
  24. Stretch="Fill" RenderTransformOrigin="0.5,0.5" Fill="{TemplateBinding Control.Background}">
  25. <Path.RenderTransform>
  26. <TransformGroup>
  27. <ScaleTransform/>
  28. <SkewTransform/>
  29. <RotateTransform/>
  30. <TranslateTransform/>
  31. </TransformGroup>
  32. </Path.RenderTransform>
  33. </Path>
  34. </Border>
  35. <ContentPresenter Name="contentPresenter" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
  36. ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" Focusable="False" RecognizesAccessKey="True"
  37. SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" Content="{TemplateBinding ContentControl.Content}"
  38. HorizontalAlignment="Center" VerticalAlignment="Center" />
  39. </Grid>
  40. <!--设置触发器-->
  41. <ControlTemplate.Triggers>
  42. <!--鼠标移动上去时-->
  43. <Trigger Property="UIElement.IsMouseOver" Value="True" >
  44. <Setter TargetName="bdrButton" Value="{Binding XMoverBrush, RelativeSource={RelativeSource TemplatedParent}}" Property="Path.Fill" />
  45. </Trigger>
  46. <!--鼠标按下去时-->
  47. <Trigger Property="ButtonBase.IsPressed" Value="True">
  48. <Setter TargetName="bdrButton" Value="{Binding XEnterBrush, RelativeSource={RelativeSource TemplatedParent}}" Property="Path.Fill" />
  49. </Trigger>
  50. <!--禁用Button时-->
  51. <Trigger Property="IsEnabled" Value="false">
  52. <Setter TargetName="bdrButton" Value="{Binding XUnEnabledBrush, RelativeSource={RelativeSource TemplatedParent}}" Property="Path.Fill" />
  53. </Trigger>
  54. <!--如果设置了锁住按下的状态的属性,那么当按下时-->
  55. <MultiTrigger>
  56. <MultiTrigger.Conditions>
  57. <Condition Property="IsFocused" Value="True"/>
  58. <Condition Property="XIsFoucedBrushLock" Value="True"/>
  59. </MultiTrigger.Conditions>
  60. <MultiTrigger.Setters>
  61. <Setter TargetName="bdrButton" Value="{Binding XEnterBrush, RelativeSource={RelativeSource TemplatedParent}}" Property="Path.Fill" />
  62. </MultiTrigger.Setters>
  63. </MultiTrigger>
  64. </ControlTemplate.Triggers>
  65. </ControlTemplate>
  66. </Setter.Value>
  67. </Setter>
  68. </Style>
  69. </ResourceDictionary>

  其中的StyleFocusVisual是用来定义按Tab到这个控件上的样式的,代码如下:

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  3. <Style x:Key="StyleFocusVisual">
  4. <Setter Property="Control.Template">
  5. <Setter.Value>
  6. <ControlTemplate>
  7. <Border Margin="0" BorderBrush="#FF9FBDF4" BorderThickness="1"/>
  8. </ControlTemplate>
  9. </Setter.Value>
  10. </Setter>
  11. </Style>
  12. </ResourceDictionary>

  接下来是CS的:

  

  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Media;
  5. using System.Windows.Shapes;
  6. using System.Windows.Media.Imaging;
  7.  
  8. namespace KAN.WPF.XCtrl.Controls
  9. {
  10. /// <summary>
  11. /// 扩展按钮:可设置悬浮和按下时的背景,可改变形状,并可设置按钮按下后保持锁定状态
  12. /// </summary>
  13. public class XButton : Button
  14. {
  15. #region 依赖属性
  16. public static readonly DependencyProperty XMoverBrushProperty;//鼠标经过时的画刷
  17. public static readonly DependencyProperty XEnterBrushProperty;//鼠标按下时的画刷
  18. public static readonly DependencyProperty XUnEnabledBrushProperty;//禁用时的画刷
  19. public static readonly DependencyProperty XIsFoucedBrushLockProperty;//是否得到焦点时锁住画刷
  20. public static readonly DependencyProperty XShapeProperty;//外形的路径
  21. public static readonly DependencyProperty XStrokeBrushProperty;//外形的路径着色
  22. public static readonly DependencyProperty XStrokeThicknessProperty;//外形的路径粗细(默认为0,因为有Border边框,所以要设这个值,要先把BorderThickness设为0)
  23. #endregion
  24.  
  25. #region 内部方法
  26. /// <summary>
  27. /// 静态构造方法
  28. /// </summary>
  29. static XButton()
  30. {
  31. //注册依赖属性
  32. XButton.XMoverBrushProperty = DependencyProperty.Register("XMoverBrush", typeof(Brush), typeof(XButton),
  33. new PropertyMetadata(Brushes.WhiteSmoke));
  34. XButton.XEnterBrushProperty = DependencyProperty.Register("XEnterBrush", typeof(Brush), typeof(XButton),
  35. new PropertyMetadata(Brushes.Silver));
  36. XButton.XUnEnabledBrushProperty = DependencyProperty.Register("XUnEnabledBrush", typeof(Brush), typeof(XButton),
  37. new PropertyMetadata(Brushes.Silver));
  38. XButton.XStrokeBrushProperty = DependencyProperty.Register("XStrokeBrush", typeof(Brush), typeof(XButton),
  39. new PropertyMetadata(Brushes.Silver));
  40. XButton.XStrokeThicknessProperty = DependencyProperty.Register("XStrokeThickness", typeof(Double), typeof(XButton),
  41. new PropertyMetadata(0.0));
  42. XButton.XIsFoucedBrushLockProperty = DependencyProperty.Register("XIsFoucedBrushLock", typeof(bool), typeof(XButton),
  43. new PropertyMetadata(false));
  44. XButton.XShapeProperty = DependencyProperty.Register("XShape", typeof(string), typeof(XButton),
  45. new PropertyMetadata("M 0 0 L 0 0 L 100 0 L 100 100 L 0 100 Z"));
  46. FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(XButton), new FrameworkPropertyMetadata(typeof(XButton)));
  47. }
  48. #endregion
  49.  
  50. #region 公布属性
  51. /// <summary>
  52. /// 公布属性XMoverBrush(鼠标经过时的画刷)
  53. /// </summary>
  54. public Brush XMoverBrush
  55. {
  56. get
  57. {
  58. return base.GetValue(XButton.XMoverBrushProperty) as Brush;
  59. }
  60. set
  61. {
  62. base.SetValue(XButton.XMoverBrushProperty, value);
  63. }
  64. }
  65.  
  66. /// <summary>
  67. /// 公布属性XMoverBrush(鼠标按下时的画刷)
  68. /// </summary>
  69. public Brush XEnterBrush
  70. {
  71. get
  72. {
  73. return base.GetValue(XButton.XEnterBrushProperty) as Brush;
  74. }
  75. set
  76. {
  77. base.SetValue(XButton.XEnterBrushProperty, value);
  78. }
  79. }
  80.  
  81. /// <summary>
  82. /// 公布属性XUnEnabledBrush(禁用时的画刷)
  83. /// </summary>
  84. public Brush XUnEnabledBrush
  85. {
  86. get
  87. {
  88. return base.GetValue(XButton.XUnEnabledBrushProperty) as Brush;
  89. }
  90. set
  91. {
  92. base.SetValue(XButton.XUnEnabledBrushProperty, value);
  93. }
  94. }
  95.  
  96. /// <summary>
  97. /// 公布属性XIsFoucedBrushLock(是否得到焦点时锁住画刷)
  98. /// </summary>
  99. public bool XIsFoucedBrushLock
  100. {
  101. get
  102. {
  103. return (bool)base.GetValue(XButton.XIsFoucedBrushLockProperty);
  104. }
  105. set
  106. {
  107. base.SetValue(XButton.XIsFoucedBrushLockProperty, value);
  108. }
  109. }
  110.  
  111. /// <summary>
  112. /// 公布属性XShape(外形的路径)
  113. /// </summary>
  114. public String XShape
  115. {
  116. get
  117. {
  118. return base.GetValue(XButton.XShapeProperty) as String;
  119. }
  120. set
  121. {
  122. base.SetValue(XButton.XShapeProperty, value);
  123. }
  124. }
  125.  
  126. /// <summary>
  127. /// 公布属性XStrokeBrush(外形的路径着色)
  128. /// </summary>
  129. public Brush XStrokeBrush
  130. {
  131. get
  132. {
  133. return base.GetValue(XButton.XStrokeBrushProperty) as Brush;
  134. }
  135. set
  136. {
  137. base.SetValue(XButton.XStrokeBrushProperty, value);
  138. }
  139. }
  140.  
  141. /// <summary>
  142. /// 公布属性XStrokeThickness(外形的路径粗细)
  143. /// </summary>
  144. public Double XStrokeThickness
  145. {
  146. get
  147. {
  148. return (Double)base.GetValue(XButton.XStrokeThicknessProperty);
  149. }
  150. set
  151. {
  152. base.SetValue(XButton.XStrokeThicknessProperty, value);
  153. }
  154. }
  155. #endregion
  156. }
  157. }

  看了代码上的注释应该都能明白吧!要是有不明白的可以留言。

  至于源代码,我之后会整理几个控件后一起发上来的!

WPF自定义控件(一)——Button的更多相关文章

  1. WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要是对文本 ...

  2. WPF自定义控件与样式(2)-自定义按钮FButton

    一.前言.效果图 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 还是先看看效果 ...

  3. WPF自定义控件与样式(15)-终结篇 & 系列文章索引 & 源码共享

    系列文章目录  WPF自定义控件与样式(1)-矢量字体图标(iconfont) WPF自定义控件与样式(2)-自定义按钮FButton WPF自定义控件与样式(3)-TextBox & Ric ...

  4. WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 日历控 ...

  5. WPF自定义控件与样式(15)-终结篇

    原文:WPF自定义控件与样式(15)-终结篇 系列文章目录  WPF自定义控件与样式(1)-矢量字体图标(iconfont) WPF自定义控件与样式(2)-自定义按钮FButton WPF自定义控件与 ...

  6. WPF自定义控件创建

    WPF自定义控件创建 本文简单的介绍一下WPF自定义控件的开发. 首先,我们打开VisualStudio创建一个WPF自定义控件库,如下图: 然后,我们可以看到创建的解决方案如下: 在解决方案中,我们 ...

  7. WPF自定义控件(三)の扩展控件

    扩展控件,顾名思义就是对已有的控件进行扩展,一般继承于已有的原生控件,不排除继承于自定义的控件,不过这样做意义不大,因为既然都自定义了,为什么不一步到位呢,有些不同的需求也可以通过此来完成,不过类似于 ...

  8. WPF自定义控件(二)の重写原生控件样式模板

    话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式. 开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么 ...

  9. WPF自定义控件(一)の控件分类

    一.什么是控件(Controls) 控件是指对数据和方法的封装.控件可以有自己的属性和方法,其中属性是控件数据的简单访问者,方法则是控件的一些简单而可见的功能.控件创建过程包括设计.开发.调试(就是所 ...

  10. 【转】WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要内容: 日历控件Calendar自定义样式: 日期控件DatePicker自定 ...

随机推荐

  1. HDU1213

    http://acm.split.hdu.edu.cn/showproblem.php?pid=1213 #include<stdio.h> #include<algorithm&g ...

  2. 利用UDP19端口实施DOS攻击的真实案例

    昨天在一个用户现场发现了一个利用UDP19端口对互联网受害者主机进行DOS攻击的真实案例.这个情况是我第一次见到,个人认为对以后遇到此类情况的兄弟具有参考价值.有必要做一个简单的分析记录. 在此次的分 ...

  3. android界面布局技巧(一)

    (1)//得到手机的宽高 Display display = getWindowManager().getDefaultDisplay(); int screenWidth = display.get ...

  4. Flask框架学习笔记(API接口管理平台 V1.0)

    今天博主终于完成了API接口管理平台,最后差的就是数据库的维护, 博主这里介绍下平台的设计原理,首先基于python,利用flask的web框架+bootstrap前端框架完成,先阶段完成了前台展示页 ...

  5. git克隆项目到一个非空目录

    这只是记录: 1. 进入非空目录,假设是 /workdir/proj1 2. git clone --no-checkout https://git.oschina.net/NextApp/platf ...

  6. 【CImg】简单的畸变矩形矫正

    三个角点确定一个平面,畸变的平面可以看成是不同基底下同一图像的表示 ============================我是分割线============================= 1. ...

  7. Android开发-API指南-<instrumentation >

    <instrumentation> 英文原文:http://developer.android.com/guide/topics/manifest/instrumentation-elem ...

  8. Swift学习—字符串&数组&字典

    字符串 OC和Swift中字符串的区别 在OC中字符串类型时NSString,在Swift中字符串类型是String OC中字符串@"",Swift中字符串"" ...

  9. rsync安装使用

    安装 yum install rsync mkdir /etc/rsyncd cd /etc/rsyncd vi rsyncd.conf pid file = /var/run/rsyncd.pid ...

  10. SQL where 1=1的作用

    浅谈where 1=1 1.简单理解的话where 1=1 永真, where 1<>1 永假 2.1<>1 的用处:     用于只取结构不取数据的场合     例如:    ...