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

一、自定义MButton

  • 控件外观控制的属性,如圆角、鼠标悬浮前景色背景色、是否开启动画(鼠标悬停时小图标转一圈,移开又转回去)、鼠标按下颜色等;
  • 字体图标相关属性,如字符值、字体图标大小、字体图标间距等。
  • 首先重写要修改的属性和添加要扩展的功能(在.cs中)
  •     public partial class MButton : Button
    {
    public static readonly DependencyProperty PressedBackgroundProperty =
    DependencyProperty.Register("PressedBackground", typeof(Brush), typeof(MButton), new PropertyMetadata(Brushes.DarkBlue));
    /// <summary>
    /// 鼠标按下背景样式
    /// </summary>
    public Brush PressedBackground
    {
    get { return (Brush)GetValue(PressedBackgroundProperty); }
    set { SetValue(PressedBackgroundProperty, value); }
    } public static readonly DependencyProperty PressedForegroundProperty =
    DependencyProperty.Register("PressedForeground", typeof(Brush), typeof(MButton), new PropertyMetadata(Brushes.White));
    /// <summary>
    /// 鼠标按下前景样式(图标、文字)
    /// </summary>
    public Brush PressedForeground
    {
    get { return (Brush)GetValue(PressedForegroundProperty); }
    set { SetValue(PressedForegroundProperty, value); }
    } public static readonly DependencyProperty MouseOverBackgroundProperty =
    DependencyProperty.Register("MouseOverBackground", typeof(Brush), typeof(MButton), new PropertyMetadata(Brushes.RoyalBlue));
    /// <summary>
    /// 鼠标进入背景样式
    /// </summary>
    public Brush MouseOverBackground
    {
    get { return (Brush)GetValue(MouseOverBackgroundProperty); }
    set { SetValue(MouseOverBackgroundProperty, value); }
    } public static readonly DependencyProperty MouseOverForegroundProperty =
    DependencyProperty.Register("MouseOverForeground", typeof(Brush), typeof(MButton), new PropertyMetadata(Brushes.White));
    /// <summary>
    /// 鼠标进入前景样式
    /// </summary>
    public Brush MouseOverForeground
    {
    get { return (Brush)GetValue(MouseOverForegroundProperty); }
    set { SetValue(MouseOverForegroundProperty, value); }
    } public static readonly DependencyProperty CornerRadiusProperty =
    DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MButton), new PropertyMetadata(new CornerRadius(2)));
    /// <summary>
    /// 按钮圆角大小,左上,右上,右下,左下
    /// </summary>
    public CornerRadius CornerRadius
    {
    get { return (CornerRadius)GetValue(CornerRadiusProperty); }
    set { SetValue(CornerRadiusProperty, value); }
    } public static readonly DependencyProperty ContentDecorationsProperty = DependencyProperty.Register(
    "ContentDecorations", typeof(TextDecorationCollection), typeof(MButton), new PropertyMetadata(null));
    public TextDecorationCollection ContentDecorations
    {
    get { return (TextDecorationCollection)GetValue(ContentDecorationsProperty); }
    set { SetValue(ContentDecorationsProperty, value); }
    } static FButton()
    {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(FButton), new FrameworkPropertyMetadata(typeof(FButton)));
    }
    }

      

下面是模板:

<!--MButton模板-->
<ControlTemplate x:Key="FButton_Template" TargetType="{x:Type local:MButton}">
<Border x:Name="border" Background="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Background}"
Height="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Height}"
CornerRadius="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=CornerRadius}"
Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Width}"> Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= FIcon}"
FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= FIconSize}"
Foreground="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Foreground}">
<TextBlock.RenderTransform>
<RotateTransform x:Name="transIcon" Angle="0"/>
</TextBlock.RenderTransform>
</TextBlock> <TextBlock VerticalAlignment="Center" x:Name="txt"
TextDecorations="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ContentDecorations}"
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}"
FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FontSize}"
Foreground="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Foreground}"></TextBlock>
</StackPanel>
</Border>
<!--触发器-->
<ControlTemplate.Triggers>
<!--设置鼠标进入时的背景、前景样式-->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=MouseOverBackground}" TargetName="border" />
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=MouseOverForeground}" TargetName="icon"/>
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=MouseOverForeground}" TargetName="txt"/>
</Trigger> <!--鼠标按下时的前景、背景样式-->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=PressedBackground}" TargetName="border" />
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=PressedForeground}" TargetName="icon"/>
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
Path=PressedForeground}" TargetName="txt"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.5" TargetName="border"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

  

