一.前言.预览

  申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。

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

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

效果图:

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

2.1 TextBox基本样式

样式代码如下:

  1. <!--TextBox默认样式-->
  2. <Style TargetType="{x:Type TextBox}" x:Key="DefaultTextBox">
  3. <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
  4. <Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" />
  5. <Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
  6. <Setter Property="FontSize" Value="{StaticResource FontSize}" />
  7. <Setter Property="BorderThickness" Value="1" />
  8. <Setter Property="MinHeight" Value="26" />
  9. <Setter Property="Width" Value="100" />
  10. <Setter Property="Background" Value="{StaticResource TextBackground}" />
  11. <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
  12. <Setter Property="Padding" Value="0" />
  13. <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
  14. <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" />
  15. <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" />
  16. <Setter Property="VerticalContentAlignment" Value="Center" />
  17. <!-- change SnapsToDevicePixels to True to view a better border and validation error -->
  18. <Setter Property="SnapsToDevicePixels" Value="True" />
  19. <!--英 ['kærət] 美 ['kærət] 插入符号-->
  20. <Setter Property="CaretBrush" Value="{StaticResource TextForeground}" />
  21. <Setter Property="Template">
  22. <Setter.Value>
  23. <ControlTemplate TargetType="{x:Type TextBox}">
  24. <Grid x:Name="PART_Root">
  25. <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
  26. CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}"
  27. BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" />
  28. <Grid x:Name="PART_InnerGrid">
  29. <Grid.ColumnDefinitions>
  30. <ColumnDefinition Width="Auto" />
  31. <ColumnDefinition Width="*" />
  32. <ColumnDefinition Width="Auto" />
  33. </Grid.ColumnDefinitions>
  34. <!--Label区域-->
  35. <ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}"
  36. Content="{TemplateBinding local:ControlAttachProperty.Label}"/>
  37. <!--内容区域-->
  38. <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2"
  39. VerticalAlignment="Stretch" Background="{x:Null}" />
  40. <!--水印-->
  41. <TextBlock x:Name="Message" Padding="{TemplateBinding Padding}" Visibility="Collapsed"
  42. Text="{TemplateBinding local:ControlAttachProperty.Watermark}" Grid.Column="1"
  43. Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="{StaticResource WatermarkOpacity}"
  44. HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  45. VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="5,2,5,2" />
  46. <!--附加内容区域-->
  47. <Border x:Name="PART_AttachContent" Grid.Column="2" Margin="2" VerticalAlignment="Center" HorizontalAlignment="Center" >
  48. <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" />
  49. </Border>
  50. </Grid>
  51. </Grid>
  52. <ControlTemplate.Triggers>
  53. <!--显示水印-->
  54. <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
  55. <Setter TargetName="Message" Property="Visibility" Value="Visible" />
  56. </DataTrigger>
  57.  
  58. <Trigger Property="IsMouseOver" Value="True">
  59. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/>
  60. </Trigger>
  61. <Trigger Property="IsFocused" Value="True">
  62. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/>
  63. </Trigger>
  64. <!--不可用-->
  65. <Trigger Property="IsEnabled" Value="False">
  66. <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}" />
  67. </Trigger>
  68. <!--只读时,禁用PART_AttachContent-->
  69. <Trigger Property="IsReadOnly" Value="True">
  70. <Setter TargetName="PART_AttachContent" Property="IsEnabled" Value="False" />
  71. <Setter TargetName="Bg" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" />
  72. <Setter TargetName="PART_ContentHost" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" />
  73. <Setter TargetName="Label" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" />
  74. </Trigger>
  75. </ControlTemplate.Triggers>
  76. </ControlTemplate>
  77. </Setter.Value>
  78. </Setter>
  79. </Style>

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

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

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

  1. #region FocusBorderBrush 焦点边框色,输入控件
  2.  
  3. public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached(
  4. "FocusBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));
  5. public static void SetFocusBorderBrush(DependencyObject element, Brush value)
  6. {
  7. element.SetValue(FocusBorderBrushProperty, value);
  8. }
  9. public static Brush GetFocusBorderBrush(DependencyObject element)
  10. {
  11. return (Brush)element.GetValue(FocusBorderBrushProperty);
  12. }
  13.  
  14. #endregion
  15.  
  16. #region MouseOverBorderBrush 鼠标进入边框色,输入控件
  17.  
  18. public static readonly DependencyProperty MouseOverBorderBrushProperty =
  19. DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty),
  20. new FrameworkPropertyMetadata(Brushes.Transparent,
  21. FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));
  22.  
  23. /// <summary>
  24. /// Sets the brush used to draw the mouse over brush.
  25. /// </summary>
  26. public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value)
  27. {
  28. obj.SetValue(MouseOverBorderBrushProperty, value);
  29. }
  30.  
  31. /// <summary>
  32. /// Gets the brush used to draw the mouse over brush.
  33. /// </summary>
  34. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  35. [AttachedPropertyBrowsableForType(typeof(CheckBox))]
  36. [AttachedPropertyBrowsableForType(typeof(RadioButton))]
  37. [AttachedPropertyBrowsableForType(typeof(DatePicker))]
  38. [AttachedPropertyBrowsableForType(typeof(ComboBox))]
  39. [AttachedPropertyBrowsableForType(typeof(RichTextBox))]
  40. public static Brush GetMouseOverBorderBrush(DependencyObject obj)
  41. {
  42. return (Brush)obj.GetValue(MouseOverBorderBrushProperty);
  43. }
  44.  
  45. #endregion
  46.  
  47. #region AttachContentProperty 附加组件模板
  48. /// <summary>
  49. /// 附加组件模板
  50. /// </summary>
  51. public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached(
  52. "AttachContent", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));
  53.  
  54. public static ControlTemplate GetAttachContent(DependencyObject d)
  55. {
  56. return (ControlTemplate)d.GetValue(AttachContentProperty);
  57. }
  58.  
  59. public static void SetAttachContent(DependencyObject obj, ControlTemplate value)
  60. {
  61. obj.SetValue(AttachContentProperty, value);
  62. }
  63. #endregion
  64.  
  65. #region WatermarkProperty 水印
  66. /// <summary>
  67. /// 水印
  68. /// </summary>
  69. public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
  70. "Watermark", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));
  71.  
  72. public static string GetWatermark(DependencyObject d)
  73. {
  74. return (string)d.GetValue(WatermarkProperty);
  75. }
  76.  
  77. public static void SetWatermark(DependencyObject obj, string value)
  78. {
  79. obj.SetValue(WatermarkProperty, value);
  80. }
  81. #endregion
  82.  
  83. #region CornerRadiusProperty Border圆角
  84. /// <summary>
  85. /// Border圆角
  86. /// </summary>
  87. public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
  88. "CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));
  89.  
  90. public static CornerRadius GetCornerRadius(DependencyObject d)
  91. {
  92. return (CornerRadius)d.GetValue(CornerRadiusProperty);
  93. }
  94.  
  95. public static void SetCornerRadius(DependencyObject obj, CornerRadius value)
  96. {
  97. obj.SetValue(CornerRadiusProperty, value);
  98. }
  99. #endregion
  100.  
  101. #region LabelProperty TextBox的头部Label
  102. /// <summary>
  103. /// TextBox的头部Label
  104. /// </summary>
  105. public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached(
  106. "Label", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));
  107.  
  108. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  109. public static string GetLabel(DependencyObject d)
  110. {
  111. return (string)d.GetValue(LabelProperty);
  112. }
  113.  
  114. public static void SetLabel(DependencyObject obj, string value)
  115. {
  116. obj.SetValue(LabelProperty, value);
  117. }
  118. #endregion
  119.  
  120. #region LabelTemplateProperty TextBox的头部Label模板
  121. /// <summary>
  122. /// TextBox的头部Label模板
  123. /// </summary>
  124. public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached(
  125. "LabelTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));
  126.  
  127. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  128. public static ControlTemplate GetLabelTemplate(DependencyObject d)
  129. {
  130. return (ControlTemplate)d.GetValue(LabelTemplateProperty);
  131. }
  132.  
  133. public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value)
  134. {
  135. obj.SetValue(LabelTemplateProperty, value);
  136. }
  137. #endregion

