using System; using System.Collections.ObjectModel; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace Muchinfo.WPF.Controls.CaptchaSpace { public class CaptchaControl : ItemsControl { static CaptchaControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CaptchaControl), new FrameworkPropertyMetadata(typeof(CaptchaControl))); } public string QuantityCharacters { get { return (string)GetValue(QuantityCharactersProperty); } set { SetValue(QuantityCharactersProperty, value); } } // Using a DependencyProperty as the backing store for QuantityCharacters. This enables animation, styling, binding, etc... public static readonly DependencyProperty QuantityCharactersProperty = DependencyProperty.Register("QuantityCharacters", typeof(string), typeof(CaptchaControl), new PropertyMetadata("", OnQuantityCharactersChanged)); public Color BackgroundColorStart { get { return (Color)GetValue(BackgroundColorStartProperty); } set { SetValue(BackgroundColorStartProperty, value); } } // Using a DependencyProperty as the backing store for BackgroundColorStart. This enables animation, styling, binding, etc... public static readonly DependencyProperty BackgroundColorStartProperty = DependencyProperty.Register("BackgroundColorStart", typeof(Color), typeof(CaptchaControl), new PropertyMetadata(Colors.Coral, OnColorStartChanged)); public Color BackgroundColorEnd { get { return (Color)GetValue(BackgroundColorEndProperty); } set { SetValue(BackgroundColorEndProperty, value); } } // Using a DependencyProperty as the backing store for BackgroundColorEnd. This enables animation, styling, binding, etc... public static readonly DependencyProperty BackgroundColorEndProperty = DependencyProperty.Register("BackgroundColorEnd", typeof(Color), typeof(CaptchaControl), new PropertyMetadata(Colors.YellowGreen, OnColorEndChanged)); public Color ForegroundColorStart { get { return (Color)GetValue(ForegroundColorStartProperty); } set { SetValue(ForegroundColorStartProperty, value); } } // Using a DependencyProperty as the backing store for ForegroundColorStart. This enables animation, styling, binding, etc... public static readonly DependencyProperty ForegroundColorStartProperty = DependencyProperty.Register("ForegroundColorStart", typeof(Color), typeof(CaptchaControl), new PropertyMetadata(Colors.Turquoise, OnForeColorStartChanged)); public Color ForegroundColorEnd { get { return (Color)GetValue(ForegroundColorEndProperty); } set { SetValue(ForegroundColorEndProperty, value); } } // Using a DependencyProperty as the backing store for ForegroundColorEnd. This enables animation, styling, binding, etc... public static readonly DependencyProperty ForegroundColorEndProperty = DependencyProperty.Register("ForegroundColorEnd", typeof(Color), typeof(CaptchaControl), new PropertyMetadata(Colors.Lavender, OnForeColorEndChanged)); public int SpaceBetweenLetters { get { return (int)GetValue(SpaceBetweenLettersProperty); } set { SetValue(SpaceBetweenLettersProperty, value); } } // Using a DependencyProperty as the backing store for SpaceBetweenLetters. This enables animation, styling, binding, etc... public static readonly DependencyProperty SpaceBetweenLettersProperty = DependencyProperty.Register("SpaceBetweenLetters", typeof(int), typeof(CaptchaControl), new PropertyMetadata(10, OnSpaceBetweenLettersChanged)); public bool IsUniqueForegroundColor { get { return (bool)GetValue(IsUniqueForegroundColorProperty); } set { SetValue(IsUniqueForegroundColorProperty, value); } } // Using a DependencyProperty as the backing store for IsUniqueForegroundColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsUniqueForegroundColorProperty = DependencyProperty.Register("IsUniqueForegroundColor", typeof(bool), typeof(CaptchaControl), new PropertyMetadata(true, OnIsUniqueForegroundColorChanged)); public bool IsUniqueBackgroundColor { get { return (bool)GetValue(IsUniqueBackgroundColorProperty); } set { SetValue(IsUniqueBackgroundColorProperty, value); } } // Using a DependencyProperty as the backing store for IsUniqueBackgroundColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsUniqueBackgroundColorProperty = DependencyProperty.Register("IsUniqueBackgroundColor", typeof(bool), typeof(CaptchaControl), new PropertyMetadata(true, OnIsUniqueBackgroundColorChanged)); public string CaptchaText { get { return (string)GetValue(CaptchaTextProperty); } set { SetValue(CaptchaTextProperty, value); } } // Using a DependencyProperty as the backing store for CaptchaText. This enables animation, styling, binding, etc... public static readonly DependencyProperty CaptchaTextProperty = DependencyProperty.Register("CaptchaText", typeof(string), typeof(CaptchaControl), new PropertyMetadata("", OnCaptchaTextChanged)); #region Global Variables private readonly Random random; private readonly Color color = new Color(); private static readonly char[] CharArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123467890".ToCharArray(); #endregion private ObservableCollection captchaLetters = new ObservableCollection(); public ObservableCollection CaptchaLetters { get { return captchaLetters; } set { captchaLetters = value; } } public CaptchaControl() { random = new Random(); } private static void OnCaptchaTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captchacontrol = d as CaptchaControl; captchacontrol.SetBackgroundGradient(); captchacontrol.SetForegroundGradient(); captchacontrol.SetBackgroundGradient(); } private static void OnIsUniqueBackgroundColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captchacontrol = d as CaptchaControl; captchacontrol.SetBackgroundGradient(); } private static void OnSpaceBetweenLettersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captchacontrol = d as CaptchaControl; //foreach (var captcha in captchacontrol.CaptchaLetters) //{ // captcha.SpaceBetweenLetters = captchacontrol.SpaceBetweenLetters; //} } private static void OnIsUniqueForegroundColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captcha = d as CaptchaControl; captcha.SetForegroundGradient(); } private static void OnForeColorEndChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captcha = d as CaptchaControl; captcha.SetForegroundGradient(); } private static void OnForeColorStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CaptchaControl captcha = d as CaptchaControl; captcha.SetForegroundGradient(); } private static void OnQuantityCharactersChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { //CaptchaControl captcha = d as CaptchaControl; //var quantity = 8; //if (int.TryParse(captcha.QuantityCharacters, out quantity)) //{ // captcha.InitializeCaptcha(quantity); //} //else //{ // throw new Exception("You have to set QuantityCharacter property"); //} } private static void OnColorStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { CaptchaControl captcha = d as CaptchaControl; captcha.SetBackgroundGradient(); } private static void OnColorEndChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { CaptchaControl captcha = d as CaptchaControl; captcha.SetBackgroundGradient(); } private void InitializeCaptcha(int quantityCharacters) { CaptchaLetters = new ObservableCollection(); var captcha = new char[quantityCharacters]; for (var x = 0; x < captcha.Length; x++) { captcha[x] = CharArray[random.Next(CharArray.Length)]; var c = new Captcha { Letter = captcha[x].ToString(), FontSize = (int)this.FontSize, SpaceBetweenLetters = this.SpaceBetweenLetters }; SetTransformGroup(c); CaptchaLetters.Add(c); } var builder = new StringBuilder(); foreach (var letter in CaptchaLetters) { builder.Append(letter.Letter); } CaptchaText = builder.ToString(); this.ItemsSource = CaptchaLetters; } public override void OnApplyTemplate() { var quantity = 8; if (int.TryParse(QuantityCharacters, out quantity)) { InitializeCaptcha(quantity); } else { throw new Exception("You have to set QuantityCharacter property"); } base.OnApplyTemplate(); } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { ReflushCaptchaText(); base.OnMouseLeftButtonDown(e); } /// /// 刷新验证码 /// public void ReflushCaptchaText() { var quantity = 8; if (int.TryParse(QuantityCharacters, out quantity)) { InitializeCaptcha(quantity); } else { throw new Exception("You have to set QuantityCharacter property"); } } protected override void OnMouseEnter(MouseEventArgs e) { // e.MouseDevice.SetCursor(Cursors.Hand); Mouse.SetCursor(Cursors.Hand); base.OnMouseEnter(e); } protected override void OnMouseLeave(MouseEventArgs e) { Mouse.SetCursor(Cursors.Arrow); base.OnMouseLeave(e); } private void SetForegroundGradient() { if (IsUniqueForegroundColor) { foreach (var captcha in CaptchaLetters) { captcha.ForegroundGradient = this.SetForegroundGradientSameColor(); } } else { foreach (var captcha in CaptchaLetters) { captcha.ForegroundGradient = this.SetForegroundGradientRandomColor(); } } } private LinearGradientBrush SetForegroundGradientRandomColor() { var gradient = new LinearGradientBrush(); gradient.StartPoint = new Point(0.5f, 1); gradient.EndPoint = new Point(0.8f, 0); gradient.GradientStops.Add(new GradientStop() { Color = Color.FromArgb((byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255)), Offset = 3 }); gradient.GradientStops.Add(new GradientStop() { Color = Color.FromArgb((byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255)) }); return gradient; } private LinearGradientBrush SetForegroundGradientSameColor() { var gradient = new LinearGradientBrush(); gradient.StartPoint = new Point(0.5f, 1); gradient.EndPoint = new Point(0.8f, 0); gradient.GradientStops.Add(new GradientStop() { Color = ForegroundColorStart, Offset = 3 }); gradient.GradientStops.Add(new GradientStop() { Color = ForegroundColorEnd }); return gradient; } private void SetBackgroundGradient() { var gradient = new LinearGradientBrush(); gradient.StartPoint = new Point(0.5f, 0); gradient.EndPoint = new Point(0.5f, 1); if (IsUniqueBackgroundColor) { gradient.GradientStops.Add(new GradientStop() { Color = BackgroundColorStart, Offset = 3 }); gradient.GradientStops.Add(new GradientStop() { Color = BackgroundColorStart }); } else { gradient.GradientStops.Add(new GradientStop() { Color = BackgroundColorStart, Offset = 3 }); gradient.GradientStops.Add(new GradientStop() { Color = BackgroundColorEnd }); } this.Background = gradient; } private void SetTransformGroup(Captcha captcha) { this.SetRotate(ref captcha); this.SetScale(ref captcha); this.SetSkew(ref captcha); this.SetTranslate(ref captcha); this.SetFontColor(ref captcha); } private void SetRotate(ref Captcha captcha) { captcha.Rotate.Angle = random.Next(-10, 10); captcha.Rotate.CenterX = random.Next(1, 3); captcha.Rotate.CenterY = random.Next(1, 3); captcha.TransformGroup.Children.Add(captcha.Rotate); } private void SetScale(ref Captcha captcha) { captcha.Scale.ScaleX = random.Next(2, 3); captcha.Scale.ScaleY = random.Next(1, 2); //captcha.Scale.CenterX = random.Next(1,5)/10.0; //captcha.Scale.CenterY = random.Next(1, 5)/10.0; captcha.TransformGroup.Children.Add(captcha.Scale); } private void SetSkew(ref Captcha captcha) { captcha.Skew.AngleX = random.Next(-10, 10); captcha.Skew.AngleY = random.Next(-10, 10); captcha.Skew.CenterX = random.Next(1, 3); captcha.Skew.CenterY = random.Next(1, 3); captcha.TransformGroup.Children.Add(captcha.Skew); } private void SetTranslate(ref Captcha captcha) { captcha.Translate.X = random.Next(2, 4); captcha.Translate.Y = random.Next(1, 4); captcha.TransformGroup.Children.Add(captcha.Translate); } private void SetFontColor(ref Captcha captcha) { captcha.FontColor = Color.FromArgb(255, 0, 0, (byte)random.Next(0, 20)); } } }