下面是样式:

<!--默认样式-->
<Style TargetType="{x:Type local:MButton}">
<Setter Property="Background" Value="{StaticResource ButtonBackground}" />
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}" />
<Setter Property="MouseOverBackground" Value="{StaticResource ButtonMouseOverBackground}" />
<Setter Property="MouseOverForeground" Value="{StaticResource ButtonMouseOverForeground}" />
<Setter Property="PressedBackground" Value="{StaticResource ButtonPressedBackground}" />
<Setter Property="PressedForeground" Value="{StaticResource ButtonPressedForeground}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="30" />
<Setter Property="FontSize" Value="13" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Template" Value="{StaticResource FButton_Template}"/>
<Setter Property="Padding" Value="3,1,3,1" />
<Setter Property="Content" Value="{x:Null}" />
<Setter Property="AllowsAnimation" Value="False" />
</Style>

  

这样我们就万行了扩展Button

二、自定义TextBox

  这个TextBox可设置水印,可设置必填和正则表达式验证。

   就是在输入完成后,控件一旦失去焦点就会自动验证!会根据我开放出来的“是否可以为空”属性进行验证,一旦为空,则控件变为警告样式。

  但这还不是最特别的,为了各种手机号啊,邮箱啊的验证,我还开放了一个正则表达式的属性,在这个属性中填上正则表达式,同上, 一旦失去焦点就会自动验证输入的内容能否匹配正则表达式,如果不能匹配,则控件变为警告样式。

  之后,代码还可以通过我开放的另一个属性来判断当前输入框的输入是否有误。

 
 1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3 xmlns:ctrl="clr-namespace:KAN.WPF.XCtrl.Controls">
4 <Style TargetType="{x:Type ctrl:XTextBox}">
5 <!--StyleFocusVisual-->
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="BorderBrush" Value="Silver"/>
11 <Setter Property="BorderThickness" Value="1"/>
12 <Setter Property="Template">
13 <Setter.Value>
14 <ControlTemplate TargetType="{x:Type ctrl:XTextBox}">
15 <Border Name="brdText" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
16 BorderBrush="{TemplateBinding BorderBrush}" SnapsToDevicePixels="true" Padding="2">
17 <Grid>
18 <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
19 <StackPanel Orientation="Horizontal" Visibility="Collapsed" Name="stpWatermark">
20 <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center"
21 FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}"
22 Foreground="{Binding XWmkForeground, RelativeSource={RelativeSource TemplatedParent}}"
23 Text="{Binding XWmkText, RelativeSource={RelativeSource TemplatedParent}}" Cursor="IBeam" />
24 </StackPanel>
25 <ContentPresenter></ContentPresenter>
26 </Grid>
27 </Border>
28 <ControlTemplate.Triggers>
29 <!--当失去焦点并且没有输入任何内容时-->
30 <MultiTrigger>
31 <MultiTrigger.Conditions>
32 <Condition Property="Text" Value=""/>
33 <Condition Property="IsFocused" Value="False"/>
34 </MultiTrigger.Conditions>
35 <MultiTrigger.Setters>
36 <Setter Property="Visibility" TargetName="stpWatermark" Value="Visible"/>
37 </MultiTrigger.Setters>
38 </MultiTrigger>
39 <!--当验证失败时-->
40 <Trigger Property="XIsError" Value="true">
41 <Setter TargetName="brdText" Property="BorderBrush" Value="Red" />
42 <Setter TargetName="brdText" Property="Background" Value="Beige" />
43 </Trigger>
44 </ControlTemplate.Triggers>
45 </ControlTemplate>
46 </Setter.Value>
47 </Setter>
48 </Style>
49 </ResourceDictionary>
 

  再来看看CS:

 
  1 using System;
