本博文针对人群:WPF新手。
博文内容:通过Style制定包含清空Button的TextBox样式模板,通过在Style中引入自定义类的附加属性完成对TextBox的内容清空。
  1. <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">博文目的:帮助刚入门的WPF开发人员或有需要的人快速了解该样式的实现。由于本人水平有限,难免有不足的地方,欢迎请指正,共同进步!</span>

正题:

带清空按钮TextBox的实现(WPF)分为两部分:样式模板(Style)部分和附加属性类(TextBoxHelper)部分。

一、样式模板(Style)

我们先定义Style,目标类型:TextBox

下面针对TextBox的Template部分详细说明:

关键代码如下(只保留核心属性设置)

  1. <ControlTemplate TargetType="{x:Type TextBox}">
  2. <Border >
  3. <DockPanel LastChildFill="True">
  4. <Button x:Name="Part_ClearButton" DockPanel.Dock="Right"  Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" />
  5. <ScrollViewer x:Name="PART_ContentHost" DockPanel.Dock="Left" />
  6. </DockPanel>
  7. </Border>
  8. <ControlTemplate.Triggers>
  9. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
  10. <Setter TargetName="Part_ClearButton" Property="Visibility" Value="Collapsed" />
  11. </DataTrigger>
  12. ................................省略
  13. </ControlTemplate.Triggers>
  14. </ControlTemplate>

为了方便直观理解,下图为样式模板(ControlTemplate)的示意图。

关于ControlTemplate相信大家都有个大概了解了,下面针对其中容易出错的地方补充几点说明:

1.关于最外层的Border对于它的 BorderBrush、BorderThickness、 SnapsToDevicePixels、 Background最好都不要自己设定尽量都使用TemplateBinding绑定到应用模板的TextBox上。原因嘛,当然是为了留给用户使用时尽量多的对于TextBox外观自主权,总不能说用了这个Style后边框、背景都不能设定吧。

2.对于DockPanel,其属性LastChildFill="True",本身默认值即为“True”,可以省略不写,但是一定要知道。

3.关于DockPanel中ScrollViewer和Button的布局,一定要先定义Button,后定义ScrollViewer。原因:就是因为第2条的LastChildFill="True"属性,如果先定义ScrollViewer,后定义Button会出现什么效果,大家可以自己试试看。

4.对于ScrollViewer 它的名字一定要是"PART_ContentHost" 否则将Windows将无法识别导致不能显示文字。

5.对于Button为了是Button显示正方形所以Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" 将自己的宽绑定到了实际显示高度上。最好将Focusable设为False。原因:防止输入时点击清空按钮导致ScrollViewer失去焦点,具体表现为点击清空按钮,输入框的光标不闪烁了。FontSize尽量TemplateBinding到应用模板的目标控件上。

将Style重构提取,最后放入资源词典以供重用。

提炼后的Style

  1. <!--获得焦点后边框颜色-->
  2. <SolidColorBrush x:Key="FocusedBorderBrush" Color="Black"/>
  3. <!--鼠标移上时背景色-->
  4. <SolidColorBrush x:Key="MouseOverBackground" Color="LightGray"/>
  5. <!--清空按钮模板样式-->
  6. <ControlTemplate x:Key="ClearButtonTemplate" TargetType="Button">
  7. <Grid>
  8. <Rectangle x:Name="rctButton" Fill="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Rectangle>
  9. <ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
  10. HorizontalAlignment="Center"
  11. VerticalAlignment="Center">
  12. </ContentPresenter>
  13. </Grid>
  14. <ControlTemplate.Triggers>
  15. <Trigger Property="IsMouseOver" Value="True">
  16. <Setter TargetName="rctButton" Property="Fill" Value="{DynamicResource MouseOverBackground}"/>
  17. </Trigger>
  18. </ControlTemplate.Triggers>
  19. </ControlTemplate>
  20. <!--带有清空按钮的TextBox风格-->
  21. <Style x:Key="ClearButtonTextBoxStyle" TargetType="{x:Type TextBox}">
  22. <Setter Property="Template">
  23. <Setter.Value>
  24. <ControlTemplate TargetType="{x:Type TextBox}">
  25. <Border x:Name="bdRoot"
  26. BorderBrush="{TemplateBinding BorderBrush}"
  27. BorderThickness="{TemplateBinding BorderThickness}"
  28. SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
  29. Background="{TemplateBinding Background}">
  30. <DockPanel LastChildFill="True">
  31. <Button x:Name="Part_ClearButton"
  32. UC:TextBoxHelper.IsClearButton="True"
  33. Content="X"
  34. DockPanel.Dock="Right"
  35. Focusable="False"
  36. Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
  37. Template="{DynamicResource ClearButtonTemplate}"
  38. FontSize="{TemplateBinding FontSize}">
  39. </Button>
  40. <ScrollViewer x:Name="PART_ContentHost" DockPanel.Dock="Left" Background="{TemplateBinding Background}"/>
  41. </DockPanel>
  42. </Border>
  43. <ControlTemplate.Triggers>
  44. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
  45. <Setter TargetName="Part_ClearButton" Property="Visibility" Value="Collapsed" />
  46. </DataTrigger>
  47. <Trigger Property="IsFocused" Value="True">
  48. <Setter TargetName="bdRoot" Property="BorderBrush" Value="{DynamicResource FocusedBorderBrush}"/>
  49. </Trigger>
  50. <Trigger Property="IsMouseOver" Value="True">
  51. <Setter TargetName="bdRoot" Property="BorderBrush" Value="{DynamicResource FocusedBorderBrush}"/>
  52. </Trigger>
  53. </ControlTemplate.Triggers>
  54. </ControlTemplate>
  55. </Setter.Value>
  56. </Setter>
  57. </Style>

