博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【转】WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展...
阅读量:6708 次
发布时间:2019-06-25

本文共 18569 字,大约阅读时间需要 61 分钟。

一.前言.预览

  申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等。

本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括:

  • 基本文本框TextBox控件样式及扩展功能,实现了样式、水印、Label标签、功能扩展;
  • 富文本框RichTextBox控件样式;
  • 密码输入框PasswordBox控件样式及扩展功能;

效果图:

二.基本文本框TextBox控件样式及扩展功能

2.1 TextBox基本样式

样式代码如下:  

模板内容主要包含四部分:

  • 用于实现Label标签的预留区域;
  • TextBox本身的文本输入显示部分;
  • 水印显示部分;
  • 功能扩展的预留区域;

  其中Label标签、功能扩展,还有输入框的不同状态显示效果都是通过附加属性来实现的,其实从本质上附加属性和控件上定义的依赖属性是同一个概念,有些时候附加属性会更加方便,对于一些可共用的属性,就比较方便,这一点怎本文是有体现的。上面代码使用到的附加属性代码:

#region FocusBorderBrush 焦点边框色,输入控件        public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached(            "FocusBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));        public static void SetFocusBorderBrush(DependencyObject element, Brush value)        {            element.SetValue(FocusBorderBrushProperty, value);        }        public static Brush GetFocusBorderBrush(DependencyObject element)        {            return (Brush)element.GetValue(FocusBorderBrushProperty);        }        #endregion        #region MouseOverBorderBrush 鼠标进入边框色,输入控件        public static readonly DependencyProperty MouseOverBorderBrushProperty =            DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty),                new FrameworkPropertyMetadata(Brushes.Transparent,                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));        ///         /// Sets the brush used to draw the mouse over brush.        ///         public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value)        {            obj.SetValue(MouseOverBorderBrushProperty, value);        }        ///         /// Gets the brush used to draw the mouse over brush.        ///         [AttachedPropertyBrowsableForType(typeof(TextBox))]        [AttachedPropertyBrowsableForType(typeof(CheckBox))]        [AttachedPropertyBrowsableForType(typeof(RadioButton))]        [AttachedPropertyBrowsableForType(typeof(DatePicker))]        [AttachedPropertyBrowsableForType(typeof(ComboBox))]        [AttachedPropertyBrowsableForType(typeof(RichTextBox))]        public static Brush GetMouseOverBorderBrush(DependencyObject obj)        {            return (Brush)obj.GetValue(MouseOverBorderBrushProperty);        }        #endregion        #region AttachContentProperty 附加组件模板        ///         /// 附加组件模板        ///         public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached(            "AttachContent", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));        public static ControlTemplate GetAttachContent(DependencyObject d)        {            return (ControlTemplate)d.GetValue(AttachContentProperty);        }        public static void SetAttachContent(DependencyObject obj, ControlTemplate value)        {            obj.SetValue(AttachContentProperty, value);        }        #endregion        #region WatermarkProperty 水印        ///         /// 水印        ///         public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(            "Watermark", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));        public static string GetWatermark(DependencyObject d)        {            return (string)d.GetValue(WatermarkProperty);        }        public static void SetWatermark(DependencyObject obj, string value)        {            obj.SetValue(WatermarkProperty, value);        }        #endregion        #region CornerRadiusProperty Border圆角        ///         /// Border圆角        ///         public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(            "CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));        public static CornerRadius GetCornerRadius(DependencyObject d)        {            return (CornerRadius)d.GetValue(CornerRadiusProperty);        }        public static void SetCornerRadius(DependencyObject obj, CornerRadius value)        {            obj.SetValue(CornerRadiusProperty, value);        }        #endregion        #region LabelProperty TextBox的头部Label        ///         /// TextBox的头部Label        ///         public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached(            "Label", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static string GetLabel(DependencyObject d)        {            return (string)d.GetValue(LabelProperty);        }        public static void SetLabel(DependencyObject obj, string value)        {            obj.SetValue(LabelProperty, value);        }        #endregion        #region LabelTemplateProperty TextBox的头部Label模板        ///         /// TextBox的头部Label模板        ///         public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached(            "LabelTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static ControlTemplate GetLabelTemplate(DependencyObject d)        {            return (ControlTemplate)d.GetValue(LabelTemplateProperty);        }        public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value)        {            obj.SetValue(LabelTemplateProperty, value);        }        #endregion