2.2 水印效果实现

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

  1. <StackPanel>
  2. <TextBox Width="140" Height="40" Margin="3" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible">333333333333333</TextBox>
  3. <TextBox Width="150" Height="30" Margin="3" core:ControlAttachProperty.Watermark="我是水印" core:ControlAttachProperty.CornerRadius="2"></TextBox>
  4. <TextBox Width="150" Height="30" Margin="3" IsReadOnly="True" core:ControlAttachProperty.CornerRadius="15" SnapsToDevicePixels="True" >我是只读的</TextBox>
  5. <TextBox Width="150" Height="30" Margin="3" IsEnabled="False">IsEnabled="False"</TextBox>
  6. <TextBox Width="150" Height="30" core:ControlAttachProperty.Watermark="我是水印"></TextBox>
  7. </StackPanel>

  效果:

  

2.3 Label标签实现

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

  1. <!--TextBox包含附加属性Label的样式-->
  2. <Style TargetType="{x:Type TextBox}" x:Key="LabelTextBox" BasedOn="{StaticResource DefaultTextBox}">
  3. <Setter Property="local:ControlAttachProperty.LabelTemplate" >
  4. <Setter.Value>
  5. <ControlTemplate TargetType="ContentControl">
  6. <Border Width="60" Background="{StaticResource TextLabelBackground}">
  7. <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock>
  8. </Border>
  9. </ControlTemplate>
  10. </Setter.Value>
  11. </Setter>
  12. </Style>

  使用示例及效果:

  1. <TextBox Width="200" Height="30" Margin="3" core:ControlAttachProperty.Watermark="请输入姓名"
  2. Style="{StaticResource LabelTextBox}" core:ControlAttachProperty.Label="姓名:"></TextBox>

