效果
实现
说明:
①账号、密码、验证码的每一行都是一个用户控件(UserControl);
②水印”账号“、”密码“、”验证码“是直接写在用户控件中最底层的label,在文本框的焦点获取和丢失事件中操作水印的可见性。
用户控件:账号
1.准备图片
2.新建用户控件”UserTextBox.xaml“
3.调整位置和大小,CornerRadius是调整文本框的圆角👇
<Label x:Name="labelUser" Content="账号" HorizontalAlignment="Left" Margin="30,0,0,0" VerticalAlignment="Center" Foreground="#FFACAAAA" />
<Image HorizontalAlignment="Left" Height="20" Margin="0,0,0,0" VerticalAlignment="Center" Width="20" Source="/Image/user.png"/>
<TextBox x:Name="textBoxUser" HorizontalAlignment="Left" Margin="30,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" Width="170" Height="25" FontSize="13" Background="{x:Null}" Foreground="Black" VerticalContentAlignment="Center" GotFocus="textBoxUser_GotFocus" LostFocus="textBoxUser_LostFocus">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="5" />
</Style>
</TextBox.Resources>
</TextBox>
4.逻辑编写”UserTextBox.xaml.cs“
/// <summary>
/// 判断文本框是否有输入
/// </summary>
private bool bHadInput = false;
/// <summary>
/// 文本框获取焦点
/// </summary>
private void textBoxUser_GotFocus(object sender, RoutedEventArgs e)
{
//如果文本框没有输入,则清空文本框(即清除label“账号”)
if (!bHadInput)
{
labelUser.Visibility = Visibility.Collapsed;
}
}
/// <summary>
/// 文本框失去焦点
/// </summary>
private void textBoxUser_LostFocus(object sender, RoutedEventArgs e)
{
//如果文本框为空,则显示默认的内容(即灰色的label“账号”),同时将bHadInput置为false;否则,将bHadInput置为true
if (textBoxUser.Text.Equals(string.Empty))
{
labelUser.Visibility = Visibility.Visible;
bHadInput = false;
}
else
{
bHadInput = true;
}
}
用户控件:密码
1.准备图片
2.新建用户控件”PasswordTextBox.xaml“
3.调整位置和大小,CornerRadius是调整文本框的圆角👇
<Label x:Name="labelPassword" Content="密码" HorizontalAlignment="Left" Margin="30,0,0,0" VerticalAlignment="Center" Foreground="#FFACAAAA" />
<Image HorizontalAlignment="Left" Height="20" Margin="0,0,0,0" VerticalAlignment="Center" Width="20" Source="/Image/password.png"/>
<PasswordBox x:Name="passwordBox" HorizontalAlignment="Left" Margin="30,0,0,0" VerticalAlignment="Center" VerticalContentAlignment="Center" Background="{x:Null}" Width="170" Height="25" FontSize="13" GotFocus="passwordBox_GotFocus" LostFocus="passwordBox_LostFocus">
<PasswordBox.Resources>
<Style TargetType="{x:Type PasswordBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<ScrollViewer x:Name="PART_ContentHost" Focusable="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</PasswordBox.Resources>
</PasswordBox>
4.逻辑编写”PasswordTextBox.xaml.cs“
/// <summary>
/// 判断文本框是否有输入
/// </summary>
private bool bHadInput = false;
/// <summary>
/// 文本框获取焦点
/// </summary>
private void passwordBox_GotFocus(object sender, RoutedEventArgs e)
{
//如果文本框没有输入,则清空文本框(即清除label“密码”)
if (!bHadInput)
{
labelPassword.Visibility = Visibility.Collapsed;
}
}
/// <summary>
/// 文本框失去焦点
/// </summary>
private void passwordBox_LostFocus(object sender, RoutedEventArgs e)
{
//如果文本框为空,则显示默认的内容(即label“密码”),同时将bHadInput置为false;否则,将bHadInput置为true
if (passwordBox.Password.Equals(string.Empty))
{
labelPassword.Visibility = Visibility.Visible;
bHadInput = false;
}
else
{
bHadInput = true;
}
}
用户控件:验证码
1新建用户控件”ValidcodeTextBox.xaml“,调整位置和大小👇
<Label x:Name="labelValidcode" Content="验证码" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Center" Foreground="#FFACAAAA" />
<TextBox x:Name="textBoxValidcode" HorizontalAlignment="Left" Margin="0,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" Width="90" Height="25" FontSize="13" Background="{x:Null}" VerticalContentAlignment="Center" GotFocus="textBoxValidcode_GotFocus" LostFocus="textBoxValidcode_LostFocus">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="5" />
</Style>
</TextBox.Resources>
</TextBox>
<Image x:Name="imgValidcode" Margin="100,0,0,0" Height="25" Loaded="imgValidcode_Loaded" Stretch="UniformToFill" StretchDirection="DownOnly" MouseLeftButtonUp="imgValidcode_MouseLeftButtonUp" />
2.新建类ValidCode.cs,比较重要的再此段代码的最下面的方法”CreateCheckCodeImage()“👇,可以在此方法中修改字体样式等等
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace HMIS.PublicClass
{
public class ValidCode
{
#region Private Fields
private const double PI = 3.1415926535897932384626433832795;
private const double PI2 = 6.283185307179586476925286766559;
//private readonly int _wordsLen = 4;
private int _len;
private CodeType _codetype;
private readonly Single _jianju = (float)20.0;
private readonly Single _height = (float)25.0;
private string _checkCode;
#endregion
#region Public Property
public string CheckCode
{
get
{
return _checkCode;
}
}
#endregion
#region Constructors
public ValidCode(int len, CodeType ctype)
{
this._len = len;
this._codetype = ctype;
}
#endregion
#region Public Field
public enum CodeType { Words, Numbers, Characters, Alphas }
#endregion
#region Private Methods
private string GenerateNumbers()
{
string strOut = "";
System.Random random = new Random();
for (int i = 0; i < _len; i++)
{
string num = Convert.ToString(random.Next(10000) % 10);
strOut += num;
}
return strOut.Trim();
}
private string GenerateCharacters()
{
string strOut = "";
System.Random random = new Random();
for (int i = 0; i < _len; i++)
{
string num = Convert.ToString((char)(65 + random.Next(10000) % 26));
strOut += num;
}
return strOut.Trim();
}
private string GenerateAlphas()
{
string strOut = "";
string num = "";
System.Random random = new Random();
for (int i = 0; i < _len; i++)
{
if (random.Next(500) % 2 == 0)
{
num = Convert.ToString(random.Next(10000) % 10);
}
else
{
num = Convert.ToString((char)(65 + random.Next(10000) % 26));
}
strOut += num;
}
return strOut.Trim();
}
private System.Drawing.Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
{
System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
// 将位图背景填充为白色
System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
graph.FillRectangle(new SolidBrush(System.Drawing.Color.Transparent), 0, 0, destBmp.Width, destBmp.Height);
graph.Dispose();
double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;
for (int i = 0; i < destBmp.Width; i++)
{
for (int j = 0; j < destBmp.Height; j++)
{
double dx = 0;
dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;
dx += dPhase;
double dy = Math.Sin(dx);
// 取得当前点的颜色
int nOldX = 0, nOldY = 0;
nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
nOldY = bXDir ? j : j + (int)(dy * dMultValue);
System.Drawing.Color color = srcBmp.GetPixel(i, j);
if (nOldX >= 0 && nOldX < destBmp.Width && nOldY >= 0 && nOldY < destBmp.Height)
{
destBmp.SetPixel(nOldX, nOldY, color);
}
}
}
return destBmp;
}
#endregion
#region Public Methods
public Bitmap CreateCheckCodeImage()
{
string checkCode;
switch (_codetype)
{
case CodeType.Alphas:
checkCode = GenerateAlphas();
break;
case CodeType.Numbers:
checkCode = GenerateNumbers();
break;
case CodeType.Characters:
checkCode = GenerateCharacters();
break;
default:
checkCode = GenerateAlphas();
break;
}
this._checkCode = checkCode;
MemoryStream ms = null;
if (checkCode == null || checkCode.Trim() == String.Empty)
return null;
Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * _jianju)), (int)_height);
Graphics g = Graphics.FromImage(image);
try
{
Random random = new Random();
g.Clear(System.Drawing.Color.White);
// 画图片的背景噪音线
for (int i = 0; i < 18; i++)
{
int x1 = random.Next(image.Width);
int x2 = random.Next(image.Width);
int y1 = random.Next(image.Height);
int y2 = random.Next(image.Height);
g.DrawLine(new System.Drawing.Pen(Color.FromArgb(random.Next()), 1), x1, y1, x2, y2);
}
Font font = new System.Drawing.Font("Times New Roman", 8, System.Drawing.FontStyle.Bold);//字体调整
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
if (_codetype != CodeType.Words)
{
for (int i = 0; i < checkCode.Length; i++)
{
g.DrawString(checkCode.Substring(i, 1), font, brush, 2 + i * _jianju, 4);
}
}
else
{
g.DrawString(checkCode, font, brush, 2, 2);
}
// 画图片的前景噪音点
for (int i = 0; i < 150; i++)
{
int x = random.Next(image.Width);
int y = random.Next(image.Height);
image.SetPixel(x, y, Color.FromArgb(random.Next()));
}
画图片的波形滤镜效果
//if (_codetype != CodeType.Words)
//{
// image = TwistImage(image, true, 3, 1);
//}
// 画图片的边框线
g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
ms = new System.IO.MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
}
finally
{
g.Dispose();
//image.Dispose();
}
return image;
}
#endregion
}
}
3.在ValidcodeTextBox.xaml.cs类中,创建方法BitmapToImageSource,用来将Bitmap转为ImageSource,用于Image.Source👇
/// <summary>
/// Bitmap转ImageSource
/// </summary>
/// <param name="image">提供的Bitmap</param>
/// <returns>返回的ImageSource</returns>
public ImageSource BitmapToImageSource(Bitmap image)
{
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
image.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
return bitmapSource;
}
4.创建刷新验证码的方法,在需要刷新验证码的地方调用此方法即可👇,比如在窗体刚加载时或者Image的点击事件中(即点击切换验证码);5代表5位验证码,具体的使用可参考C#登录界面验证码
public static ValidCode validCode = new ValidCode(5, ValidCode.CodeType.Alphas);//实例化这个对象
private void RefreshVaildcode()
{
imgValidcode.Source = BitmapToImageSource(validCode.CreateCheckCodeImage());//刷新验证码
}
5.编写水印显示与否的相关内容
/// <summary>
/// 判断文本框是否有输入
/// </summary>
private bool bHadInput = false;
/// <summary>
/// 文本框获取焦点
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBoxValidcode_GotFocus(object sender, RoutedEventArgs e)
{
//如果文本框没有输入,则清空文本框(即清除label“验证码”)
if (!bHadInput)
{
labelValidcode.Visibility = Visibility.Collapsed;
}
}
/// <summary>
/// 文本框失去焦点
/// </summary>
private void textBoxValidcode_LostFocus(object sender, RoutedEventArgs e)
{
//如果文本框为空,则显示默认的内容(即label“验证码”),同时将bHadInput置为false;否则,将bHadInput置为true
if (textBoxValidcode.Text.Equals(string.Empty))
{
labelValidcode.Visibility = Visibility.Visible;
bHadInput = false;
}
else
{
bHadInput = true;
}
}
在主界面中引用用户控件
xmlns:userControlItems="clr-namespace:HMIS.UserControlItems"
<userControlItems:UserTextBox x:Name="userTextBox" Margin="0,20,0,150" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" />
<userControlItems:PasswordTextBox x:Name="passwordTextBox" Margin="0,70,0,100" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" />
<userControlItems:ValidcodeTextBox x:Name="validcodeTextBox" Margin="0,120,0,50" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" />