2.2 水印效果实现

  通过2.1的代码示例,可以看出,水印是内置了一个TextBlock,用附加属性ControlAttachProperty.Watermark设置水印内容,在触发器中检测,当TextBox中有输入值,则隐藏水印的TextBlock,使用示例:  

333333333333333
我是只读的
IsEnabled="False"

 效果:

  

2.3 Label标签实现

  参考2.1的代码,预留了Label的区域,通过设置附加属性local:ControlAttachProperty.Label设置标签文本,local:ControlAttachProperty.LabelTemplate设置Label标签的模板样式,即可自定义实现Label标签,自定义样式:

使用示例及效果: 

2.4 扩展功能及自定义扩展

  思路和2.3的Label标签实现相似,清除文本框内的内容是一个常用需求,我们就线扩展一个这么一个功能的TextBox,通过附加属性ControlAttachProperty.AttachContent定义扩展功能的模板,模板内定义的是一个按钮FButton(可参考上一篇,本文末尾附录中有链接)  

这里定义的是显示效果,清除TextBox内容的逻辑代码如何实现的呢?还是附加属性:

  • ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" :注入事件到当前Button
  • Command="local:ControlAttachProperty.ClearTextCommand":定义Fbutton的命令对象实例Command
  • CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}":把TextBox作为参数传入

  逻辑代码如下,从代码不难看出,它是支持多种输入控件的内容清除的,也就是说该扩展功能可以轻松支持其他输入控件,第四节密码数据的清除也是这样使用的。

#region IsClearTextButtonBehaviorEnabledProperty 清除输入框Text值按钮行为开关(设为ture时才会绑定事件)        ///         /// 清除输入框Text值按钮行为开关        ///         public static readonly DependencyProperty IsClearTextButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsClearTextButtonBehaviorEnabled"            , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsClearTextButtonBehaviorEnabledChanged));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static bool GetIsClearTextButtonBehaviorEnabled(DependencyObject d)        {            return (bool)d.GetValue(IsClearTextButtonBehaviorEnabledProperty);        }        public static void SetIsClearTextButtonBehaviorEnabled(DependencyObject obj, bool value)        {            obj.SetValue(IsClearTextButtonBehaviorEnabledProperty, value);        }        ///         /// 绑定清除Text操作的按钮事件        ///         private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            var button = d as FButton;            if (e.OldValue != e.NewValue && button != null)            {                button.CommandBindings.Add(ClearTextCommandBinding);            }        }        #endregion        #region ClearTextCommand 清除输入框Text事件命令        ///         /// 清除输入框Text事件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令        ///         public static RoutedUICommand ClearTextCommand { get; private set; }        ///         /// ClearTextCommand绑定事件        ///         private static readonly CommandBinding ClearTextCommandBinding;        ///         /// 清除输入框文本值        ///         private static void ClearButtonClick(object sender, ExecutedRoutedEventArgs e)        {            var tbox = e.Parameter as FrameworkElement;            if (tbox == null) return;            if (tbox is TextBox)            {                ((TextBox)tbox).Clear();            }            if (tbox is PasswordBox)            {                ((PasswordBox)tbox).Clear();            }            if (tbox is ComboBox)            {                var cb = tbox as ComboBox;                cb.SelectedItem = null;                cb.Text = string.Empty;            }            if (tbox is MultiComboBox)            {                var cb = tbox as MultiComboBox;                cb.SelectedItem = null;                cb.UnselectAll();                cb.Text = string.Empty;            }            if (tbox is DatePicker)            {                var dp = tbox as DatePicker;                dp.SelectedDate = null;                dp.Text = string.Empty;            }            tbox.Focus();        }        #endregion        ///         /// 静态构造函数        ///         static ControlAttachProperty()        {            //ClearTextCommand            ClearTextCommand = new RoutedUICommand();            ClearTextCommandBinding = new CommandBinding(ClearTextCommand);            ClearTextCommandBinding.Executed += ClearButtonClick;            //OpenFileCommand            OpenFileCommand = new RoutedUICommand();            OpenFileCommandBinding = new CommandBinding(OpenFileCommand);            OpenFileCommandBinding.Executed += OpenFileButtonClick;            //OpenFolderCommand            OpenFolderCommand = new RoutedUICommand();            OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);            OpenFolderCommandBinding.Executed += OpenFolderButtonClick;            SaveFileCommand = new RoutedUICommand();            SaveFileCommandBinding = new CommandBinding(SaveFileCommand);            SaveFileCommandBinding.Executed += SaveFileButtonClick;        }