2.4 扩展功能及自定义扩展

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

  1. <!--TextBox包含清除Text按钮的样式-->
  2. <Style TargetType="{x:Type TextBox}" x:Key="ClearButtonTextBox" BasedOn="{StaticResource DefaultTextBox}">
  3. <Setter Property="local:ControlAttachProperty.AttachContent">
  4. <Setter.Value>
  5. <ControlTemplate>
  6. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  7. local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand"
  8. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"
  9. Margin="1,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  10. </ControlTemplate>
  11. </Setter.Value>
  12. </Setter>
  13. </Style>

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

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

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

  1. #region IsClearTextButtonBehaviorEnabledProperty 清除输入框Text值按钮行为开关(设为ture时才会绑定事件)
  2. /// <summary>
  3. /// 清除输入框Text值按钮行为开关
  4. /// </summary>
  5. public static readonly DependencyProperty IsClearTextButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsClearTextButtonBehaviorEnabled"
  6. , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsClearTextButtonBehaviorEnabledChanged));
  7.  
  8. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  9. public static bool GetIsClearTextButtonBehaviorEnabled(DependencyObject d)
  10. {
  11. return (bool)d.GetValue(IsClearTextButtonBehaviorEnabledProperty);
  12. }
  13.  
  14. public static void SetIsClearTextButtonBehaviorEnabled(DependencyObject obj, bool value)
  15. {
  16. obj.SetValue(IsClearTextButtonBehaviorEnabledProperty, value);
  17. }
  18.  
  19. /// <summary>
  20. /// 绑定清除Text操作的按钮事件
  21. /// </summary>
  22. private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  23. {
  24. var button = d as FButton;
  25. if (e.OldValue != e.NewValue && button != null)
  26. {
  27. button.CommandBindings.Add(ClearTextCommandBinding);
  28. }
  29. }
  30.  
  31. #endregion
  32.  
  33. #region ClearTextCommand 清除输入框Text事件命令
  34.  
  35. /// <summary>
  36. /// 清除输入框Text事件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令
  37. /// </summary>
  38. public static RoutedUICommand ClearTextCommand { get; private set; }
  39.  
  40. /// <summary>
  41. /// ClearTextCommand绑定事件
  42. /// </summary>
  43. private static readonly CommandBinding ClearTextCommandBinding;
  44.  
  45. /// <summary>
  46. /// 清除输入框文本值
  47. /// </summary>
  48. private static void ClearButtonClick(object sender, ExecutedRoutedEventArgs e)
  49. {
  50. var tbox = e.Parameter as FrameworkElement;
  51. if (tbox == null) return;
  52. if (tbox is TextBox)
  53. {
  54. ((TextBox)tbox).Clear();
  55. }
  56. if (tbox is PasswordBox)
  57. {
  58. ((PasswordBox)tbox).Clear();
  59. }
  60. if (tbox is ComboBox)
  61. {
  62. var cb = tbox as ComboBox;
  63. cb.SelectedItem = null;
  64. cb.Text = string.Empty;
  65. }
  66. if (tbox is MultiComboBox)
  67. {
  68. var cb = tbox as MultiComboBox;
  69. cb.SelectedItem = null;
  70. cb.UnselectAll();
  71. cb.Text = string.Empty;
  72. }
  73. if (tbox is DatePicker)
  74. {
  75. var dp = tbox as DatePicker;
  76. dp.SelectedDate = null;
  77. dp.Text = string.Empty;
  78. }
  79. tbox.Focus();
  80. }
  81.  
  82. #endregion
  83.  
  84. /// <summary>
  85. /// 静态构造函数
  86. /// </summary>
  87. static ControlAttachProperty()
  88. {
  89. //ClearTextCommand
  90. ClearTextCommand = new RoutedUICommand();
  91. ClearTextCommandBinding = new CommandBinding(ClearTextCommand);
  92. ClearTextCommandBinding.Executed += ClearButtonClick;
  93. //OpenFileCommand
  94. OpenFileCommand = new RoutedUICommand();
  95. OpenFileCommandBinding = new CommandBinding(OpenFileCommand);
  96. OpenFileCommandBinding.Executed += OpenFileButtonClick;
  97. //OpenFolderCommand
  98. OpenFolderCommand = new RoutedUICommand();
  99. OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);
  100. OpenFolderCommandBinding.Executed += OpenFolderButtonClick;
  101.  
  102. SaveFileCommand = new RoutedUICommand();
  103. SaveFileCommandBinding = new CommandBinding(SaveFileCommand);
  104. SaveFileCommandBinding.Executed += SaveFileButtonClick;
  105. }

  效果:

  

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

  1. <TextBox Width="200" Height="30" Margin="3" core:ControlAttachProperty.Watermark="查询关键词" IsEnabled="True">
  2. <core:ControlAttachProperty.AttachContent>
  3. <ControlTemplate>
  4. <StackPanel Orientation="Horizontal">
  5. <core:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  6. FIconSize="18" Margin="1,1,2,3" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  7. <core:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  8. FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  9. </StackPanel>
  10. </ControlTemplate>
  11. </core:ControlAttachProperty.AttachContent>
  12. </TextBox>

  效果:

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

  1. <!--TextBox包含附加属性Label,以及ClearText按钮的样式-->
  2. <Style TargetType="{x:Type TextBox}" x:Key="LabelClearButtonTextBox" BasedOn="{StaticResource DefaultTextBox}">
  3. <Setter Property="local:ControlAttachProperty.LabelTemplate" >
  4. <Setter.Value>
  5. <ControlTemplate TargetType="ContentControl">
  6. <Border Width="60" Background="{StaticResource TextLabelBackground}">
  7. <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock>
  8. </Border>
  9. </ControlTemplate>
  10. </Setter.Value>
  11. </Setter>
  12. <Setter Property="local:ControlAttachProperty.AttachContent">
  13. <Setter.Value>
  14. <ControlTemplate>
  15. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  16. local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand"
  17. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"
  18. Margin="0,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  19. </ControlTemplate>
  20. </Setter.Value>
  21. </Setter>
  22. </Style>

