【转】WPF自定义控件与样式(3)-TextBox RichTextBox PasswordBox样式、水印、Label标签、功能扩展...
一.前言.預(yù)覽
申明:WPF自定義控件與樣式是一個(gè)系列文章,前后是有些關(guān)聯(lián)的,但大多是按照由簡(jiǎn)到繁的順序逐步發(fā)布的等。
本文主要是對(duì)文本輸入控件進(jìn)行樣式開發(fā),及相關(guān)擴(kuò)展功能開發(fā),主要內(nèi)容包括:
- 基本文本框TextBox控件樣式及擴(kuò)展功能,實(shí)現(xiàn)了樣式、水印、Label標(biāo)簽、功能擴(kuò)展;
- 富文本框RichTextBox控件樣式;
- 密碼輸入框PasswordBox控件樣式及擴(kuò)展功能;
效果圖:
二.基本文本框TextBox控件樣式及擴(kuò)展功能
2.1 TextBox基本樣式
樣式代碼如下:??
<!--TextBox默認(rèn)樣式--><Style TargetType="{x:Type TextBox}" x:Key="DefaultTextBox"><Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" /><Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" /><Setter Property="FontFamily" Value="{StaticResource FontFamily}" /><Setter Property="FontSize" Value="{StaticResource FontSize}" /><Setter Property="BorderThickness" Value="1" /><Setter Property="MinHeight" Value="26" /><Setter Property="Width" Value="100" /><Setter Property="Background" Value="{StaticResource TextBackground}" /><Setter Property="Foreground" Value="{StaticResource TextForeground}" /><Setter Property="Padding" Value="0" /><Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /><Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /><Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /><Setter Property="VerticalContentAlignment" Value="Center" /><!-- change SnapsToDevicePixels to True to view a better border and validation error --><Setter Property="SnapsToDevicePixels" Value="True" /><!--英 ['k?r?t] 美 ['k?r?t] 插入符號(hào)--><Setter Property="CaretBrush" Value="{StaticResource TextForeground}" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type TextBox}"><Grid x:Name="PART_Root"><Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /><Grid x:Name="PART_InnerGrid"><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition Width="*" /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><!--Label區(qū)域--><ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}"Content="{TemplateBinding local:ControlAttachProperty.Label}"/><!--內(nèi)容區(qū)域--><ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2"VerticalAlignment="Stretch" Background="{x:Null}" /><!--水印--><TextBlock x:Name="Message" Padding="{TemplateBinding Padding}" Visibility="Collapsed"Text="{TemplateBinding local:ControlAttachProperty.Watermark}" Grid.Column="1"Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="{StaticResource WatermarkOpacity}"HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="5,2,5,2" /><!--附加內(nèi)容區(qū)域--><Border x:Name="PART_AttachContent" Grid.Column="2" Margin="2" VerticalAlignment="Center" HorizontalAlignment="Center" ><ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" /></Border></Grid></Grid><ControlTemplate.Triggers><!--顯示水印--><DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value=""><Setter TargetName="Message" Property="Visibility" Value="Visible" /></DataTrigger><Trigger Property="IsMouseOver" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><!--不可用--><Trigger Property="IsEnabled" Value="False"><Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}" /></Trigger><!--只讀時(shí),禁用PART_AttachContent--><Trigger Property="IsReadOnly" Value="True"><Setter TargetName="PART_AttachContent" Property="IsEnabled" Value="False" /><Setter TargetName="Bg" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" /><Setter TargetName="PART_ContentHost" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" /><Setter TargetName="Label" Property="Opacity" Value="{StaticResource ReadonlyOpacity}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>模板內(nèi)容主要包含四部分:
- 用于實(shí)現(xiàn)Label標(biāo)簽的預(yù)留區(qū)域;
- TextBox本身的文本輸入顯示部分;
- 水印顯示部分;
- 功能擴(kuò)展的預(yù)留區(qū)域;
其中Label標(biāo)簽、功能擴(kuò)展,還有輸入框的不同狀態(tài)顯示效果都是通過附加屬性來實(shí)現(xiàn)的,其實(shí)從本質(zhì)上附加屬性和控件上定義的依賴屬性是同一個(gè)概念,有些時(shí)候附加屬性會(huì)更加方便,對(duì)于一些可共用的屬性,就比較方便,這一點(diǎn)怎本文是有體現(xiàn)的。上面代碼使用到的附加屬性代碼:
#region FocusBorderBrush 焦點(diǎn)邊框色,輸入控件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 鼠標(biāo)進(jìn)入邊框色,輸入控件public static readonly DependencyProperty MouseOverBorderBrushProperty =DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty),new FrameworkPropertyMetadata(Brushes.Transparent,FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));/// <summary>/// Sets the brush used to draw the mouse over brush./// </summary>public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value){obj.SetValue(MouseOverBorderBrushProperty, value);}/// <summary>/// Gets the brush used to draw the mouse over brush./// </summary>[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 附加組件模板/// <summary>/// 附加組件模板/// </summary>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 水印/// <summary>/// 水印/// </summary>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圓角/// <summary>/// Border圓角/// </summary>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/// <summary>/// TextBox的頭部Label/// </summary>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模板/// <summary>/// TextBox的頭部Label模板/// </summary>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);}#endregion2.2 水印效果實(shí)現(xiàn)
通過2.1的代碼示例,可以看出,水印是內(nèi)置了一個(gè)TextBlock,用附加屬性ControlAttachProperty.Watermark設(shè)置水印內(nèi)容,在觸發(fā)器中檢測(cè),當(dāng)TextBox中有輸入值,則隱藏水印的TextBlock,使用示例:??
<StackPanel><TextBox Width="140" Height="40" Margin="3" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible">333333333333333</TextBox><TextBox Width="150" Height="30" Margin="3" core:ControlAttachProperty.Watermark="我是水印" core:ControlAttachProperty.CornerRadius="2"></TextBox><TextBox Width="150" Height="30" Margin="3" IsReadOnly="True" core:ControlAttachProperty.CornerRadius="15" SnapsToDevicePixels="True" >我是只讀的</TextBox><TextBox Width="150" Height="30" Margin="3" IsEnabled="False">IsEnabled="False"</TextBox><TextBox Width="150" Height="30" core:ControlAttachProperty.Watermark="我是水印"></TextBox></StackPanel>效果:
2.3 Label標(biāo)簽實(shí)現(xiàn)
參考2.1的代碼,預(yù)留了Label的區(qū)域,通過設(shè)置附加屬性local:ControlAttachProperty.Label設(shè)置標(biāo)簽文本,local:ControlAttachProperty.LabelTemplate設(shè)置Label標(biāo)簽的模板樣式,即可自定義實(shí)現(xiàn)Label標(biāo)簽,自定義樣式:
<!--TextBox包含附加屬性Label的樣式--><Style TargetType="{x:Type TextBox}" x:Key="LabelTextBox" BasedOn="{StaticResource DefaultTextBox}"><Setter Property="local:ControlAttachProperty.LabelTemplate" ><Setter.Value><ControlTemplate TargetType="ContentControl"><Border Width="60" Background="{StaticResource TextLabelBackground}"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock></Border></ControlTemplate></Setter.Value></Setter></Style>使用示例及效果:?
<TextBox Width="200" Height="30" Margin="3" core:ControlAttachProperty.Watermark="請(qǐng)輸入姓名" Style="{StaticResource LabelTextBox}" core:ControlAttachProperty.Label="姓名:"></TextBox>2.4 擴(kuò)展功能及自定義擴(kuò)展
思路和2.3的Label標(biāo)簽實(shí)現(xiàn)相似,清除文本框內(nèi)的內(nèi)容是一個(gè)常用需求,我們就線擴(kuò)展一個(gè)這么一個(gè)功能的TextBox,通過附加屬性ControlAttachProperty.AttachContent定義擴(kuò)展功能的模板,模板內(nèi)定義的是一個(gè)按鈕FButton(可參考上一篇,本文末尾附錄中有鏈接)??
<!--TextBox包含清除Text按鈕的樣式--><Style TargetType="{x:Type TextBox}" x:Key="ClearButtonTextBox" BasedOn="{StaticResource DefaultTextBox}"><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"Margin="1,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style>這里定義的是顯示效果,清除TextBox內(nèi)容的邏輯代碼如何實(shí)現(xiàn)的呢?還是附加屬性:
- ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" :注入事件到當(dāng)前Button
- Command="local:ControlAttachProperty.ClearTextCommand":定義Fbutton的命令對(duì)象實(shí)例Command
- CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}":把TextBox作為參數(shù)傳入
邏輯代碼如下,從代碼不難看出,它是支持多種輸入控件的內(nèi)容清除的,也就是說該擴(kuò)展功能可以輕松支持其他輸入控件,第四節(jié)密碼數(shù)據(jù)的清除也是這樣使用的。
#region IsClearTextButtonBehaviorEnabledProperty 清除輸入框Text值按鈕行為開關(guān)(設(shè)為ture時(shí)才會(huì)綁定事件)/// <summary>/// 清除輸入框Text值按鈕行為開關(guān)/// </summary>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);}/// <summary>/// 綁定清除Text操作的按鈕事件/// </summary>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事件命令/// <summary>/// 清除輸入框Text事件命令,需要使用IsClearTextButtonBehaviorEnabledChanged綁定命令/// </summary>public static RoutedUICommand ClearTextCommand { get; private set; }/// <summary>/// ClearTextCommand綁定事件/// </summary>private static readonly CommandBinding ClearTextCommandBinding;/// <summary>/// 清除輸入框文本值/// </summary>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/// <summary>/// 靜態(tài)構(gòu)造函數(shù)/// </summary>static ControlAttachProperty(){//ClearTextCommandClearTextCommand = new RoutedUICommand();ClearTextCommandBinding = new CommandBinding(ClearTextCommand);ClearTextCommandBinding.Executed += ClearButtonClick;//OpenFileCommandOpenFileCommand = new RoutedUICommand();OpenFileCommandBinding = new CommandBinding(OpenFileCommand);OpenFileCommandBinding.Executed += OpenFileButtonClick;//OpenFolderCommandOpenFolderCommand = new RoutedUICommand();OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);OpenFolderCommandBinding.Executed += OpenFolderButtonClick;SaveFileCommand = new RoutedUICommand();SaveFileCommandBinding = new CommandBinding(SaveFileCommand);SaveFileCommandBinding.Executed += SaveFileButtonClick;}效果:
當(dāng)然我們也可以自定義擴(kuò)展其他功能,如:??
<TextBox Width="200" Height="30" Margin="3" core:ControlAttachProperty.Watermark="查詢關(guān)鍵詞" IsEnabled="True"><core:ControlAttachProperty.AttachContent><ControlTemplate><StackPanel Orientation="Horizontal"><core:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"FIconSize="18" Margin="1,1,2,3" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/><core:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></StackPanel></ControlTemplate></core:ControlAttachProperty.AttachContent></TextBox>效果:
由上不難同時(shí)實(shí)現(xiàn)Label標(biāo)簽和清除文本內(nèi)容的樣式:
<!--TextBox包含附加屬性Label,以及ClearText按鈕的樣式--><Style TargetType="{x:Type TextBox}" x:Key="LabelClearButtonTextBox" BasedOn="{StaticResource DefaultTextBox}"><Setter Property="local:ControlAttachProperty.LabelTemplate" ><Setter.Value><ControlTemplate TargetType="ContentControl"><Border Width="60" Background="{StaticResource TextLabelBackground}"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock></Border></ControlTemplate></Setter.Value></Setter><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"Margin="0,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style>2.6 文件選擇輸入相關(guān)擴(kuò)展
先看看效果,就明白了。
?
具體實(shí)現(xiàn)原理和上面2.4差不多 ,實(shí)現(xiàn)了三個(gè)文件、文件夾選擇相關(guān)的功能擴(kuò)展,樣式代碼:
<!--LabelOpenFileTextBox--><Style TargetType="{x:Type TextBox}" x:Key="LabelOpenFileTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}"><Setter Property="local:ControlAttachProperty.Label" Value="文件路徑"/><Setter Property="local:ControlAttachProperty.Watermark" Value="選擇文件路徑"/><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsOpenFileButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.OpenFileCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"Margin="0,1,0,1" FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style><!--LabelOpenFolderTextBox--><Style TargetType="{x:Type TextBox}" x:Key="LabelOpenFolderTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}"><Setter Property="local:ControlAttachProperty.Label" Value="設(shè)置路徑"/><Setter Property="local:ControlAttachProperty.Watermark" Value="選擇文件夾路徑"/><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsOpenFolderButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.OpenFolderCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"Margin="0,1,0,1" FIconSize="22" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style><!--LabelSaveFileTextBox--><Style TargetType="{x:Type TextBox}" x:Key="LabelSaveFileTextBox" BasedOn="{StaticResource LabelClearButtonTextBox}"><Setter Property="local:ControlAttachProperty.Label" Value="保存路徑"/><Setter Property="local:ControlAttachProperty.Watermark" Value="選擇文件保存路徑"/><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsSaveFileButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.SaveFileCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"Margin="0,1,0,1" FIconSize="20" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style>當(dāng)然實(shí)現(xiàn)原理和2.4一樣,都是依賴屬性來實(shí)現(xiàn)事件的注入和綁定的,所以就不多廢話了:
#region IsOpenFileButtonBehaviorEnabledProperty 選擇文件命令行為開關(guān)/// <summary>/// 選擇文件命令行為開關(guān)/// </summary>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 選擇文件夾命令行為開關(guān)/// <summary>/// 選擇文件夾命令行為開關(guān)/// </summary>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 選擇文件保存路徑及名稱/// <summary>/// 選擇文件保存路徑及名稱/// </summary>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 選擇文件命令/// <summary>/// 選擇文件命令,需要使用IsClearTextButtonBehaviorEnabledChanged綁定命令/// </summary>public static RoutedUICommand OpenFileCommand { get; private set; }/// <summary>/// OpenFileCommand綁定事件/// </summary>private static readonly CommandBinding OpenFileCommandBinding;/// <summary>/// 執(zhí)行OpenFileCommand/// </summary>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 = "請(qǐng)選擇文件";//“圖像文件(*.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 選擇文件夾命令/// <summary>/// 選擇文件夾命令/// </summary>public static RoutedUICommand OpenFolderCommand { get; private set; }/// <summary>/// OpenFolderCommand綁定事件/// </summary>private static readonly CommandBinding OpenFolderCommandBinding;/// <summary>/// 執(zhí)行OpenFolderCommand/// </summary>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 = "請(qǐng)選擇文件路徑";fd.SelectedPath = txt.Text.Trim();if (fd.ShowDialog() == DialogResult.OK){txt.Text = fd.SelectedPath;}tbox.Focus();}#endregion#region SaveFileCommand 選擇文件保存路徑及名稱/// <summary>/// 選擇文件保存路徑及名稱/// </summary>public static RoutedUICommand SaveFileCommand { get; private set; }/// <summary>/// SaveFileCommand綁定事件/// </summary>private static readonly CommandBinding SaveFileCommandBinding;/// <summary>/// 執(zhí)行OpenFileCommand/// </summary>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/// <summary>/// 靜態(tài)構(gòu)造函數(shù)/// </summary>static ControlAttachProperty(){//ClearTextCommandClearTextCommand = new RoutedUICommand();ClearTextCommandBinding = new CommandBinding(ClearTextCommand);ClearTextCommandBinding.Executed += ClearButtonClick;//OpenFileCommandOpenFileCommand = new RoutedUICommand();OpenFileCommandBinding = new CommandBinding(OpenFileCommand);OpenFileCommandBinding.Executed += OpenFileButtonClick;//OpenFolderCommandOpenFolderCommand = new RoutedUICommand();OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand);OpenFolderCommandBinding.Executed += OpenFolderButtonClick;SaveFileCommand = new RoutedUICommand();SaveFileCommandBinding = new CommandBinding(SaveFileCommand);SaveFileCommandBinding.Executed += SaveFileButtonClick;}?三.富文本框RichTextBox控件樣式
RichTextBox的樣式比較簡(jiǎn)單:??
<!--***************************DefaultRichTextBox***************************--><Style x:Key="DefaultRichTextBox" TargetType="{x:Type RichTextBox}"><Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" /><Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" /><Setter Property="FontFamily" Value="{StaticResource FontFamily}" /><Setter Property="FontSize" Value="{StaticResource FontSize}" /><Setter Property="BorderThickness" Value="1" /><Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /><Setter Property="MinHeight" Value="26" /><Setter Property="MinWidth" Value="10" /><Setter Property="Background" Value="{StaticResource TextBackground}" /><Setter Property="Foreground" Value="{StaticResource TextForeground}" /><Setter Property="CaretBrush" Value="{StaticResource TextForeground}" /><Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /><Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /><Setter Property="Padding" Value="1" /><Setter Property="AllowDrop" Value="True" /><Setter Property="VerticalScrollBarVisibility" Value="Auto" /><Setter Property="FocusVisualStyle" Value="{x:Null}" /><Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" /><!--該值指示是否啟用了筆勢(shì)--><Setter Property="Stylus.IsFlicksEnabled" Value="False" /><!--SnapsToDevicePixels:該值來確定呈現(xiàn)此元素是否應(yīng)使用特定于設(shè)備的像素設(shè)置--><Setter Property="SnapsToDevicePixels" Value="True" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type TextBoxBase}"><Grid><Border x:Name="Bd"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"Background="{TemplateBinding Background}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"><ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><Trigger Property="IsEnabled" Value="False"><Setter TargetName="Bd" Property="Opacity" Value="0.5" /></Trigger><Trigger Property="IsReadOnly" Value="True"><Setter TargetName="Bd" Property="Opacity" Value="0.85" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>使用實(shí)力及效果:??
四.密碼輸入框PasswordBox控件樣式及擴(kuò)展功能
密碼輸入控件的樣式和第二節(jié)文本框TextBox基本一致,就不做詳細(xì)的說明了,直接上樣式的代碼,相關(guān)邏輯(C#) 代碼和上面是一樣的(復(fù)用)。
<!--TextBox默認(rèn)樣式--><Style TargetType="{x:Type PasswordBox}" x:Key="DefaultPasswordBox"><Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" /><Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" /><Setter Property="FontFamily" Value="{StaticResource FontFamily}" /><Setter Property="FontSize" Value="{StaticResource FontSize}" /><Setter Property="BorderThickness" Value="1" /><Setter Property="PasswordChar" Value="●"/><Setter Property="Height" Value="30" /><Setter Property="Width" Value="200" /><Setter Property="Background" Value="{StaticResource TextBackground}" /><Setter Property="Foreground" Value="{StaticResource TextForeground}" /><Setter Property="Padding" Value="0" /><Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /><Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /><Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /><Setter Property="VerticalContentAlignment" Value="Center" /><!-- change SnapsToDevicePixels to True to view a better border and validation error --><Setter Property="SnapsToDevicePixels" Value="True" /><!--英 ['k?r?t] 美 ['k?r?t] 插入符號(hào)--><Setter Property="CaretBrush" Value="{StaticResource TextForeground}" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type PasswordBox}"><Grid x:Name="PART_Root"><Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /><Grid x:Name="PART_InnerGrid"><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition Width="*" /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><!--Label區(qū)域--><ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}"Content="{TemplateBinding local:ControlAttachProperty.Label}"/><!--內(nèi)容區(qū)域--><ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2"VerticalAlignment="Stretch" Background="{x:Null}" /><!--附加內(nèi)容區(qū)域--><Border x:Name="PART_AttachContent" Grid.Column="2" Margin="2" VerticalAlignment="Center" HorizontalAlignment="Center" ><ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" /></Border></Grid></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/></Trigger><!--不可用--><Trigger Property="IsEnabled" Value="False"><Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style><!--TextBox包含清除Text按鈕的樣式--><Style TargetType="{x:Type PasswordBox}" x:Key="ClearButtonPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}"><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"Margin="1,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style><!--TextBox包含附加屬性Label的樣式--><Style TargetType="{x:Type PasswordBox}" x:Key="LabelPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}"><Setter Property="local:ControlAttachProperty.LabelTemplate" ><Setter.Value><ControlTemplate TargetType="ContentControl"><Border Width="60" Background="{StaticResource TextLabelBackground}"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock></Border></ControlTemplate></Setter.Value></Setter></Style><!--TextBox包含附加屬性Label,以及ClearText按鈕的樣式--><Style TargetType="{x:Type PasswordBox}" x:Key="LabelClearButtonPasswordBox" BasedOn="{StaticResource DefaultPasswordBox}"><Setter Property="local:ControlAttachProperty.LabelTemplate" ><Setter.Value><ControlTemplate TargetType="ContentControl"><Border Width="60" Background="{StaticResource TextLabelBackground}"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="3" Text="{TemplateBinding Content}"></TextBlock></Border></ControlTemplate></Setter.Value></Setter><Setter Property="local:ControlAttachProperty.AttachContent"><Setter.Value><ControlTemplate><local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"Margin="0,3,1,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/></ControlTemplate></Setter.Value></Setter></Style>使用示例及效果:??
?
原文地址:http://www.cnblogs.com/anding/p/4970845.html
轉(zhuǎn)載于:https://www.cnblogs.com/mqxs/p/10142316.html
總結(jié)
以上是生活随笔為你收集整理的【转】WPF自定义控件与样式(3)-TextBox RichTextBox PasswordBox样式、水印、Label标签、功能扩展...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 西柏坡剧情介绍
- 下一篇: gitlab中的CI