二、附加属性类

为什么不采用Trigger置空Text实现而要采用附加属性类?
以下为原因,不关心的可以跳过...

由于在Style中通过Trigger来设置TextBox的Text属性为“”暂时存在缺陷:
当TextBox定义时如果设置Text属性将导致Trigger将Text置空失效,详细描述如下
使用Trigger置空Text原理,我们在模板触发器中添加数据触发器
  1. <DataTrigger Binding="{Binding IsPressed,ElementName=Part_ClearButton}" Value="True">
  2. <Setter Property="Text" Value=""/>
  3. </DataTrigger>

当清空按钮按下时,触发

  1. <Setter Property="Text" Value=""/>
但是如果定义TextBox时
  1. <TextBox Text="{Binding xxx}"
  2. Visibility="Collapsed"
  3. Height="24"
  4. Width="250"
  5. Style="{DynamicResource ClearButtonTextBoxStyle}"
  6. >
  7. </TextBox>

  1. <TextBox Text="xxx"
  2. Visibility="Collapsed"
  3. Height="24"
  4. Width="250"
  5. Style="{DynamicResource ClearButtonTextBoxStyle}"
  6. >
  7. </TextBox>

此时,风格中 的触发器将失效,无法清空文本内容,经尝试,Trigger、DataTrigger均会失效,而且"Text"属性不支持StoryBorad也无法通过故事板清空。

使用附加属性清空文本内容

原理,通过在Style的ControlTemplate中 的清空按钮Part_ClearButton
加上自定义的附加属性,在附加属性改变的回调函数中获得依赖对象,该对象即为我们定义的Part_ClearButton
,获得按钮后为它的Click挂上我们的自定义事件,这样当点击清空按钮时,即可执行我们的自定义事件,只需要在事件里通过VisualTreeHelper.GetParent向上获取到应用模板的TextBox,然后通过TextBox.Clear()清空内容即可.

下面为代码,比较简单
  1. public class TextBoxHelper
  2. {
  3. #region 附加属性 IsClearButton
  4. /// <summary>
  5. /// 附加属性,是否带清空按钮
  6. /// </summary>
  7. public static readonly DependencyProperty IsClearButtonProperty =
  8. DependencyProperty.RegisterAttached("IsClearButton", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false, ClearText));
  9. public static bool GetIsClearButton(DependencyObject obj)
  10. {
  11. return (bool)obj.GetValue(IsClearButtonProperty);
  12. }
  13. public static void SetIsClearButton(DependencyObject obj, bool value)
  14. {
  15. obj.SetValue(IsClearButtonProperty, value);
  16. }
  17. #endregion
  18. #region 回调函数和清空输入框内容的实现
  19. /// <summary>
  20. /// 回调函数若附加属性IsClearButton值为True则挂载清空TextBox内容的函数
  21. /// </summary>
  22. /// <param name="d">属性所属依赖对象</param>
  23. /// <param name="e">属性改变事件参数</param>
  24. private static void ClearText(DependencyObject d, DependencyPropertyChangedEventArgs e)
  25. {
  26. Button btn = d as Button;
  27. if (d != null && e.OldValue != e.NewValue)
  28. {
  29. btn.Click -= ClearTextClicked;
  30. if ((bool)e.NewValue)
  31. {
  32. btn.Click += ClearTextClicked;
  33. }
  34. }
  35. }
  36. /// <summary>
  37. /// 清空应用该附加属性的父TextBox内容函数
  38. /// </summary>
  39. /// <param name="sender">发送对象</param>
  40. /// <param name="e">路由事件参数</param>
  41. public static void ClearTextClicked(object sender, RoutedEventArgs e)
  42. {
  43. Button btn = sender as Button;
  44. if (btn != null)
  45. {
  46. var parent = VisualTreeHelper.GetParent(btn);
  47. while (!(parent is TextBox))
  48. {
  49. parent = VisualTreeHelper.GetParent(parent);
  50. }
  51. TextBox txt = parent as TextBox;
  52. if (txt != null)
  53. {
  54. txt.Clear();
  55. }
  56. }
  57. }
  58. #endregion
  59. }