2.6 文件选择输入相关扩展

  先看看效果,就明白了。

  

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

  1. <!--LabelOpenFileTextBox-->
  2. <Style TargetType="{x:Type TextBox}" x:Key="LabelOpenFileTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}">
  3. <Setter Property="local:ControlAttachProperty.Label" Value="文件路径"/>
  4. <Setter Property="local:ControlAttachProperty.Watermark" Value="选择文件路径"/>
  5. <Setter Property="local:ControlAttachProperty.AttachContent">
  6. <Setter.Value>
  7. <ControlTemplate>
  8. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  9. local:ControlAttachProperty.IsOpenFileButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.OpenFileCommand"
  10. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"
  11. Margin="0,1,0,1" FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  12. </ControlTemplate>
  13. </Setter.Value>
  14. </Setter>
  15. </Style>
  16.  
  17. <!--LabelOpenFolderTextBox-->
  18. <Style TargetType="{x:Type TextBox}" x:Key="LabelOpenFolderTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}">
  19. <Setter Property="local:ControlAttachProperty.Label" Value="设置路径"/>
  20. <Setter Property="local:ControlAttachProperty.Watermark" Value="选择文件夹路径"/>
  21. <Setter Property="local:ControlAttachProperty.AttachContent">
  22. <Setter.Value>
  23. <ControlTemplate>
  24. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  25. local:ControlAttachProperty.IsOpenFolderButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.OpenFolderCommand"
  26. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"
  27. Margin="0,1,0,1" FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  28. </ControlTemplate>
  29. </Setter.Value>
  30. </Setter>
  31. </Style>
  32.  
  33. <!--LabelSaveFileTextBox-->
  34. <Style TargetType="{x:Type TextBox}" x:Key="LabelSaveFileTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}">
  35. <Setter Property="local:ControlAttachProperty.Label" Value="保存路径"/>
  36. <Setter Property="local:ControlAttachProperty.Watermark" Value="选择文件保存路径"/>
  37. <Setter Property="local:ControlAttachProperty.AttachContent">
  38. <Setter.Value>
  39. <ControlTemplate>
  40. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  41. local:ControlAttachProperty.IsSaveFileButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.SaveFileCommand"
  42. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"
  43. Margin="0,1,0,1" FIconSize="20" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  44. </ControlTemplate>
  45. </Setter.Value>
  46. </Setter>
  47. </Style>

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

  1. #region IsOpenFileButtonBehaviorEnabledProperty 选择文件命令行为开关
  2. /// <summary>
  3. /// 选择文件命令行为开关
  4. /// </summary>
  5. public static readonly DependencyProperty IsOpenFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFileButtonBehaviorEnabled"
  6. , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFileButtonBehaviorEnabledChanged));
  7.  
  8. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  9. public static bool GetIsOpenFileButtonBehaviorEnabled(DependencyObject d)
  10. {
  11. return (bool)d.GetValue(IsOpenFileButtonBehaviorEnabledProperty);
  12. }
  13.  
  14. public static void SetIsOpenFileButtonBehaviorEnabled(DependencyObject obj, bool value)
  15. {
  16. obj.SetValue(IsOpenFileButtonBehaviorEnabledProperty, value);
  17. }
  18.  
  19. private static void IsOpenFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  20. {
  21. var button = d as FButton;
  22. if (e.OldValue != e.NewValue && button != null)
  23. {
  24. button.CommandBindings.Add(OpenFileCommandBinding);
  25. }
  26. }
  27.  
  28. #endregion
  29.  
  30. #region IsOpenFolderButtonBehaviorEnabledProperty 选择文件夹命令行为开关
  31. /// <summary>
  32. /// 选择文件夹命令行为开关
  33. /// </summary>
  34. public static readonly DependencyProperty IsOpenFolderButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFolderButtonBehaviorEnabled"
  35. , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFolderButtonBehaviorEnabledChanged));
  36.  
  37. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  38. public static bool GetIsOpenFolderButtonBehaviorEnabled(DependencyObject d)
  39. {
  40. return (bool)d.GetValue(IsOpenFolderButtonBehaviorEnabledProperty);
  41. }
  42.  
  43. public static void SetIsOpenFolderButtonBehaviorEnabled(DependencyObject obj, bool value)
  44. {
  45. obj.SetValue(IsOpenFolderButtonBehaviorEnabledProperty, value);
  46. }
  47.  
  48. private static void IsOpenFolderButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  49. {
  50. var button = d as FButton;
  51. if (e.OldValue != e.NewValue && button != null)
  52. {
  53. button.CommandBindings.Add(OpenFolderCommandBinding);
  54. }
  55. }
  56.  
  57. #endregion
  58.  
  59. #region IsSaveFileButtonBehaviorEnabledProperty 选择文件保存路径及名称
  60. /// <summary>
  61. /// 选择文件保存路径及名称
  62. /// </summary>
  63. public static readonly DependencyProperty IsSaveFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsSaveFileButtonBehaviorEnabled"
  64. , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsSaveFileButtonBehaviorEnabledChanged));
  65.  
  66. [AttachedPropertyBrowsableForType(typeof(TextBox))]
  67. public static bool GetIsSaveFileButtonBehaviorEnabled(DependencyObject d)
  68. {
  69. return (bool)d.GetValue(IsSaveFileButtonBehaviorEnabledProperty);
  70. }
  71.  
  72. public static void SetIsSaveFileButtonBehaviorEnabled(DependencyObject obj, bool value)
  73. {
  74. obj.SetValue(IsSaveFileButtonBehaviorEnabledProperty, value);
  75. }
  76.  
  77. private static void IsSaveFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  78. {
  79. var button = d as FButton;
  80. if (e.OldValue != e.NewValue && button != null)
  81. {
  82. button.CommandBindings.Add(SaveFileCommandBinding);
  83. }
  84. }
  85.  
  86. #endregion
  87.  
  88. #region OpenFileCommand 选择文件命令
  89.  
  90. /// <summary>
  91. /// 选择文件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令
  92. /// </summary>
  93. public static RoutedUICommand OpenFileCommand { get; private set; }
  94.  
  95. /// <summary>
  96. /// OpenFileCommand绑定事件
  97. /// </summary>
  98. private static readonly CommandBinding OpenFileCommandBinding;
  99.  
  100. /// <summary>
  101. /// 执行OpenFileCommand
  102. /// </summary>
  103. private static void OpenFileButtonClick(object sender, ExecutedRoutedEventArgs e)
  104. {
  105. var tbox = e.Parameter as FrameworkElement;
  106. var txt = tbox as TextBox;
  107. string filter = txt.Tag == null ? "所有文件(*.*)|*.*" : txt.Tag.ToString();
  108. if (filter.Contains(".bin"))
  109. {
  110. filter += "|所有文件(*.*)|*.*";
  111. }
  112. if (txt == null) return;
  113. OpenFileDialog fd = new OpenFileDialog();
  114. fd.Title = "请选择文件";
  115. //“图像文件(*.bmp, *.jpg)|*.bmp;*.jpg|所有文件(*.*)|*.*”
  116. fd.Filter = filter;
  117. fd.FileName = txt.Text.Trim();
  118. if (fd.ShowDialog() == true)
  119. {
  120. txt.Text = fd.FileName;
  121. }
  122. tbox.Focus();
  123. }
  124.  
  125. #endregion
  126.  
  127. #region OpenFolderCommand 选择文件夹命令
  128.  
  129. /// <summary>
  130. /// 选择文件夹命令
  131. /// </summary>
  132. public static RoutedUICommand OpenFolderCommand { get; private set; }
  133.  
  134. /// <summary>
  135. /// OpenFolderCommand绑定事件
  136. /// </summary>
  137. private static readonly CommandBinding OpenFolderCommandBinding;
  138.  
  139. /// <summary>
  140. /// 执行OpenFolderCommand
  141. /// </summary>
  142. private static void OpenFolderButtonClick(object sender, ExecutedRoutedEventArgs e)
  143. {
  144. var tbox = e.Parameter as FrameworkElement;
  145. var txt = tbox as TextBox;
  146. if (txt == null) return;
  147. FolderBrowserDialog fd = new FolderBrowserDialog();
  148. fd.Description = "请选择文件路径";
  149. fd.SelectedPath = txt.Text.Trim();
  150. if (fd.ShowDialog() == DialogResult.OK)
  151. {
  152. txt.Text = fd.SelectedPath;
  153. }
  154. tbox.Focus();
  155. }
  156.  
  157. #endregion
  158.  
  159. #region SaveFileCommand 选择文件保存路径及名称
  160.  
  161. /// <summary>
  162. /// 选择文件保存路径及名称
  163. /// </summary>
  164. public static RoutedUICommand SaveFileCommand { get; private set; }
  165.  
  166. /// <summary>
  167. /// SaveFileCommand绑定事件
  168. /// </summary>
  169. private static readonly CommandBinding SaveFileCommandBinding;
  170.  
  171. /// <summary>
  172. /// 执行OpenFileCommand
  173. /// </summary>
  174. private static void SaveFileButtonClick(object sender, ExecutedRoutedEventArgs e)
  175. {
  176. var tbox = e.Parameter as FrameworkElement;
  177. var txt = tbox as TextBox;
  178. if (txt == null) return;
  179. SaveFileDialog fd = new SaveFileDialog();
  180. fd.Title = "文件保存路径";
  181. fd.Filter = "所有文件(*.*)|*.*";
  182. fd.FileName = txt.Text.Trim();
  183. if (fd.ShowDialog() == DialogResult.OK)
  184. {
  185. txt.Text = fd.FileName;
  186. }
  187. tbox.Focus();
  188. }
  189.  
  190. #endregion
  191.  
  192. /// <summary>
  193. /// 静态构造函数
  194. /// </summary>
  195. static ControlAttachProperty()
  196. {
  197. //ClearTextCommand
  198. ClearTextCommand = new RoutedUICommand();
  199. ClearTextCommandBinding = new CommandBinding(ClearTextCommand);
  200. ClearTextCommandBinding.Executed += ClearButtonClick;
  201. //OpenFileCommand
  202. OpenFileCommand = new RoutedUICommand();
  203. OpenFileCommandBinding = new CommandBinding(OpenFileCommand);
  204. OpenFileCommandBinding.Executed += OpenFileButtonClick;
  205. //OpenFolderCommand
  206. OpenFolderCommand = new RoutedUICommand();
  207. OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);
  208. OpenFolderCommandBinding.Executed += OpenFolderButtonClick;
  209.  
  210. SaveFileCommand = new RoutedUICommand();
  211. SaveFileCommandBinding = new CommandBinding(SaveFileCommand);
  212. SaveFileCommandBinding.Executed += SaveFileButtonClick;
  213. }

