使用附加屬性增加控件屬性,使得這個附加屬性在使用的時候沒有局限性,可以在任何的控件中使用它來增加所需要的屬性,使得控件的屬性使用起來非常靈活
一、自定義附加屬性
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace Demo3.Control { public class ControlAttachProperty { #region 圓角 public static CornerRadius GetCornerRadius(DependencyObject obj) { return (CornerRadius)obj.GetValue(CornerRadiusProperty); } public static void SetCornerRadius(DependencyObject obj, CornerRadius value) { obj.SetValue(CornerRadiusProperty, value); } // Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 用戶頭像模板 public static ControlTemplate GetIconTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(IconTemplateProperty); } public static void SetIconTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(IconTemplateProperty, value); } // Using a DependencyProperty as the backing store for IconTemplate. This enables animation, styling, binding, etc... public static readonly DependencyProperty IconTemplateProperty = DependencyProperty.RegisterAttached("IconTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 刪除按妞區域模板 public static ControlTemplate GetAttachTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(AttachTemplateProperty); } public static void SetAttachTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(AttachTemplateProperty, value); } // Using a DependencyProperty as the backing store for AttachTemplate. This enables animation, styling, binding, etc... public static readonly DependencyProperty AttachTemplateProperty = DependencyProperty.RegisterAttached("AttachTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 用戶名水印 public static string GetUserNameWaterMark(DependencyObject obj) { return (string)obj.GetValue(UserNameWaterMarkProperty); } public static void SetUserNameWaterMark(DependencyObject obj, string value) { obj.SetValue(UserNameWaterMarkProperty, value); } // Using a DependencyProperty as the backing store for UserNameWaterMark. This enables animation, styling, binding, etc... public static readonly DependencyProperty UserNameWaterMarkProperty = DependencyProperty.RegisterAttached("UserNameWaterMark", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 密碼水印 public static string GetPasswordWaterMark(DependencyObject obj) { return (string)obj.GetValue(PasswordWaterMarkProperty); } public static void SetPasswordWaterMark(DependencyObject obj, string value) { obj.SetValue(PasswordWaterMarkProperty, value); } // Using a DependencyProperty as the backing store for PasswordWaterMark. This enables animation, styling, binding, etc... public static readonly DependencyProperty PasswordWaterMarkProperty = DependencyProperty.RegisterAttached("PasswordWaterMark", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 用戶頭像(未被點擊時) public static string GetUserIcon(DependencyObject obj) { return (string)obj.GetValue(UserIconProperty); } public static void SetUserIcon(DependencyObject obj, string value) { obj.SetValue(UserIconProperty, value); } // Using a DependencyProperty as the backing store for UserIcon. This enables animation, styling, binding, etc... public static readonly DependencyProperty UserIconProperty = DependencyProperty.RegisterAttached("UserIcon", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 用戶頭像(點擊時) public static string GetUserIconPress(DependencyObject obj) { return (string)obj.GetValue(UserIconPressProperty); } public static void SetUserIconPress(DependencyObject obj, string value) { obj.SetValue(UserIconPressProperty, value); } // Using a DependencyProperty as the backing store for UserIconPress. This enables animation, styling, binding, etc... public static readonly DependencyProperty UserIconPressProperty = DependencyProperty.RegisterAttached("UserIconPress", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 密碼圖標(未被點擊時) public static string GetPassWordIcon(DependencyObject obj) { return (string)obj.GetValue(PassWordIconProperty); } public static void SetPassWordIcon(DependencyObject obj, string value) { obj.SetValue(PassWordIconProperty, value); } // Using a DependencyProperty as the backing store for PassWordIcon. This enables animation, styling, binding, etc... public static readonly DependencyProperty PassWordIconProperty = DependencyProperty.RegisterAttached("PassWordIcon", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 密碼圖標(點擊時) public static string GetPasswordIconPress(DependencyObject obj) { return (string)obj.GetValue(PasswordIconPressProperty); } public static void SetPasswordIconPress(DependencyObject obj, string value) { obj.SetValue(PasswordIconPressProperty, value); } // Using a DependencyProperty as the backing store for PasswordIconPress. This enables animation, styling, binding, etc... public static readonly DependencyProperty PasswordIconPressProperty = DependencyProperty.RegisterAttached("PasswordIconPress", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 刪除按妞背景圖片 public static ImageBrush GetDeleteButtonBG(DependencyObject obj) { return (ImageBrush)obj.GetValue(DeleteButtonBGProperty); } public static void SetDeleteButtonBG(DependencyObject obj, ImageBrush value) { obj.SetValue(DeleteButtonBGProperty, value); } // Using a DependencyProperty as the backing store for DeleteButtonBG. This enables animation, styling, binding, etc... public static readonly DependencyProperty DeleteButtonBGProperty = DependencyProperty.RegisterAttached("DeleteButtonBG", typeof(ImageBrush), typeof(ControlAttachProperty), new PropertyMetadata(null)); #endregion #region 定義是否開啟綁定事件 public static bool GetIsCommandClearTextEvent(DependencyObject obj) { return (bool)obj.GetValue(IsCommandClearTextEventProperty); } public static void SetIsCommandClearTextEvent(DependencyObject obj, bool value) { obj.SetValue(IsCommandClearTextEventProperty, value); } // Using a DependencyProperty as the backing store for IsCommandClearTextEvent. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsCommandClearTextEventProperty = DependencyProperty.RegisterAttached("IsCommandClearTextEvent", typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false,IsCommandClearTextEventChanged)); private static void IsCommandClearTextEventChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { } #endregion #region 是否顯示密碼樣式 public static bool GetIsVisiblityPassword(DependencyObject obj) { return (bool)obj.GetValue(IsVisiblityPasswordProperty); } public static void SetIsVisiblityPassword(DependencyObject obj, bool value) { obj.SetValue(IsVisiblityPasswordProperty, value); } // Using a DependencyProperty as the backing store for IsVisiblityPassword. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsVisiblityPasswordProperty = DependencyProperty.RegisterAttached("IsVisiblityPassword", typeof(bool), typeof(ControlAttachProperty), new PropertyMetadata(false)); #endregion #region 清除事件命令 public static bool GetIsClearTextButtonBehaviorEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsClearTextButtonBehaviorEnabledProperty); } public static void SetIsClearTextButtonBehaviorEnabled(DependencyObject obj, bool value) { obj.SetValue(IsClearTextButtonBehaviorEnabledProperty, value); } // Using a DependencyProperty as the backing store for IsClearTextButtonBehaviorEnabled. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsClearTextButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsClearTextButtonBehaviorEnabled", typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false,IsClearTextButtonBehaviorEnabledChanged)); /// <summary> /// 當附加屬性值發生改變時,調用此方法 /// </summary> /// <param name="d"></param> /// <param name="e"></param> private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button=d as DeleteButton; if(e.OldValue != e.NewValue) { //當命令觸發的時候,會向上傳遞,而此時這個命令外圍就是自己本身 button.CommandBindings.Add(ClearTextCommandBinding); } } /** * 當命令觸發的時候,會一級一級向上傳遞,當傳遞到命令關聯者時,會處理這個命令 */ /// <summary> /// 創建一個命令 /// </summary> public static RoutedUICommand ClearTextCommand{get;private set;} /// <summary> /// 命令綁定關聯 /// </summary> private static readonly CommandBinding ClearTextCommandBinding; 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(); } tbox.Focus(); } #endregion static ControlAttachProperty() { ClearTextCommand = new RoutedUICommand(); ClearTextCommandBinding =new CommandBinding(); //將者命令加入到這個命令關聯中,如果某個控件調用了這個命令,只要他所在的層級中有關聯這個命令關聯對象,那么這個命令對象就會對其進行處理 ClearTextCommandBinding.Command = ClearTextCommand; ClearTextCommandBinding.Executed+=ClearButtonClick; } } }
在布局文件中使用它
<Window x:Class="Demo3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:Demo3.Control" Background="Black" Title="MainWindow" WindowStartupLocation="CenterScreen" Height="350" Width="525"> <StackPanel> <TextBox x:Name="UserName" Width="230" Height="38" Margin="0,20,0,0" FontSize="18" VerticalContentAlignment="Center" c:ControlAttachProperty.CornerRadius="5" c:ControlAttachProperty.UserNameWaterMark="用戶名" c:ControlAttachProperty.UserIcon="{StaticResource UserName_BG}" c:ControlAttachProperty.UserIconPress="{StaticResource UserName_BG_Press}" c:ControlAttachProperty.DeleteButtonBG="{StaticResource Delete_Button_BG}" c:ControlAttachProperty.IsVisiblityPassword="false" Style="{StaticResource IconClearButtonTextBox}" /> <TextBox x:Name="Password" Width="230" Height="38" Margin="0,20,0,0" FontSize="18" VerticalContentAlignment="Center" c:ControlAttachProperty.CornerRadius="5" c:ControlAttachProperty.UserNameWaterMark="密碼" c:ControlAttachProperty.UserIcon="{StaticResource Password_BG}" c:ControlAttachProperty.UserIconPress="{StaticResource Password_BG_Press}" c:ControlAttachProperty.DeleteButtonBG="{StaticResource Delete_Button_BG}" c:ControlAttachProperty.IsVisiblityPassword="true" Style="{StaticResource IconClearButtonTextBox}" /> </StackPanel> </Window>
在style文件中進行使用
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:c="clr-namespace:Demo3.Control" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/Demo3;component/Resources/Style/DeleteButton.xaml" /> </ResourceDictionary.MergedDictionaries> <!--TextBox默認樣式--> <Style x:Key="DefaultTextBox" TargetType="{x:Type TextBox}"> <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TextBox}"> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" CornerRadius="{TemplateBinding c:ControlAttachProperty.CornerRadius}" Background="White" BorderBrush="Transparent" BorderThickness="0"> <Grid x:Name="PART_InnerGrid"> <Grid.ColumnDefinitions> <ColumnDefinition Width="30"/> <ColumnDefinition /> <ColumnDefinition Width="40"/> </Grid.ColumnDefinitions> <!--用戶頭像區域--> <ContentControl x:Name="UserIcon" Grid.Column="0" Margin="5" Template="{TemplateBinding c:ControlAttachProperty.IconTemplate}" Focusable="False" /> <!--文本和水印--> <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2" VerticalAlignment="Stretch" Background="{x:Null}" /> <TextBlock x:Name="WaterMark" Grid.Column="1" VerticalAlignment="Center" Foreground="Silver" FontSize="18" Text="{TemplateBinding c:ControlAttachProperty.UserNameWaterMark}" Visibility="Collapsed" Padding="5,0,0,0" /> <!-- 刪除按鈕--> <ContentControl x:Name="DeleteIcon" Grid.Column="2" Width="15" Height="15" Margin="0,5,10,5" Visibility="Visible" VerticalAlignment="Center" HorizontalAlignment="Right" Template="{TemplateBinding c:ControlAttachProperty.AttachTemplate}" Focusable="False" /> </Grid> </Border> <ControlTemplate.Triggers> <!--當Text為空時,隱藏刪除按鈕--> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=Text}" Value=""> <Setter Property="Visibility" TargetName="DeleteIcon" Value="Collapsed" /> <Setter Property="Visibility" TargetName="WaterMark" Value="Visible" /> </DataTrigger> <!--是否顯示密碼樣式--> <Trigger Property="c:ControlAttachProperty.IsVisiblityPassword" Value="True"> <Setter Property="Height" Value="30"/> <Setter Property="Foreground" Value="Transparent"></Setter> <Setter Property="FontSize" Value="20"></Setter> <Setter Property="FontFamily" Value="Courier New"></Setter> <Setter Property="TextDecorations"> <Setter.Value> <TextDecorationCollection> <TextDecoration> <TextDecoration.Pen> <Pen Thickness="10" Brush="Black" EndLineCap="Round" StartLineCap="Round" DashCap="Round" > <Pen.DashStyle> <DashStyle Dashes="0.0,1.2" Offset="0.6"/> </Pen.DashStyle> </Pen> </TextDecoration.Pen> <TextDecoration.Location> <TextDecorationLocation>Strikethrough</TextDecorationLocation> </TextDecoration.Location> </TextDecoration> </TextDecorationCollection> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--TextBox包含附加屬性Icon,以及ClearText按鈕的樣式--> <Style x:Key="IconClearButtonTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource DefaultTextBox}"> <!--設置用戶頭像模板--> <Setter Property="c:ControlAttachProperty.IconTemplate"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Grid> <Image x:Name="Bg_HP" Source="{Binding Path=(c:ControlAttachProperty.UserIcon),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" Visibility="Visible"/> <Image x:Name="Bg_HP_Press" Source="{Binding Path=(c:ControlAttachProperty.UserIconPress),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" Visibility="Collapsed" /> </Grid> <ControlTemplate.Triggers> <DataTrigger Binding="{Binding IsFocused, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}" Value="true"> <Setter Property="Visibility" TargetName="Bg_HP" Value="Collapsed" /> <Setter Property="Visibility" TargetName="Bg_HP_Press" Value="Visible" /> </DataTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> <!--設置刪除按妞模板--> <Setter Property="c:ControlAttachProperty.AttachTemplate"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <c:DeleteButton ButtonBG="{Binding Path=(c:ControlAttachProperty.DeleteButtonBG),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" BorderBrush="Transparent" Style="{StaticResource DeleteButtonStyle}" BorderThickness="0" x:Name="CleanButton" c:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="c:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}" Focusable="false" /> <ControlTemplate.Triggers> <DataTrigger Binding="{Binding Text,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}" Value=""> <Setter Property="Visibility" TargetName="CleanButton" Value="Collapsed" /> </DataTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>