2 using System.Windows;
3 using System.Windows.Controls;
4 using System.Windows.Media;
5 using System.Windows.Input;
6 using System.Text.RegularExpressions;
7
8 namespace KAN.WPF.XCtrl.Controls
9 {
10 /// <summary>
11 /// 扩展输入框:可设置水印,可设置必填,可设置正则表达式验证
12 /// </summary>
13 public class XTextBox:TextBox
14 {
15 #region 依赖属性
16 public static readonly DependencyProperty XWmkTextProperty;//水印文字
17 public static readonly DependencyProperty XWmkForegroundProperty;//水印着色
18 public static readonly DependencyProperty XIsErrorProperty;//是否字段有误
19 public static readonly DependencyProperty XAllowNullProperty;//是否允许为空
20 public static readonly DependencyProperty XRegExpProperty;//正则表达式
21 #endregion
22
23 #region 内部方法
24 /// <summary>
25 /// 注册事件
26 /// </summary>
27 public XTextBox()
28 {
29 this.LostFocus += new RoutedEventHandler(XTextBox_LostFocus);
30 this.GotFocus += new RoutedEventHandler(XTextBox_GotFocus);
31 this.PreviewMouseDown += new MouseButtonEventHandler(XTextBox_PreviewMouseDown);
32 }
33
34 /// <summary>
35 /// 静态构造函数
36 /// </summary>
37 static XTextBox()
38 {
39 //注册依赖属性
40 XTextBox.XWmkTextProperty = DependencyProperty.Register("XWmkText", typeof(String), typeof(XTextBox), new PropertyMetadata(null));
41 XTextBox.XAllowNullProperty = DependencyProperty.Register("XAllowNull", typeof(bool), typeof(XTextBox), new PropertyMetadata(true));
42 XTextBox.XIsErrorProperty = DependencyProperty.Register("XIsError", typeof(bool), typeof(XTextBox), new PropertyMetadata(false));
43 XTextBox.XRegExpProperty = DependencyProperty.Register("XRegExp", typeof(string), typeof(XTextBox), new PropertyMetadata(""));
44 XTextBox.XWmkForegroundProperty = DependencyProperty.Register("XWmkForeground", typeof(Brush),
45 typeof(XTextBox), new PropertyMetadata(Brushes.Silver));
46 FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(XTextBox), new FrameworkPropertyMetadata(typeof(XTextBox)));
47 }
48
49 /// <summary>
50 /// 失去焦点时检查输入
51 /// </summary>
52 /// <param name="sender"></param>
53 /// <param name="e"></param>
54 void XTextBox_LostFocus(object sender, RoutedEventArgs e)
55 {
56 this.XIsError = false;
57 if (XAllowNull == false && this.Text.Trim() == "")
58 {
59 this.XIsError = true;
60 }
61 if (Regex.IsMatch(this.Text.Trim(), XRegExp) == false)
62 {
63 this.XIsError = true;
64 }
65 }
66
67 /// <summary>
68 /// 获得焦点时选中文字
69 /// </summary>
70 /// <param name="sender"></param>
71 /// <param name="e"></param>
72 void XTextBox_GotFocus(object sender, RoutedEventArgs e)
73 {
74 this.SelectAll();
75 }
76
77 /// <summary>
78 /// 鼠标点击时选中文字
79 /// </summary>
80 /// <param name="sender"></param>
81 /// <param name="e"></param>
82 void XTextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
83 {
84 if (this.IsFocused == false)
85 {
86 TextBox textBox = e.Source as TextBox;
87 textBox.Focus();
88 e.Handled = true;
89 }
90 }
91 #endregion
92
93 #region 公布属性
94 /// <summary>
95 /// 公布属性XWmkText(水印文字)
96 /// </summary>
97 public String XWmkText
98 {
99 get
100 {
101 return base.GetValue(XTextBox.XWmkTextProperty) as String;
102 }
103 set
104 {
105 base.SetValue(XTextBox.XWmkTextProperty, value);
106 }
107 }
108
109 /// <summary>
110 /// 公布属性XWmkForeground(水印着色)
111 /// </summary>
112 public Brush XWmkForeground
113 {
114 get
115 {
116 return base.GetValue(XTextBox.XWmkForegroundProperty) as Brush;
117 }
118 set
119 {
120 base.SetValue(XTextBox.XWmkForegroundProperty, value);
121 }
122 }
123
124 /// <summary>
125 /// 公布属性XIsError(是否字段有误)
126 /// </summary>
127 public bool XIsError
128 {
129 get
130 {
131 return (bool)base.GetValue(XTextBox.XIsErrorProperty);
132 }
133 set
134 {
135 base.SetValue(XTextBox.XIsErrorProperty, value);
136 }
137 }
138
139 /// <summary>
140 /// 公布属性XAllowNull(是否允许为空)
141 /// </summary>
142 public bool XAllowNull
143 {
144 get
145 {
146 return (bool)base.GetValue(XTextBox.XAllowNullProperty);
147 }
148 set
149 {
150 base.SetValue(XTextBox.XAllowNullProperty, value);
151 }
152 }
153
154 /// <summary>
155 /// 公布属性XRegExp(正则表达式)
156 /// </summary>
157 public string XRegExp
158 {
159 get
160 {
161 return base.GetValue(XTextBox.XRegExpProperty) as string;
162 }
163 set
164 {
165 base.SetValue(XTextBox.XRegExpProperty, value);
166 }
167 }
168 #endregion
169 }
170 }