三.富文本框RichTextBox控件样式

  RichTextBox的样式比较简单:

  1. <!--***************************DefaultRichTextBox***************************-->
  2.  
  3. <Style x:Key="DefaultRichTextBox" TargetType="{x:Type RichTextBox}">
  4. <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
  5. <Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" />
  6. <Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
  7. <Setter Property="FontSize" Value="{StaticResource FontSize}" />
  8. <Setter Property="BorderThickness" Value="1" />
  9. <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
  10. <Setter Property="MinHeight" Value="26" />
  11. <Setter Property="MinWidth" Value="10" />
  12. <Setter Property="Background" Value="{StaticResource TextBackground}" />
  13. <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
  14. <Setter Property="CaretBrush" Value="{StaticResource TextForeground}" />
  15. <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" />
  16. <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" />
  17. <Setter Property="Padding" Value="1" />
  18. <Setter Property="AllowDrop" Value="True" />
  19. <Setter Property="VerticalScrollBarVisibility" Value="Auto" />
  20. <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  21. <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
  22. <!--该值指示是否启用了笔势-->
  23. <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
  24. <!--SnapsToDevicePixels:该值来确定呈现此元素是否应使用特定于设备的像素设置-->
  25. <Setter Property="SnapsToDevicePixels" Value="True" />
  26. <Setter Property="Template">
  27. <Setter.Value>
  28. <ControlTemplate TargetType="{x:Type TextBoxBase}">
  29. <Grid>
  30. <Border x:Name="Bd"
  31. BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
  32. Background="{TemplateBinding Background}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
  33. <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
  34. </Border>
  35. </Grid>
  36. <ControlTemplate.Triggers>
  37. <Trigger Property="IsMouseOver" Value="True">
  38. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/>
  39. </Trigger>
  40. <Trigger Property="IsFocused" Value="True">
  41. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/>
  42. </Trigger>
  43. <Trigger Property="IsEnabled" Value="False">
  44. <Setter TargetName="Bd" Property="Opacity" Value="0.5" />
  45. </Trigger>
  46. <Trigger Property="IsReadOnly" Value="True">
  47. <Setter TargetName="Bd" Property="Opacity" Value="0.85" />
  48. </Trigger>
  49. </ControlTemplate.Triggers>
  50. </ControlTemplate>
  51. </Setter.Value>
  52. </Setter>
  53. </Style>

  使用实力及效果:

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

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

  1. <!--TextBox默认样式-->
  2. <Style TargetType="{x:Type PasswordBox}" x:Key="DefaultPasswordBox">
  3. <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
  4. <Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" />
  5. <Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
  6. <Setter Property="FontSize" Value="{StaticResource FontSize}" />
  7. <Setter Property="BorderThickness" Value="1" />
  8. <Setter Property="PasswordChar" Value="●"/>
  9. <Setter Property="Height" Value="30" />
  10. <Setter Property="Width" Value="200" />
  11. <Setter Property="Background" Value="{StaticResource TextBackground}" />
  12. <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
  13. <Setter Property="Padding" Value="0" />
  14. <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
  15. <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" />
  16. <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" />
  17. <Setter Property="VerticalContentAlignment" Value="Center" />
  18. <!-- change SnapsToDevicePixels to True to view a better border and validation error -->
  19. <Setter Property="SnapsToDevicePixels" Value="True" />
  20. <!--英 ['kærət] 美 ['kærət] 插入符号-->
  21. <Setter Property="CaretBrush" Value="{StaticResource TextForeground}" />
  22. <Setter Property="Template">
  23. <Setter.Value>
  24. <ControlTemplate TargetType="{x:Type PasswordBox}">
  25. <Grid x:Name="PART_Root">
  26. <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
  27. CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}"
  28. BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" />
  29. <Grid x:Name="PART_InnerGrid">
  30. <Grid.ColumnDefinitions>
  31. <ColumnDefinition Width="Auto" />
  32. <ColumnDefinition Width="*" />
  33. <ColumnDefinition Width="Auto" />
  34. </Grid.ColumnDefinitions>
  35. <!--Label区域-->
  36. <ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}"
  37. Content="{TemplateBinding local:ControlAttachProperty.Label}"/>
  38. <!--内容区域-->
  39. <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2"
  40. VerticalAlignment="Stretch" Background="{x:Null}" />
  41. <!--附加内容区域-->
  42. <Border x:Name="PART_AttachContent" Grid.Column="2" Margin="2" VerticalAlignment="Center" HorizontalAlignment="Center" >
  43. <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" />
  44. </Border>
  45. </Grid>
  46. </Grid>
  47. <ControlTemplate.Triggers>
  48. <Trigger Property="IsMouseOver" Value="True">
  49. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/>
  50. </Trigger>
  51. <Trigger Property="IsFocused" Value="True">
  52. <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/>
  53. </Trigger>
  54. <!--不可用-->
  55. <Trigger Property="IsEnabled" Value="False">
  56. <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter>
  57. </Trigger>
  58. </ControlTemplate.Triggers>
  59. </ControlTemplate>
  60. </Setter.Value>
  61. </Setter>
  62. </Style>
  63.  
  64. <!--TextBox包含清除Text按钮的样式-->
  65. <Style TargetType="{x:Type PasswordBox}" x:Key="ClearButtonPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}">
  66. <Setter Property="local:ControlAttachProperty.AttachContent">
  67. <Setter.Value>
  68. <ControlTemplate>
  69. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  70. local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand"
  71. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"
  72. Margin="1,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  73. </ControlTemplate>
  74. </Setter.Value>
  75. </Setter>
  76. </Style>
  77.  
  78. <!--TextBox包含附加属性Label的样式-->
  79. <Style TargetType="{x:Type PasswordBox}" x:Key="LabelPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}">
  80. <Setter Property="local:ControlAttachProperty.LabelTemplate" >
  81. <Setter.Value>
  82. <ControlTemplate TargetType="ContentControl">
  83. <Border Width="60" Background="{StaticResource TextLabelBackground}">
  84. <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock>
  85. </Border>
  86. </ControlTemplate>
  87. </Setter.Value>
  88. </Setter>
  89. </Style>
  90.  
  91. <!--TextBox包含附加属性Label,以及ClearText按钮的样式-->
  92. <Style TargetType="{x:Type PasswordBox}" x:Key="LabelClearButtonPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}">
  93. <Setter Property="local:ControlAttachProperty.LabelTemplate" >
  94. <Setter.Value>
  95. <ControlTemplate TargetType="ContentControl">
  96. <Border Width="60" Background="{StaticResource TextLabelBackground}">
  97. <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock>
  98. </Border>
  99. </ControlTemplate>
  100. </Setter.Value>
  101. </Setter>
  102. <Setter Property="local:ControlAttachProperty.AttachContent">
  103. <Setter.Value>
  104. <ControlTemplate>
  105. <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
  106. local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand"
  107. CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"
  108. Margin="0,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
  109. </ControlTemplate>
  110. </Setter.Value>
  111. </Setter>
  112. </Style>

