using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace CustomUI
{
public enum EnumIpBoxType
{
///
/// IP地址或者网关
///
IpAddress,
///
/// 子网掩码
///
SubnetMask,
}
public class IpTextBox : Control
{
///
/// IP正则
///
private const string ipRegex = @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$";
private const string ZeroTo255Tip = "{0} 不是有效项。请指定一个介于 0 和 255 间的值";
#region private fields
private TextBox PART_BOX1;
private TextBox PART_BOX2;
private TextBox PART_BOX3;
private TextBox PART_BOX4;
#endregion
#region DependencyProperty
#region Type
///
/// 获取或者设置文本框类型
///
public EnumIpBoxType Type
{
get { return (EnumIpBoxType)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(EnumIpBoxType), typeof(IpTextBox), new PropertyMetadata(EnumIpBoxType.IpAddress));
#endregion
#region IsHasError
///
/// 获取或者设置是否输入了不合法的数字
///
public bool IsHasError
{
get { return (bool)GetValue(IsHasErrorProperty); }
private set { SetValue(IsHasErrorProperty, value); }
}
public static readonly DependencyProperty IsHasErrorProperty =
DependencyProperty.Register("IsHasError", typeof(bool), typeof(IpTextBox), new PropertyMetadata(false));
#endregion
#region ErrorContent
///
/// 获取或者设置非法输入时的提示内容
///
public string ErrorContent
{
get { return (string)GetValue(ErrorContentProperty); }
private set { SetValue(ErrorContentProperty, value); }
}
public static readonly DependencyProperty ErrorContentProperty =
DependencyProperty.Register("ErrorContent", typeof(string), typeof(IpTextBox), new PropertyMetadata(string.Empty));
#endregion
#region IsKeyboardFocused
public new bool IsKeyboardFocused
{
get { return (bool)GetValue(IsKeyboardFocusedProperty); }
private set { SetValue(IsKeyboardFocusedProperty, value); }
}
public new static readonly DependencyProperty IsKeyboardFocusedProperty =
DependencyProperty.Register("IsKeyboardFocused", typeof(bool), typeof(IpTextBox), new PropertyMetadata(false));
#endregion
#region Text
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(IpTextBox), new PropertyMetadata(string.Empty));
#endregion
#endregion
#region Constructors
static IpTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IpTextBox), new FrameworkPropertyMetadata(typeof(IpTextBox)));
}
#endregion
#region Override
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_BOX1 = this.GetTemplateChild("PART_BOX1") as TextBox;
this.PART_BOX2 = this.GetTemplateChild("PART_BOX2") as TextBox;
this.PART_BOX3 = this.GetTemplateChild("PART_BOX3") as TextBox;
this.PART_BOX4 = this.GetTemplateChild("PART_BOX4") as TextBox;
if(this.PART_BOX1 != null)
{
this.PART_BOX1.PreviewTextInput += PART_BOX1_PreviewTextInput;
this.PART_BOX1.TextChanged += PART_BOX1_TextChanged;
this.PART_BOX1.GotFocus += (o, e) => { this.IsKeyboardFocused = true; };
this.PART_BOX1.LostFocus += (o, e) => { this.IsKeyboardFocused = false; };
this.PART_BOX1.PreviewKeyDown += PART_BOX1_PreviewKeyDown;
}
if(this.PART_BOX2 != null)
{
this.PART_BOX2.PreviewTextInput += PART_BOX2_PreviewTextInput;
this.PART_BOX2.TextChanged += PART_BOX2_TextChanged;
this.PART_BOX2.GotFocus += (o, e) => { this.IsKeyboardFocused = true; };
this.PART_BOX2.LostFocus += (o, e) => { this.IsKeyboardFocused = false; };
this.PART_BOX2.PreviewKeyDown += PART_BOX1_PreviewKeyDown;
}
if(this.PART_BOX3 != null)
{
this.PART_BOX3.PreviewTextInput += PART_BOX3_PreviewTextInput;
this.PART_BOX3.TextChanged += PART_BOX3_TextChanged;
this.PART_BOX3.GotFocus += (o, e) => { this.IsKeyboardFocused = true; };
this.PART_BOX3.LostFocus += (o, e) => { this.IsKeyboardFocused = false; };
this.PART_BOX3.PreviewKeyDown += PART_BOX1_PreviewKeyDown;
}
if(this.PART_BOX4 != null)
{
this.PART_BOX4.PreviewTextInput += PART_BOX4_PreviewTextInput;
this.PART_BOX4.GotFocus += (o, e) => { this.IsKeyboardFocused = true; };
this.PART_BOX4.LostFocus += (o, e) => { this.IsKeyboardFocused = false; };
this.PART_BOX4.PreviewKeyDown += PART_BOX1_PreviewKeyDown;
}
}
void PART_BOX1_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Control) && e.Key == Key.V)
{
IDataObject data = Clipboard.GetDataObject();
if(data.GetDataPresent(DataFormats.Text))
{
string text = (string)data.GetData(DataFormats.UnicodeText);
Regex regex = new Regex(ipRegex);
if(regex.IsMatch(text))
{
string[] strs = text.Split(new char[] { '.' });
//因为已经判断过是正确的IP地址,因此不用判断索引是否越界
this.PART_BOX1.Text = strs[0];
this.PART_BOX2.Text = strs[1];
this.PART_BOX3.Text = strs[2];
this.PART_BOX4.Text = strs[3];
this.PART_BOX1.Focus();
this.PART_BOX1.SelectionStart = 0;
}
else
{
this.IsHasError = true;
this.ErrorContent = "您正在尝试将格式错误的 IP 地址粘贴到该字段";
this.PART_BOX1.Text = string.Empty;
this.PART_BOX2.Text = string.Empty;
this.PART_BOX3.Text = string.Empty;
this.PART_BOX4.Text = string.Empty;
}
}
e.Handled = true;
}
}
#endregion
#region private function
///
/// 检查输入的字符是否为数字
///
///
///
private bool IsNumber(string input)
{
Regex regex = new Regex("^[0-9]*$");
return regex.IsMatch(input);
}
///
/// 检查输入的数字是否在某个范围内
///
///
///
///
///
private bool IsNumberRange(int number, int start, int end)
{
return number >= start && number <= end;
}
///
/// 检查输入的文本是否符合IP地址格式
///
///
///
///
private bool CheckNumberIsLegal(string text1, string text2)
{
if (!this.IsNumber(text2)) return true;
int text = Convert.ToInt32(text1);
return !this.IsNumberRange(text, 0, 255);
}
#endregion
#region Event Implement Function
void PART_BOX1_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
string input = this.PART_BOX1.Text + e.Text;
if (!string.IsNullOrWhiteSpace(input) && ".".Equals(e.Text))
{
e.Handled = true;
this.PART_BOX2.Focus();
}
else
{
//输入的不是数字,则直接返回
if (!this.IsNumber(e.Text))
{
e.Handled = true;
return;
}
if(!string.IsNullOrWhiteSpace(this.PART_BOX1.SelectedText))
{
input = this.PART_BOX1.Text.Remove(this.PART_BOX1.SelectionStart, this.PART_BOX1.SelectionLength) + e.Text;
}
int text = Convert.ToInt32(input);
switch (this.Type)
{
case EnumIpBoxType.IpAddress:
if (!this.IsNumberRange(text, 0, 223))
{
e.Handled = true;
this.IsHasError = true;
this.ErrorContent = string.Format("{0} 不是有效项。请指定一个介于 1 和 223 间的值", input);
this.PART_BOX1.Text = "223";
}
else
{
IsHasError = false;
}
break;
case EnumIpBoxType.SubnetMask:
if (!this.IsNumberRange(text, 0, 255))
{
e.Handled = true;
this.IsHasError = true;
this.ErrorContent = string.Format(ZeroTo255Tip, input);
this.PART_BOX1.Text = "255";
}
else
{
IsHasError = false;
}
break;
}
}
}
void PART_BOX2_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
string input = this.PART_BOX2.Text + e.Text;
if (!string.IsNullOrWhiteSpace(this.PART_BOX2.SelectedText))
{
input = this.PART_BOX2.Text.Remove(this.PART_BOX2.SelectionStart, this.PART_BOX2.SelectionLength) + e.Text;
}
//如果输入了.且该文本框不为空,则自动跳到下一个输入框中
if (!string.IsNullOrWhiteSpace(input) && ".".Equals(e.Text))
{
e.Handled = true;
this.PART_BOX3.Focus();
}
else
{
e.Handled = this.CheckNumberIsLegal(input, e.Text);
//如果输入不合法,则默认为255
if (e.Handled)
{
this.PART_BOX2.Text = "255";
this.PART_BOX2.SelectionStart = this.PART_BOX2.Text.Length + 1;
this.IsHasError = true;
this.ErrorContent = string.Format(ZeroTo255Tip, input);
}
else
{
this.IsHasError = false;
}
}
}
void PART_BOX3_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
string input = this.PART_BOX3.Text + e.Text;
if (!string.IsNullOrWhiteSpace(this.PART_BOX3.SelectedText))
{
input = this.PART_BOX3.Text.Remove(this.PART_BOX3.SelectionStart, this.PART_BOX3.SelectionLength) + e.Text;
}
if (!string.IsNullOrWhiteSpace(input) && ".".Equals(e.Text))
{
e.Handled = true;
this.PART_BOX4.Focus();
}
else
{
e.Handled = this.CheckNumberIsLegal(input, e.Text);
if (e.Handled)
{
this.PART_BOX3.Text = "255";
this.PART_BOX3.SelectionStart = this.PART_BOX3.Text.Length + 1;
this.IsHasError = true;
this.ErrorContent = string.Format(ZeroTo255Tip, input);
}
else
{
this.IsHasError = false;
}
}
}
void PART_BOX4_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
string input = this.PART_BOX4.Text + e.Text;
if (!string.IsNullOrWhiteSpace(this.PART_BOX4.SelectedText))
{
input = this.PART_BOX4.Text.Remove(this.PART_BOX4.SelectionStart, this.PART_BOX4.SelectionLength) + e.Text;
}
e.Handled = this.CheckNumberIsLegal(input, e.Text);
if (e.Handled)
{
this.PART_BOX4.Text = "255";
this.PART_BOX4.SelectionStart = this.PART_BOX4.Text.Length + 1;
this.IsHasError = true;
this.ErrorContent = string.Format(ZeroTo255Tip, input);
}
else
{
this.IsHasError = false;
}
}
void PART_BOX1_TextChanged(object sender, TextChangedEventArgs e)
{
if (this.PART_BOX1.Text.Length == 3)
{
int number = 1;
if (Int32.TryParse(this.PART_BOX1.Text, out number))
{
switch (this.Type)
{
case EnumIpBoxType.IpAddress:
if (number < 1)
{
this.PART_BOX1.Text = "1";
}
break;
case EnumIpBoxType.SubnetMask:
break;
}
}
this.PART_BOX2.Focus();
}
}
void PART_BOX2_TextChanged(object sender, TextChangedEventArgs e)
{
if (this.PART_BOX2.Text.Length == 3)
{
this.PART_BOX3.Focus();
}
}
void PART_BOX3_TextChanged(object sender, TextChangedEventArgs e)
{
if (this.PART_BOX3.Text.Length == 3)
{
this.PART_BOX4.Focus();
}
}
#endregion
}
}