好了,扩展控件就介绍完了

自定义控件系列博文链接:

WPF自定义控件(一)の控件分类
WPF自定义控件(二)の重写原生控件样式模板
WPF自定义控件(三)の扩展控件
WPF自定义控件(四)の自定义控件
WPF自定义控件(五)の用户控件

WPF自定义控件(三)の扩展控件的更多相关文章

  1. WPF自定义控件之图片控件 AsyncImage

    AsyncImage 是一个封装完善,使用简便,功能齐全的WPF图片控件,比直接使用Image相对来说更加方便,但它的内部仍然使用Image承载图像,只不过在其基础上进行了一次完善成熟的封装 Asyn ...

  2. WPF自定义控件二:Border控件与TextBlock控件轮播动画

    需求:实现Border轮播动画与TextBlock动画 XAML代码如下: <Window.Resources> <Storyboard x:Key="OnLoaded1& ...

  3. CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)

    事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便支持wpf的开发,同时,框架仍保留最低.net framework2.0 ...

  4. CYQ.Data 支持WPF相关的数据控件绑定.Net获取iis版本

    CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09) 事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便 ...

  5. C# 自定义控件VS用户控件

    1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...

  6. 在WPF中使用WinForm控件方法

    1.      首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,System.Windows.Forms.dll. 2.      在要使用WinForm控 ...

  7. WPF中的image控件的Source赋值

    WPF中的Image控件Source的设置 1.XAML中 简单的方式(Source="haha.png"); image控件的Source设置为相对路径后(Source=&quo ...

  8. WPF后台设置xaml控件的样式System.Windows.Style

    WPF后台设置xaml控件的样式System.Windows.Style 摘-自 :感谢 作者: IT小兵   http://3w.suchso.com/projecteac-tual/wpf-zhi ...

  9. WPF Step By Step 控件介绍

    WPF Step By Step 控件介绍 回顾 上一篇,我们主要讨论了WPF的几个重点的基本知识的介绍,本篇,我们将会简单的介绍几个基本控件的简单用法,本文会举几个项目中的具体的例子,结合这些 例子 ...

随机推荐

  1. [android] android下创建一个sqlite数据库

    Sqlite数据库是开源的c语言写的数据库,android和iphone都使用的这个,首先需要创建数据库,然后创建表和字段,android提供了一个api叫SQLiteOpenHelper数据库的打开 ...

  2. 【转】消除代码中的 if-else/switch-case

    在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去实现.做的不好的会直接把实现的代码放在 if-else/swit ...

  3. 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)

    jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了.首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构.而对于 ...

  4. 小tips:JS数值之间的转换,JS中最大的Number是多少?,JS == 与 === 的区别

    JS数值之间的转换 Number(), parseInt(),parseFloat() Number()函数的转换规则如下: 1.如果boolean值,true和false将分别被转换为1和02.如果 ...

  5. Mixing a dll boost library with a static runtime is a really bad idea错误的解决

    作者:朱金灿 来源:http://blog.csdn.net/clever101 同事在使用boost库时遇到一个问题,在编译时出现一个错误:Mixing a dll boost library wi ...

  6. Xcode常用的文件路径

    1.Provisioning Profile文件在哪找? ~/Library/MobileDevice/Provisioning Profiles 2.master 在那找? ~/.cocoapods

  7. Android string.xml 添加特殊字符

    解决项目中在string.xml 中显示特殊符号的问题,如@号冒号等.只能考虑使用ASCII码进行显示: @号 @ :号 : 空格   以下为常见的ASCII十进制交换编码: --> <- ...

  8. [Android][Framework] 添加系统服务

    新博客地址 http://wossoneri.github.io/2018/09/15/[Android][Framework]create-system-service/ 做系统开发,有时候需要自己 ...

  9. 关于js脚本宿主对脚本代码的绑定

    脚本代码绑定,Unity3D是这样做的.为了体现Unity3D的基于对象设计,Unity3D可以为每个对象绑定多个脚本文件,可以是js,可以是cs,也可以是boo. threejs/editor也有与 ...

  10. ERP项目应该由谁来主导?

    前段时间在朋友圈看到了别人分享的公众号,主要是谈ERP项目应该由谁来主导的问题.文章的观点认为应该由哪个部门主导ERP的判断标准如下: 1.应该由一个期望上进的部门主导ERP项目: 2.应该由一个有话 ...