有些部分是从别人那拿过来的。
效果:
Style:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:ImageButtonTest01.Control"
xmlns:local="clr-namespace:ImageButtonTest01.Themes"
xmlns:converter="clr-namespace:ImageButtonTest01.Control.Converter">
<converter:ImageTextBoxMarginLeftConverter x:Key="ITBMLC"/>
<converter:PlaceholderFontSizeConverter x:Key="PHFSC"/>
<converter:ClearButtonEnableTester x:Key="CBET"/>
<SolidColorBrush x:Key="PasswordBox.Static.Foreground" Color="Black"/>
<SolidColorBrush x:Key="PasswordBox.Static.Background" Color="Transparent"/>
<SolidColorBrush x:Key="PasswordBox.Static.SelectionBrush" Color="#808F8787"/>
<SolidColorBrush x:Key="PasswordBox.Static.BorderBrush" Color="#FF909090"/>
<SolidColorBrush x:Key="PasswordBox.Focused.BorderBrush" Color="#FF007ACC"/>
<SolidColorBrush x:Key="PasswordBox.MouseOver.BorderBrush" Color="#FF1E1E1E"/>
<Style TargetType="{x:Type PasswordBox}" x:Key="DefaultPasswordBox">
<Setter Property="SelectionBrush" Value="{StaticResource PasswordBox.Static.SelectionBrush}"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="FontSize" Value="22"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="PasswordChar" Value="●"/>
<Setter Property="Background" Value="{StaticResource PasswordBox.Static.Background}"/>
<Setter Property="Foreground" Value="{StaticResource PasswordBox.Static.Foreground}"/>
<Setter Property="BorderBrush" Value="{StaticResource PasswordBox.Static.BorderBrush}"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="CaretBrush" Value="{StaticResource PasswordBox.Static.Foreground}"/>
<Setter Property="controls:PasswordBoxHelper.Attach" Value="True"/>
<Setter Property="controls:PasswordBoxHelper.Password" Value="{Binding Path=Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Border x:Name="PART_Root" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
CornerRadius="{TemplateBinding controls:ControlAttachProperty.CornerRadius}"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<Grid x:Name="PART_InnerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=(controls:ControlAttachProperty.CornerRadius).TopLeft, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ITBMLC}}"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--内容区域-->
<ScrollViewer x:Name="PART_ContentHost" Grid.Column="1" Margin="2"
BorderThickness="0" IsTabStop="False"
VerticalAlignment="Stretch" Background="{x:Null}"
VerticalContentAlignment="Center"/>
<TextBlock x:Name="PART_PlaceHolder" Grid.Column="1" Foreground="Black"
IsHitTestVisible="False" Margin="3,0,3,0"
HorizontalAlignment="Left" VerticalAlignment="Center"
SnapsToDevicePixels="True"
Visibility="Collapsed" Opacity="0.6"
TextAlignment="Center"
Text="{Binding Path=(controls:ControlAttachProperty.PlaceHolder), RelativeSource={RelativeSource TemplatedParent}}"
FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource PHFSC}}"/>
<!--附加内容区域-->
<!--<Border x:Name="PART_AttachContent" Grid.Column="2" Margin="1"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center"
Template="{TemplateBinding controls:ControlAttachProperty.AttachContent}"/>
</Border>-->
<controls:ImageButton x:Name="PART_ClearTextButton" IsTabStop="False" Grid.Column="2"
controls:ControlAttachProperty.IsClearButtonEnabled="True"
FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
Content="" FontSize="20" IsEnabled="True"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="controls:ControlAttachProperty.ClearTextCommand"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"
Style="{StaticResource ImageButtonTransparent}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--<DataTrigger Binding="{Binding Path=controls:PasswordBoxHelper.Password, RelativeSource={RelativeSource TemplatedParent}}" Value="">
<Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
</DataTrigger>-->
<Trigger Property="controls:PasswordBoxHelper.Password" Value="">
<Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
<Setter TargetName="PART_ClearTextButton" Property="IsEnabled" Value="False"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource PasswordBox.MouseOver.BorderBrush}"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource PasswordBox.Focused.BorderBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="PART_Root" Property="Opacity" Value="0.4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ClearButtonPasswordBox" TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource DefaultPasswordBox}">
<Setter Property="controls:ControlAttachProperty.AttachContent">
<Setter.Value>
<ControlTemplate>
<!--<controls:ImageButton x:Name="PART_ClearTextButton" IsTabStop="False"
controls:ControlAttachProperty.IsClearButtonEnabled="True"
FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
Content="" FontSize="20"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="controls:ControlAttachProperty.ClearTextCommand"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type PasswordBox}}}"
Style="{StaticResource ImageButtonTransparent}">
<controls:ImageButton.IsEnabled>
<MultiBinding Converter="{StaticResource CBET}">
<Binding Path="controls:PasswordBoxHelper.Password" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type PasswordBox}}"/>
</MultiBinding>
</controls:ImageButton.IsEnabled>
</controls:ImageButton>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
ControlAttachProperty.cs别人的(解决PasswordBox不能被继承

public static class ControlAttachProperty
{
static ControlAttachProperty()
{
/* ClearTextCommand */
ClearTextCommand = new RoutedUICommand();
ClearTextCommandBinding = new CommandBinding(ClearTextCommand);
ClearTextCommandBinding.Executed += ClearButtonClick;
}
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius),
typeof(ControlAttachProperty), new FrameworkPropertyMetadata(new CornerRadius(0,0,0,0)));
public static CornerRadius GetCornerRadius(DependencyObject d)
{
return (CornerRadius)d.GetValue(CornerRadiusProperty);
}
public static void SetCornerRadius(DependencyObject d, CornerRadius value)
{
d.SetValue(CornerRadiusProperty, value);
}
#region PlaceHolderProperty 占位符
public static readonly DependencyProperty PlaceHolderProperty = DependencyProperty.RegisterAttached("PlaceHolder", typeof(string),
typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));
public static string GetPlaceHolder(DependencyObject d)
{
return (string)d.GetValue(PlaceHolderProperty);
}
public static void SetPlaceHolder(DependencyObject obj, string value)
{
obj.SetValue(PlaceHolderProperty, value);
}
#endregion
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);
}
#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();
}
else if (tbox is PasswordBox)
{
((PasswordBox)tbox).Clear();
}
else if (tbox is ComboBox)
{
var cb = tbox as ComboBox;
cb.SelectedItem = null;
cb.Text = string.Empty;
}
else if (tbox is DatePicker)
{
var dp = tbox as DatePicker;
dp.SelectedDate = null;
dp.Text = string.Empty;
}
tbox.Focus();
}
#endregion
#region IsClearTextButtonBehaviorEnabledProperty 清除输入框Text值按钮行为开关(设为ture时才会绑定事件)
/// <summary>
/// 清除输入框Text值按钮行为开关
/// </summary>
public static readonly DependencyProperty IsClearButtonEnabledProperty = DependencyProperty.RegisterAttached("IsClearButtonEnabled", typeof(bool),
typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsClearButtonEnabledChanged));
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetIsClearButtonEnabled(DependencyObject d)
{
return (bool)d.GetValue(IsClearButtonEnabledProperty);
}
public static void SetIsClearButtonEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsClearButtonEnabledProperty, value);
}
/// <summary>
/// 绑定清除Text操作的按钮事件
/// </summary>
private static void IsClearButtonEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var button = d as ImageButton;
if ((null != button) && (e.OldValue != e.NewValue))
{
button.CommandBindings.Add(ClearTextCommandBinding);
}
}
#endregion
}
PasswordBoxHelper.cs别人的,主要解决PasswordBox的Password不是依赖属性问题
public static class PasswordBoxHelper
{
static PasswordBoxHelper()
{
}
public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool),
typeof(PasswordBoxHelper), new PropertyMetadata(false, AttachToPasswordBox));
public static bool GetAttach(DependencyObject dp)
{
return (bool)dp.GetValue(AttachProperty);
}
public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string),
typeof(PasswordBoxHelper), new FrameworkPropertyMetadata("", OnPasswordPropertyChanged));
public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}
private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxHelper));
private static bool GetIsUpdating(DependencyObject dp)
{
return (bool)dp.GetValue(IsUpdatingProperty);
}
private static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}
private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
passwordBox.PasswordChanged -= PasswordChanged;
if (!(bool)GetIsUpdating(passwordBox))
{
passwordBox.Password = (string)e.NewValue;
}
passwordBox.PasswordChanged += PasswordChanged;
}
private static void AttachToPasswordBox(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
if (null == passwordBox)
{
return;
}
if ((bool)e.OldValue)
{
passwordBox.PasswordChanged -= PasswordChanged;
}
if ((bool)e.NewValue)
{
passwordBox.PasswordChanged += PasswordChanged;
}
}
private static void PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
SetIsUpdating(passwordBox, true);
SetPassword(passwordBox, passwordBox.Password);
SetIsUpdating(passwordBox, false);
}
}
ImageTextBoxMarginLeftConverter.cs
public class ImageTextBoxMarginLeftConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
{
double v = (double)value;
if (null != parameter)
{
return v * double.Parse(parameter.ToString());
}
return v * 2.0 / 5.0;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
PlaceholderFontSizeConverter.cs
public class PlaceholderFontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double v = (double)value;
return (v * 3.5) / 5.0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
使用:
<StackPanel Grid.Row="3" Orientation="Horizontal">
<PasswordBox x:Name="usrPassword" Width="150" Height="40"
Style="{StaticResource ClearButtonPasswordBox}"
Margin="3"
control:ControlAttachProperty.PlaceHolder="请输入密码"/>
<PasswordBox x:Name="usrPassword1" Width="150" Height="40"
Style="{StaticResource ClearButtonPasswordBox}"
PasswordChar="*" Margin="3"
control:ControlAttachProperty.PlaceHolder="请输入密码"
IsEnabled="False"/>
<PasswordBox x:Name="usrPassword2" Width="150" Height="40"
Style="{StaticResource ClearButtonPasswordBox}"
PasswordChar="*" Margin="3"
control:ControlAttachProperty.PlaceHolder="请输入密码"
control:ControlAttachProperty.CornerRadius="10"
IsEnabled="True"/>
</StackPanel>