一.前言.預覽 html
申明:WPF自定義控件與樣式是一個系列文章,先後是有些關聯的,但大可能是按照由簡到繁的順序逐步發佈的等,如有不明白的地方能夠參考本系列前面的文章,文末附有部分文章連接。app
本文主要是對文本輸入控件進行樣式開發,及相關擴展功能開發,主要內容包括: ide
效果圖:函數
二.基本文本框TextBox控件樣式及擴展功能 學習
2.1 TextBox基本樣式 字體
樣式代碼以下: spa
<!--TextBox默認樣式--> <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] 插入符號--> <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區域--> <ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" Content="{TemplateBinding local:ControlAttachProperty.Label}"/> <!--內容區域--> <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" /> <!--附加內容區域--> <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> <!--只讀時,禁用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>
模板內容主要包含四部分: 命令行
其中Label標籤、功能擴展,還有輸入框的不一樣狀態顯示效果都是經過附加屬性來實現的,其實從本質上附加屬性和控件上定義的依賴屬性是同一個概念,有些時候附加屬性會更加方便,對於一些可共用的屬性,就比較方便,這一點怎本文是有體現的。上面代碼使用到的附加屬性代碼: 3d
#region FocusBorderBrush 焦點邊框色,輸入控件 public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached( "FocusBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetFocusBorderBrush(DependencyObject element, Brush value) { element.SetValue(FocusBorderBrushProperty, value); } public static Brush GetFocusBorderBrush(DependencyObject element) { return (Brush)element.GetValue(FocusBorderBrushProperty); } #endregion #region MouseOverBorderBrush 鼠標進入邊框色,輸入控件 public static readonly DependencyProperty MouseOverBorderBrushProperty = DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); /// <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); } #endregion
2.2 水印效果實現 code
經過2.1的代碼示例,能夠看出,水印是內置了一個TextBlock,用附加屬性ControlAttachProperty.Watermark設置水印內容,在觸發器中檢測,當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標籤實現
參考2.1的代碼,預留了Label的區域,經過設置附加屬性local:ControlAttachProperty.Label設置標籤文本,local:ControlAttachProperty.LabelTemplate設置Label標籤的模板樣式,便可自定義實現Label標籤,自定義樣式:
<!--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="請輸入姓名" Style="{StaticResource LabelTextBox}" core:ControlAttachProperty.Label="姓名:"></TextBox>
2.4 擴展功能及自定義擴展
思路和2.3的Label標籤實現類似,清除文本框內的內容是一個經常使用需求,咱們就線擴展一個這麼一個功能的TextBox,經過附加屬性ControlAttachProperty.AttachContent定義擴展功能的模板,模板內定義的是一個按鈕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內容的邏輯代碼如何實現的呢?仍是附加屬性:
邏輯代碼以下,從代碼不難看出,它是支持多種輸入控件的內容清除的,也就是說該擴展功能能夠輕鬆支持其餘輸入控件,第四節密碼數據的清除也是這樣使用的。
#region IsClearTextButtonBehaviorEnabledProperty 清除輸入框Text值按鈕行爲開關(設爲ture時纔會綁定事件) /// <summary> /// 清除輸入框Text值按鈕行爲開關 /// </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> /// 靜態構造函數 /// </summary> static ControlAttachProperty() { //ClearTextCommand ClearTextCommand = new RoutedUICommand(); ClearTextCommandBinding = new CommandBinding(ClearTextCommand); ClearTextCommandBinding.Executed += ClearButtonClick; //OpenFileCommand OpenFileCommand = new RoutedUICommand(); OpenFileCommandBinding = new CommandBinding(OpenFileCommand); OpenFileCommandBinding.Executed += OpenFileButtonClick; //OpenFolderCommand OpenFolderCommand = new RoutedUICommand(); OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand); OpenFolderCommandBinding.Executed += OpenFolderButtonClick; SaveFileCommand = new RoutedUICommand(); SaveFileCommandBinding = new CommandBinding(SaveFileCommand); SaveFileCommandBinding.Executed += SaveFileButtonClick; }
效果:
固然咱們也能夠自定義擴展其餘功能,如:
<TextBox Width="200" Height="30" Margin="3" core:ControlAttachProperty.Watermark="查詢關鍵詞" 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>
效果:
由上不難同時實現Label標籤和清除文本內容的樣式:
<!--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 文件選擇輸入相關擴展
先看看效果,就明白了。
具體實現原理和上面2.4差很少 ,實現了三個文件、文件夾選擇相關的功能擴展,樣式代碼:
<!--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="設置路徑"/> <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>
固然實現原理和2.4同樣,都是依賴屬性來實現事件的注入和綁定的,因此就很少廢話了:
#region IsOpenFileButtonBehaviorEnabledProperty 選擇文件命令行爲開關 /// <summary> /// 選擇文件命令行爲開關 /// </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 選擇文件夾命令行爲開關 /// <summary> /// 選擇文件夾命令行爲開關 /// </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> /// 執行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 = "請選擇文件"; //「圖像文件(*.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> /// 執行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 = "請選擇文件路徑"; 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> /// 執行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> /// 靜態構造函數 /// </summary> static ControlAttachProperty() { //ClearTextCommand ClearTextCommand = new RoutedUICommand(); ClearTextCommandBinding = new CommandBinding(ClearTextCommand); ClearTextCommandBinding.Executed += ClearButtonClick; //OpenFileCommand OpenFileCommand = new RoutedUICommand(); OpenFileCommandBinding = new CommandBinding(OpenFileCommand); OpenFileCommandBinding.Executed += OpenFileButtonClick; //OpenFolderCommand OpenFolderCommand = new RoutedUICommand(); OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand); OpenFolderCommandBinding.Executed += OpenFolderButtonClick; SaveFileCommand = new RoutedUICommand(); SaveFileCommandBinding = new CommandBinding(SaveFileCommand); SaveFileCommandBinding.Executed += SaveFileButtonClick; }
三.富文本框RichTextBox控件樣式
RichTextBox的樣式比較簡單:
<!--***************************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" /> <!--該值指示是否啓用了筆勢--> <Setter Property="Stylus.IsFlicksEnabled" Value="False" /> <!--SnapsToDevicePixels:該值來肯定呈現此元素是否應使用特定於設備的像素設置--> <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>
使用實力及效果:
四.密碼輸入框PasswordBox控件樣式及擴展功能
密碼輸入控件的樣式和第二節文本框TextBox基本一致,就不作詳細的說明了,直接上樣式的代碼,相關邏輯(C#) 代碼和上面是同樣的(複用)。
<!--TextBox默認樣式--> <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] 插入符號--> <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區域--> <ContentControl x:Name="Label" Margin="1" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" Content="{TemplateBinding local:ControlAttachProperty.Label}"/> <!--內容區域--> <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2" VerticalAlignment="Stretch" Background="{x:Null}" /> <!--附加內容區域--> <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>
使用示例及效果:
附錄.參考引用
WPF自定義控件與樣式(1)-矢量字體圖標(iconfont)
《深刻淺出WPF》學習筆記二數據綁定(Binding)、依賴屬性和附加屬性
版權全部,文章來源:http://www.cnblogs.com/anding
我的能力有限,本文內容僅供學習、探討,歡迎指正、交流。