WPF 使用附加属性增加控件属性
使用附加属性增加控件属性,使得这个附加属性在使用的时候没有局限性,可以在任何的控件中使用它来增加所需要的属性,使得控件的属性使用起来非常灵活
一、自定义附加属性
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>