效果:

  

当然我们也可以自定义扩展其他功能,如:  

效果:

由上不难同时实现Label标签和清除文本内容的样式:

2.6 文件选择输入相关扩展

  先看看效果,就明白了。

   

具体实现原理和上面2.4差不多 ,实现了三个文件、文件夹选择相关的功能扩展,样式代码:

当然实现原理和2.4一样,都是依赖属性来实现事件的注入和绑定的,所以就不多废话了:

#region IsOpenFileButtonBehaviorEnabledProperty 选择文件命令行为开关        ///         /// 选择文件命令行为开关        ///         public static readonly DependencyProperty IsOpenFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFileButtonBehaviorEnabled"            , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFileButtonBehaviorEnabledChanged));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static bool GetIsOpenFileButtonBehaviorEnabled(DependencyObject d)        {            return (bool)d.GetValue(IsOpenFileButtonBehaviorEnabledProperty);        }        public static void SetIsOpenFileButtonBehaviorEnabled(DependencyObject obj, bool value)        {            obj.SetValue(IsOpenFileButtonBehaviorEnabledProperty, value);        }        private static void IsOpenFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            var button = d as FButton;            if (e.OldValue != e.NewValue && button != null)            {                button.CommandBindings.Add(OpenFileCommandBinding);            }        }        #endregion        #region IsOpenFolderButtonBehaviorEnabledProperty 选择文件夹命令行为开关        ///         /// 选择文件夹命令行为开关        ///         public static readonly DependencyProperty IsOpenFolderButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFolderButtonBehaviorEnabled"            , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFolderButtonBehaviorEnabledChanged));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static bool GetIsOpenFolderButtonBehaviorEnabled(DependencyObject d)        {            return (bool)d.GetValue(IsOpenFolderButtonBehaviorEnabledProperty);        }        public static void SetIsOpenFolderButtonBehaviorEnabled(DependencyObject obj, bool value)        {            obj.SetValue(IsOpenFolderButtonBehaviorEnabledProperty, value);        }        private static void IsOpenFolderButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            var button = d as FButton;            if (e.OldValue != e.NewValue && button != null)            {                button.CommandBindings.Add(OpenFolderCommandBinding);            }        }        #endregion        #region IsSaveFileButtonBehaviorEnabledProperty 选择文件保存路径及名称        ///         /// 选择文件保存路径及名称        ///         public static readonly DependencyProperty IsSaveFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsSaveFileButtonBehaviorEnabled"            , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsSaveFileButtonBehaviorEnabledChanged));        [AttachedPropertyBrowsableForType(typeof(TextBox))]        public static bool GetIsSaveFileButtonBehaviorEnabled(DependencyObject d)        {            return (bool)d.GetValue(IsSaveFileButtonBehaviorEnabledProperty);        }        public static void SetIsSaveFileButtonBehaviorEnabled(DependencyObject obj, bool value)        {            obj.SetValue(IsSaveFileButtonBehaviorEnabledProperty, value);        }        private static void IsSaveFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            var button = d as FButton;            if (e.OldValue != e.NewValue && button != null)            {                button.CommandBindings.Add(SaveFileCommandBinding);            }        }        #endregion        #region OpenFileCommand 选择文件命令        ///         /// 选择文件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令        ///         public static RoutedUICommand OpenFileCommand { get; private set; }        ///         /// OpenFileCommand绑定事件        ///         private static readonly CommandBinding OpenFileCommandBinding;        ///         /// 执行OpenFileCommand        ///         private static void OpenFileButtonClick(object sender, ExecutedRoutedEventArgs e)        {            var tbox = e.Parameter as FrameworkElement;            var txt = tbox as TextBox;            string filter = txt.Tag == null ? "所有文件(*.*)|*.*" : txt.Tag.ToString();            if (filter.Contains(".bin"))            {                filter += "|所有文件(*.*)|*.*";            }            if (txt == null) return;            OpenFileDialog fd = new OpenFileDialog();            fd.Title = "请选择文件";            //“图像文件(*.bmp, *.jpg)|*.bmp;*.jpg|所有文件(*.*)|*.*”            fd.Filter = filter;            fd.FileName = txt.Text.Trim();            if (fd.ShowDialog() == true)            {                txt.Text = fd.FileName;            }            tbox.Focus();        }        #endregion        #region OpenFolderCommand 选择文件夹命令        ///         /// 选择文件夹命令        ///         public static RoutedUICommand OpenFolderCommand { get; private set; }        ///         /// OpenFolderCommand绑定事件        ///         private static readonly CommandBinding OpenFolderCommandBinding;        ///         /// 执行OpenFolderCommand        ///         private static void OpenFolderButtonClick(object sender, ExecutedRoutedEventArgs e)        {            var tbox = e.Parameter as FrameworkElement;            var txt = tbox as TextBox;            if (txt == null) return;            FolderBrowserDialog fd = new FolderBrowserDialog();            fd.Description = "请选择文件路径";            fd.SelectedPath = txt.Text.Trim();            if (fd.ShowDialog() == DialogResult.OK)            {                txt.Text = fd.SelectedPath;            }            tbox.Focus();        }        #endregion        #region SaveFileCommand 选择文件保存路径及名称        ///         /// 选择文件保存路径及名称        ///         public static RoutedUICommand SaveFileCommand { get; private set; }        ///         /// SaveFileCommand绑定事件        ///         private static readonly CommandBinding SaveFileCommandBinding;        ///         /// 执行OpenFileCommand        ///         private static void SaveFileButtonClick(object sender, ExecutedRoutedEventArgs e)        {            var tbox = e.Parameter as FrameworkElement;            var txt = tbox as TextBox;            if (txt == null) return;            SaveFileDialog fd = new SaveFileDialog();            fd.Title = "文件保存路径";            fd.Filter = "所有文件(*.*)|*.*";            fd.FileName = txt.Text.Trim();            if (fd.ShowDialog() == DialogResult.OK)            {                txt.Text = fd.FileName;            }            tbox.Focus();        }        #endregion        ///         /// 静态构造函数        ///         static ControlAttachProperty()        {            //ClearTextCommand            ClearTextCommand = new RoutedUICommand();            ClearTextCommandBinding = new CommandBinding(ClearTextCommand);            ClearTextCommandBinding.Executed += ClearButtonClick;            //OpenFileCommand            OpenFileCommand = new RoutedUICommand();            OpenFileCommandBinding = new CommandBinding(OpenFileCommand);            OpenFileCommandBinding.Executed += OpenFileButtonClick;            //OpenFolderCommand            OpenFolderCommand = new RoutedUICommand();            OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);            OpenFolderCommandBinding.Executed += OpenFolderButtonClick;            SaveFileCommand = new RoutedUICommand();            SaveFileCommandBinding = new CommandBinding(SaveFileCommand);            SaveFileCommandBinding.Executed += SaveFileButtonClick;        }

 三.富文本框RichTextBox控件样式

  RichTextBox的样式比较简单:  