使用示例及效果:

附录.参考引用

WPF自定义控件与样式(1)-矢量字体图标(iconfont)

WPF自定义控件与样式(2)-自定义按钮FButton

《深入浅出WPF》学习笔记二数据绑定(Binding)、依赖属性和附加属性

版权所有,文章来源:http://www.cnblogs.com/anding

个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展的更多相关文章

  1. 【转】WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括: 基本文 ...

  2. 【转】WPF TextBox和PasswordBox加水印

    Textbox加水印 Textbox加水印,需要一个VisualBrush和触发器验证Text是否为空,在空的时候设置背景的Brush就可以实现水印效果. <TextBox Name=" ...

  3. WPF自定义控件(二)——TextBox

    和之前一样,先来看看效果: 这个TextBox可设置水印,可设置必填和正则表达式验证. 验证?没错,就是验证! 就是在输入完成后,控件一旦失去焦点就会自动验证!会根据我开放出来的“是否可以为空”属性进 ...

  4. WPF的TextBox以及PasswordBox显示水印文字

    1.TextBox <ControlTemplate x:Key="WaterMarkTextBox" TargetType="{x:Type TextBox}&q ...

  5. WPF自定义控件与样式(1)-矢量字体图标(iconfont)

    一.图标字体 图标字体在网页开发上运用非常广泛,具体可以网络搜索了解,网页上的运用有很多例子,如Bootstrap.但在C/S程序中使用还不多,字体图标其实就是把矢量图形打包到字体文件里,就像使用一般 ...

  6. WPF自定义控件与样式(2)-自定义按钮FButton

    一.前言.效果图 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 还是先看看效果 ...

  7. WPF自定义控件与样式(15)-终结篇 & 系列文章索引 & 源码共享

    系列文章目录  WPF自定义控件与样式(1)-矢量字体图标(iconfont) WPF自定义控件与样式(2)-自定义按钮FButton WPF自定义控件与样式(3)-TextBox & Ric ...

  8. WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Che ...

  9. WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 日历控 ...