最后我们在Style所在地引入TextBoxHelper命名空间,在Style的ControlTemplate里的按钮加上改附加属性即可

  1. <Button x:Name="Part_ClearButton"
  2. UC:TextBoxHelper.IsClearButton="True"
  3. Content="X"
  4. DockPanel.Dock="Right"
  5. Focusable="False"
  6. Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
  7. Template="{DynamicResource ClearButtonTemplate}"
  8. FontSize="{TemplateBinding FontSize}">
  9. </Button>

总结

经过以上博文,相信大家都理解带清空按钮TextBox的实现,当然这只是一个开始!最后把源代码上传,分享给大家,有什么不足的地方欢迎指正,谢谢!

我们的目标,帮助自己,帮助别人。

带清空按钮TextBox的实现(WPF)的更多相关文章

  1. android自定义文本框,后面带清空按钮

    android常见的带清空按钮的文本框,获得焦点时如果有内容则显示,否则不显示 package com.qc.health.weight; import com.qc.health.R; import ...

  2. 带清空按钮的EditText

    public class ClearEditText extends EditText implements OnFocusChangeListener, TextWatcher { // 删除按钮的 ...

  3. WPF 带清除按钮的文字框SearchTextBox

    原文:WPF 带清除按钮的文字框SearchTextBox 基于TextBox的带清除按钮的搜索框 样式部分: <!--带清除按钮文字框--> <Style TargetType=& ...

  4. WPF 实现带标题的TextBox

    这篇博客将分享在WPF中如何创建一个带Title的TextBox.首先请看一下最终的效果, 实现思路:使用TextBlock+TextBox来实现,TextBlock用来显示Title. 实现代码, ...

  5. easyui datebox 扩展清空按钮及日期判断

    <input id="EndHavDate" class="easyui-datebox" data-options="prompt:'请选择结 ...

  6. [iOS-UI]点击清空按钮,却会有提交的感觉

    一,问题分析 1.感觉像是点击清空按钮时调用了添加按钮的事件. 2.插入断电后,还真是这样. 3.仔细想想,才发现,原来是我复制了添加按钮,变成为添加按钮,进而点击清空时,不仅清空了所有内容,还把最新 ...

  7. jquery图片滚动仿QQ商城带左右按钮控制焦点图片切换滚动

    jquery图片滚动仿QQ商城带左右按钮控制焦点图片切换滚动 http://www.17sucai.com/pins/demoshow/382

  8. EasyUI 1.3.6 DateBox添加清空按钮

    EasyUI 1.3.6 DateBox添加清空按钮 效果如图: EasyUI datebox是没有清空按钮的,可通过如下方法加入: 打开jquery.easyui.min.js看到这样如此乱的代码, ...

  9. 为jEasyUi的日期控件添加一个“清空”按钮----通过修改1.4的easyui.min.js

    为 jQuery EasyUI 1.4 的datebox或datetimebox添加一个清空按钮 使用场景:为用户指定了日期的格式,且日期可以为空 修改语言包easyui-lang-zh_CN.js ...

随机推荐

  1. javax.naming.NoInitialContextException: Need to specify class name in environment or system property

    javax.naming.NoInitialContextException: Need to specify class name in environment or system property ...

  2. 安装 Percona XtraBackup 2.3

    Installing Percona XtraBackup from Percona yum repository Install the Percona repository You can ins ...

  3. Android设计模式系列(3)--SDK源码之单例模式

    单例模式,可以说是GOF的23种设计模式中最简单的一个.这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本 ...

  4. C#: 数字经纬度和度分秒经纬度间的转换

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  5. centos7下mysqldump+crontab自动备份数据库

    1.创建文件夹(存放备份数据) mkdir /bak mkdir /bak/mysqldata 2.编写脚本 vi /usr/sbin/bakmysql.sh 脚本内容如下 DATE=`date +% ...

  6. [Jobdu] 题目1373:整数中1出现的次数(从1到n整数中1出现的次数)

    题目描述: 亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他.问题是:求出1~13的整数中1出现的次数,并算出100~130 ...

  7. QT实现右键快捷菜单

    [转自]:http://blog.csdn.net/rolland1989/article/details/5754575 QWidget及其子类都可有右键菜单,因为QWidget有以下两个与右键菜单 ...

  8. Quartus调用Modelsim SE避免重复编译Altera器件库的方法

    最近用Quartus 15.0配合Modelsim SE 10.4的64位版本,简直就是闪电一般的仿真速度.但是众所周知,SE版本最大的问题就是每次由Quartus自动调用时,都要重新编译所使用的器件 ...

  9. 如何使用微信JS-SDK实际分享功能

    http://jingyan.baidu.com/album/d3b74d64c517051f77e609ed.html?picindex=7

  10. [转]JavaScript放在<head>和<body>的区别

    原文:http://liminhappygirl.iteye.com/blog/1841360 javaScript放在<head>和<body>的区别: 在HTML body ...