使用实力及效果:  

四.密码输入框PasswordBox控件样式及扩展功能

  密码输入控件的样式和第二节文本框TextBox基本一致,就不做详细的说明了,直接上样式的代码,相关逻辑(C#) 代码和上面是一样的(复用)。

使用示例及效果:  

 

原文地址:

转载地址:http://ipalo.baihongyu.com/

你可能感兴趣的文章
jQuery系列 第四章 jQuery框架的选择器
查看>>
apt
查看>>
Android Dagger2依赖注入
查看>>
FullPage.js全屏插件文档及使用方法
查看>>
修改chrome插件
查看>>
Spring Boot(06)——参数配置机制
查看>>
【WPF】右下角弹出自定义通知样式(Notification)——简单教程
查看>>
keras 使用笔记
查看>>
Android中主要类的继承关系梳理汇总
查看>>
webApp爬坑之路(1)
查看>>
分享代码片段:web集群全局唯一request id生成算法, 替代uuid等“通用”方案
查看>>
[Arm] ARM汇编语言调用C函数之参数传递(转)
查看>>
SpringMVC源码分析迷你书
查看>>
PaddlePaddle 1.3.2 发布,百度开源的深度学习框架
查看>>
Python发送邮件模块之——yagmail模块
查看>>
Android 分享微信小程序失败二三事
查看>>
SpringBoot通过jar包启动时MyBatis无法定位实体类
查看>>
linux系统常用命令
查看>>
面对霍金的担忧,人工智能会让我们在火星实现定居吗
查看>>
定制一款漂亮的终端
查看>>