随机推荐

  1. 记一次SQLServer的分页优化兼谈谈使用Row_Number()分页存在的问题

    最近有项目反应,在服务器CPU使用较高的时候,我们的事件查询页面非常的慢,查询几条记录竟然要4分钟甚至更长,而且在翻第二页的时候也是要这么多的时间,这肯定是不能接受的,也是让现场用SQLServerP ...

  2. C++中的时间函数

    C++获取时间函数众多,何时该用什么函数,拿到的是什么时间?该怎么用?很多人都会混淆. 本文是本人经历了几款游戏客户端和服务器开发后,对游戏中时间获取的一点总结. 最早学习游戏客户端时,为了获取最精确 ...

  3. 0.Win8.1,Win10,Windows Server 2012 安装 Net Framework 3.5

    后期会在博客首发更新:http://dnt.dkill.net 网站部署之~Windows Server | 本地部署:http://www.cnblogs.com/dunitian/p/482280 ...

  4. 旺财速啃H5框架之Bootstrap(一)

    接下来的时间里,我将和大家一起对当前非常流行的前端框架Bootstrap进行速度的学习,以案例的形式.对刚开始想学习Bootstrap的同学而找不着边的就很有帮助了.如果你想详细的学习Bootstra ...

  5. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  6. [开发笔记]GCC 分支预测优化

    #define likely(x) __builtin_expect(!!(x),1)#define unlikely(x) __builtin_expect(!!(x),0) 用于优化在做分支判断的 ...

  7. Android开发学习—— Fragment

    #Fragment* 用途:在一个Activity里切换界面,切换界面时只切换Fragment里面的内容* 生命周期方法跟Activity一致,可以理解把其为就是一个Activity* 定义布局文件作 ...

  8. Atitit.cto 与技术总监的区别

    Atitit.cto 与技术总监的区别 1. 核心区别1 2. Cto主要职责1 3. 如何提升到cto1 4. CTO五种基本的必备素质:2 5. 2 1. 核心区别 技术总监(Chief Tech ...

  9. PHP 数组浅析

    PHP的数组具有如下特点:1.数组初始化时无需指定长度:2.数组中的元素无需相同类型:3.数组的长度可变4.可使用var_dump(参数)或者print_r(  参数) 函数查看数组变量.5.数组内的 ...

  10. Merge Sorted Array

    Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...