擴展控件,顧名思義就是對已有的控件進行擴展,一般繼承於已有的原生控件,不排除繼承於自定義的控件,不過這樣做意義不大,因為既然都自定義了,為什么不一步到位呢,有些不同的需求也可以通過此來完成,不過類似於類繼承了。擴展控件本質也是類的繼承。下面我們通過兩個例子說明
一、自定義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自定義控件(五)の用戶控件
