本博文针对人群: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. Entity Framework Code First关系映射约定【l转发】

    本篇随笔目录: 1.外键列名默认约定 2.一对多关系 3.一对一关系 4.多对多关系 5.一对多自反关系 6.多对多自反关系 在关系数据库中,不同表之间往往不是全部都单独存在,而是相互存在关联的.两个 ...

  2. HttpClient设置超时(转)

    HttpClient  4.5版本设置连接超时时间-CloseableHttpClient设置Timeout(区别于4.3.2) HttpClient升级到4.5版本后,API有很多变化,HttpCl ...

  3. 串口通讯编程一日通3(COMMTIMEOUTS DCB整理)

    上一篇看了Overlapped IO模型后,接下来看剩下两个重要结构:  2.COMMTIMEOUTS结构 超时设置 COMMTIMEOUTS:COMMTIMEOUTS主要用于串口超时参数设置.COM ...

  4. 基于canvas的原生JS时钟效果

    概述 运用html5新增画布canvas技术,绘制时钟效果,无需引用任何插件,纯js. 详细 代码下载:http://www.demodashi.com/demo/11935.html 给大家介绍一个 ...

  5. 摘:static,const,inline,define的意义

    static 1) 产生背景 引出原因:函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想 ...

  6. Node Redis 小试

    Redis 是一个高性能的 key-value 数据库,为了保证效率,数据都是缓存在内存中,在执行频繁而又复杂的数据库查询条件时,可以使用 Redis 缓存一份查询结果,以提升应用性能. 背景 如果一 ...

  7. java中加密解密工具类

    在工作中经常遇到需要加密.解密的场景.例如用户的手机号等信息,在保存到数据库的过程中,需要对数据进行加密.取出时进行解密. public class DEStool { private String ...

  8. unity, inspector listview

    inspector中实现列表框: public override void OnInspectorGUI(){ bool isDoubleClick=false;        Event e = E ...

  9. SAP ERP 6.0 EHP7 SR2(WINDOWS MSSQL版)安装说明

    原文 by 枫竹丹青 ⋅ 1.安装准备 1.1.版本说明 本文是描述在一个Windows虚拟机.SQL Server数据库环境下,安装SAP ERP 6.0 EHP7 SR2服务器,安装完成虚拟机文件 ...

  10. form之action的绝对路径与相对路径

    1.当你的form要提交到你自己的站点之外的URL的时候,就采取绝对路径: <form action="http://www.xxx.yyy:zzzz/mmm/nn/kkk.jsp&q ...