带水印、带密码的输入框,示例:
public class WaterTextBox : TextBox
{
static WaterTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WaterTextBox), new FrameworkPropertyMetadata(typeof(WaterTextBox)));
}
/// <summary>
/// 水印文字
/// </summary>
public string WaterText
{
get { return GetValue(WaterTextProperty).ToString(); }
set { SetValue(WaterTextProperty, value); }
}
public static DependencyProperty WaterTextProperty =
DependencyProperty.Register("WaterText", typeof(string), typeof(WaterTextBox));
/// <summary>
/// 水印前景色
/// </summary>
public Brush WaterTextForeground
{
get { return (Brush)GetValue(WaterTextForegroundProperty); }
set { SetValue(WaterTextForegroundProperty, value); }
}
public static readonly DependencyProperty WaterTextForegroundProperty =
DependencyProperty.Register("WaterTextForeground", typeof(Brush), typeof(WaterTextBox),new PropertyMetadata(Brushes.Gainsboro));
/// <summary>
/// 边框角度
/// </summary>
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(WaterTextBox));
/// <summary>
/// 密码符号
/// </summary>
public char PasswordChar
{
get { return (char)GetValue(PasswordCharProperty); }
set { SetValue(PasswordCharProperty, value); }
}
// Using a DependencyProperty as the backing store for PasswardChar. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PasswordCharProperty =
DependencyProperty.Register("PasswardChar", typeof(char), typeof(WaterTextBox), new PropertyMetadata('*'));
/// <summary>
/// 密码
/// </summary>
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
// Using a DependencyProperty as the backing store for Password. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(string), typeof(WaterTextBox),new PropertyMetadata(string.Empty));
/// <summary>
/// 是否是密码框
/// </summary>
public bool IsPasswordBox
{
get { return (bool)GetValue(IsPasswordBoxProperty); }
set { SetValue(IsPasswordBoxProperty, value); }
}
// Using a DependencyProperty as the backing store for IsPasswordBox. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsPasswordBoxProperty =
DependencyProperty.Register("IsPasswordBox", typeof(bool), typeof(WaterTextBox), new PropertyMetadata(false,
(d, e) =>
{
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
var sender = d as WaterTextBox;
if (sender != null && oldValue != newValue)
{
if (newValue)
{
sender.TextChanged += Password_TextChanged;
InputMethod.SetIsInputMethodEnabled(sender, false);
}
else
{
sender.TextChanged -= Password_TextChanged;
InputMethod.SetIsInputMethodEnabled(sender, true);
sender.Text = sender.Password;
}
}
}));
private static void Password_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as WaterTextBox;
if (!string.IsNullOrWhiteSpace(textBox.Text))
{
if (textBox.Text == textBox.WaterText) return;
Action<WaterTextBox, int, int> setNewValue = (tb, newC, newS) =>
{
var newText = string.Empty;
for (int i = 0; i < newC; i++)
{
newText += textBox.PasswordChar;
}
tb.Text = newText;
tb.SelectionStart = newS;
};
var lastInput = textBox.Password;
var selectionStart = textBox.SelectionStart;
var newChars = textBox.Text.ToList();
var newChar = newChars.Find(i => i != textBox.PasswordChar);
if (newChar != 0)//新输入字符
{
var newCharIndex = newChars.IndexOf(newChar);
if (newCharIndex > 0)
{
textBox.Password = lastInput.Insert(newCharIndex, newChar.ToString());
}
else
{
textBox.Password = newChar.ToString();
}
setNewValue(textBox, newChars.Count, selectionStart);
}
else//没有新输入字符串或新输入字符和密码字符一样
{
if (lastInput.Length < newChars.Count)//输入了新字符且和密码字符一样
{
textBox.Password = lastInput.Insert(textBox.SelectionStart - 1, textBox.PasswordChar.ToString());
setNewValue(textBox, newChars.Count, selectionStart);
}
else if (lastInput.Length > newChars.Count)//没有输入字符且删除了一个字符
{
if (lastInput.Length == textBox.SelectionStart)//删除了最后一个字节
{
textBox.Password = lastInput.Remove(lastInput.Length - 1, 1);
}
else//删除了非最后一个字节
{
textBox.Password = lastInput.Remove(textBox.SelectionStart, 1);
}
setNewValue(textBox, newChars.Count, selectionStart);
}
}
}
else
{
textBox.Password = string.Empty;
}
}
}
style:
<Style TargetType="local:WaterTextBox">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Cursor" Value="IBeam"/>
<Setter Property="Padding" Value="4 0 0 0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:WaterTextBox">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding BorderCornerRadius}"
SnapsToDevicePixels="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBlock x:Name="txtRemark" Text="{TemplateBinding WaterText}"
Foreground="{TemplateBinding WaterTextForeground}" VerticalAlignment="Center"
Margin="8 0 0 0"
Visibility="Collapsed"/> <!--默认水印文字隐藏-->
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Text" Value="">
<!--使用触发器来控制水印的隐藏显示:当文本框没有字符时显示水印文字-->
<Setter Property="Visibility" Value="Visible" TargetName="txtRemark"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>