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

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

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

一、自定义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自定义控件(五)の用户控件

目录
相关文章
|
4月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
|
4月前
|
C# 开发者 Windows
一款基于Fluent设计风格、现代化的WPF UI控件库
一款基于Fluent设计风格、现代化的WPF UI控件库
122 1
|
4月前
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
218 1
|
4月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
113 0
|
4月前
|
C# Windows 监控
WPF应用跨界成长秘籍:深度揭秘如何与Windows服务完美交互,扩展功能无界限!
【8月更文挑战第31天】WPF(Windows Presentation Foundation)是 .NET 框架下的图形界面技术,具有丰富的界面设计和灵活的客户端功能。在某些场景下,WPF 应用需与 Windows 服务交互以实现后台任务处理、系统监控等功能。本文探讨了两者交互的方法,并通过示例代码展示了如何扩展 WPF 应用的功能。首先介绍了 Windows 服务的基础知识,然后阐述了创建 Windows 服务、设计通信接口及 WPF 客户端调用服务的具体步骤。通过合理的交互设计,WPF 应用可获得更强的后台处理能力和系统级操作权限,提升应用的整体性能。
130 0
|
4月前
|
C# 前端开发 UED
WPF数据验证实战:内置控件与自定义规则,带你玩转前端数据验证,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据验证是确保输入正确性的关键环节。前端验证能及时发现错误,提升用户体验和程序可靠性。本文对比了几种常用的WPF数据验证方法,并通过示例展示了如何使用内置验证控件(如`TextBox`)及自定义验证规则实现有效验证。内置控件结合`Validation`类可快速实现简单验证;自定义规则则提供了更灵活的复杂逻辑支持。希望本文能帮助开发者更好地进行WPF数据验证。
157 0
|
4月前
|
C# UED 定位技术
WPF控件大全:初学者必读,掌握控件使用技巧,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,控件是实现用户界面交互的关键元素。WPF提供了丰富的控件库,包括基础控件(如`Button`、`TextBox`)、布局控件(如`StackPanel`、`Grid`)、数据绑定控件(如`ListBox`、`DataGrid`)等。本文将介绍这些控件的基本分类及使用技巧,并通过示例代码展示如何在项目中应用。合理选择控件并利用布局控件和数据绑定功能,可以提升用户体验和程序性能。
93 0
|
4月前
|
开发框架 前端开发 JavaScript
WPF应用开发之控件动态内容展示
WPF应用开发之控件动态内容展示
|
4月前
|
前端开发 C#
wpfui:一个开源免费具有现代化设计趋势的WPF控件库
wpfui:一个开源免费具有现代化设计趋势的WPF控件库
174 0
|
4月前
|
开发框架 前端开发 C#
使用WPF开发自定义用户控件,以及实现相关自定义事件的处理
使用WPF开发自定义用户控件,以及实现相关自定义事件的处理