using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace XYY.Windows.SAAS.WpfExtention.AttachedProperties
{
public class InputAttachedProperties
{
#region 附加属性
public static bool GetEnableInputValidate(DependencyObject obj)
{
return (bool)obj.GetValue(EnableInputValidateProperty);
}
public static void SetEnableInputValidate(DependencyObject obj, bool value)
{
obj.SetValue(EnableInputValidateProperty, value);
}
//是否使用输入校验
public static readonly DependencyProperty EnableInputValidateProperty =
DependencyProperty.RegisterAttached("EnableInputValidate", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false, (a, b) =>
{
if (a is TextBox tb && b.NewValue is bool en)
{
if (en)
{
tb.PreviewTextInput += Tb_PreviewTextInput;
tb.GotFocus += Tb_GotFocus;
tb.TextChanged += Tb_TextChanged;
tb.AcceptsReturn = false;
tb.AcceptsTab = false;
tb.PreviewDrop += Tb_PreviewDrop;
CommandManager.AddPreviewExecutedHandler(tb, tbPreviewCommandExcute);
//禁用输入法
if (tb.IsInputMethodEnabled)
{
InputMethod.SetIsInputMethodEnabled(tb, false);
InputMethod.Current.ImeState = InputMethodState.Off;
}
}
else
{
tb.PreviewTextInput -= Tb_PreviewTextInput;
tb.GotFocus -= Tb_GotFocus;
tb.AcceptsReturn = true;
tb.AcceptsTab = true;
tb.PreviewDrop -= Tb_PreviewDrop;
CommandManager.RemovePreviewExecutedHandler(tb, tbPreviewCommandExcute);
//禁用输入法
if (tb.IsInputMethodEnabled)
{
InputMethod.SetIsInputMethodEnabled(tb, true);
InputMethod.Current.ImeState = InputMethodState.DoNotCare;
}
}
}
}));
private static void Tb_GotFocus(object sender, RoutedEventArgs e)
{
var tb = sender as TextBox;
tb.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, new Action(() =>
{
tb.SelectAll();
}));
}
public static bool GetIsNumber(DependencyObject obj)
{
return (bool)obj.GetValue(IsNumberProperty);
}
public static void SetIsNumber(DependencyObject obj, bool value)
{
obj.SetValue(IsNumberProperty, value);
}
//是否是数字 (不能有负号,小数)
public static readonly DependencyProperty IsNumberProperty =
DependencyProperty.RegisterAttached("IsNumber", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false));
public static bool GetIsAmount(DependencyObject obj)
{
return (bool)obj.GetValue(IsAmountProperty);
}
public static void SetIsAmount(DependencyObject obj, bool value)
{
obj.SetValue(IsAmountProperty, value);
}
//是否是金额 (可以有负号,小数)
public static readonly DependencyProperty IsAmountProperty =
DependencyProperty.RegisterAttached("IsAmount", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false));
public static int GetDecimalPlace(DependencyObject obj)
{
return (int)obj.GetValue(DecimalPlaceProperty);
}
public static void SetDecimalPlace(DependencyObject obj, int value)
{
obj.SetValue(DecimalPlaceProperty, value);
}
//小数位数
public static readonly DependencyProperty DecimalPlaceProperty =
DependencyProperty.RegisterAttached("DecimalPlace", typeof(int), typeof(InputAttachedProperties), new PropertyMetadata(3));
#endregion
#region 校验方法
private static void tbPreviewCommandExcute(object sender, ExecutedRoutedEventArgs e)
{
var tb = sender as TextBox;
var isNumber = GetIsNumber(sender as TextBox);
var isAmount = GetIsAmount(sender as TextBox);
if (e.Command == ApplicationCommands.Cut ||
e.Command == ApplicationCommands.Paste)
{
e.Handled = true;
}
if (e.Command is RoutedUICommand rc)
{
switch (rc.Name)
{
case "MoveUpByLine":
case "MoveDownByLine":
e.Handled = true;
return;
case "Space":
if (isAmount || isNumber)
e.Handled = true;
return;
case "DeletePreviousWord":
case "DeleteNextWord":
case "Backspace":
case "Delete":
var result = TestFutureText(null, sender as TextBox, rc.Name);
//只有多个连续的0替换成只有一个
if (Regex.IsMatch(result, @"^-?00+$"))
{
tb.Text = Regex.Replace(result, @"0+", m => "0");
tb.CaretIndex = tb.Text.Length;
e.Handled = true;
return;
}
//小数删得只有末尾的.,把.也删了
if (Regex.IsMatch(result, @".0*$"))
{
tb.Text = Regex.Replace(result, @".0*$", m => string.Empty);
tb.CaretIndex = tb.Text.Length;
e.Handled = true;
return;
}
//整数部分删得只有-,把整数部分改为0
if (Regex.IsMatch(result, @"^-(?!d)"))
{
tb.Text = result.Replace("-", "0");
tb.CaretIndex = 0;
tb.SelectionStart = 0;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
//如果输入了.,但是没有整数部分,整数部分补0
if (Regex.IsMatch(result, @"^."))
{
tb.Text = "0" + result;
tb.CaretIndex = 0;
tb.SelectionStart = 0;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
//整数无意义的0去掉
//小数无意义的0去掉
if (Regex.IsMatch(result, @"(^.*..*?)0+$"))
{
tb.Text = Regex.Match(result, @"(^.*..*?)0+$").Groups[1].Value;
tb.CaretIndex = tb.Text.Length;
e.Handled = true;
return;
}
break;
default:
break;
}
}
}
private static void Tb_PreviewDrop(object sender, DragEventArgs e)
{
e.Handled = true;
return;
}
private static void Tb_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
var previewText = e.Text;
var tb = sender as TextBox;
//禁用输入法
if (tb.IsInputMethodEnabled)
{
InputMethod.SetIsInputMethodEnabled(tb, false);
InputMethod.Current.ImeState = InputMethodState.Off;
}
var result = TestFutureText(previewText, tb);
var isNumber = GetIsNumber(tb);
var isAmount = GetIsAmount(tb);
var decimalSpace = GetDecimalPlace(tb);
//isAmoust和isNumber互斥,且优先级高于isNumber
if (isAmount)
isNumber = false;
if (isNumber || isAmount)
{
//不能输入空格
if (Regex.IsMatch(result, @"s+"))
{
e.Handled = true;
return;
}
//全0的时候 ,多个连接的0替换成只有一个
if (Regex.IsMatch(result, @"^-?00+$"))
{
tb.Text = Regex.Replace(result, @"0+", m => "0");
tb.CaretIndex = tb.Text.Length;
e.Handled = true;
return;
}
}
//纯数字模式
if (isNumber)
{
//如果不是纯数字,处理掉输入信号
if (!Regex.IsMatch(result, @"^d+$"))
{
e.Handled = true;
return;
}
//如果只输了0再输其他的数字,直接替换掉0
if (tb.Text == "0" && tb.SelectionLength == 0 && tb.CaretIndex == 1)
{
tb.Text = previewText;
tb.CaretIndex = 1;
e.Handled = true;
return;
}
//不能输入没有意义的0
if (Regex.IsMatch(result, @"^0(?=d)"))
{
e.Handled = true;
return;
}
}
//金额模式(正负值 小数点)
if (isAmount)
{
//只能输入数字和小数点和负号
if (!Regex.IsMatch(previewText, @"[d.-]"))
{
e.Handled = true;
return;
}
//如果光标右边是. 什么都不做,光标右移一位
if (Regex.IsMatch(tb.Text, @"d+.d+") && previewText == "." && tb.Text.Length != tb.CaretIndex && tb.Text[tb.CaretIndex] == '.')
{
tb.CaretIndex++;
}
//小数点如果超过限制,中断输入信号
if (Regex.IsMatch(result, @".d+$"))
{
var len = Regex.Match(result, @".(d+$)").Groups[1].Length;
if (len > decimalSpace)
{
e.Handled = true;
return;
}
}
//如果是-.的情况 改为-0.1
if (result == "-.")
{
tb.Text = "-0.1";
tb.CaretIndex = tb.Text.Length - 1;
tb.SelectionStart = tb.Text.Length - 1;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
if (result == ".")
{
tb.Text = "0.1";
tb.CaretIndex = tb.Text.Length - 1;
tb.SelectionStart = tb.Text.Length - 1;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
//如果有多个小数点不让输入
if (Regex.Matches(result, @".").Count > 1)
{
e.Handled = true;
return;
}
//如果有多个负号不让输入
if (Regex.Matches(result, @"-").Count > 1)
{
e.Handled = true;
return;
}
//如果负号不是在最前面不让输入
if (Regex.IsMatch(result, @"(?<!^)-"))
{
e.Handled = true;
return;
}
//不能输入空格
if (Regex.IsMatch(result, @"s+"))
{
e.Handled = true;
return;
}
//整数部分如果只输了0或-0,光标定位在0后面再输其他的数字,直接替换掉0
if (((Regex.IsMatch(result, @"^0+") && tb.CaretIndex == 1) || (Regex.IsMatch(result, @"^-0+") && tb.CaretIndex == 2)) && tb.SelectionLength == 0)
{
if (previewText != ".")
{
tb.Text = Regex.Replace(tb.Text, @"0+", m =>
{
if (m.Index == 0)
{
return previewText;
}
return m.Value;
});
tb.CaretIndex = tb.Text.IndexOf(previewText) + 1;
e.Handled = true;
return;
}
}
//小数点前面不能输入没有意义的0
if (Regex.IsMatch(result, @"^-?0(?=d)"))
{
e.Handled = true;
return;
}
//小数点后面不能输没有意义的0,所以自动补1,1为选中状态
if (Regex.IsMatch(result, @".d*0$"))
{
var decimalSpaceLen = Regex.Match(result, @"[^.]+$").Value.Length;
if (decimalSpaceLen <= decimalSpace - 1)
{
tb.Text = result + "1";
tb.CaretIndex = tb.Text.Length - 1;
tb.SelectionStart = tb.CaretIndex;
tb.SelectionLength = 1;
}
e.Handled = true;
return;
}
//如果整数部分只输入了-号,自动补全为-1 1为选中状态
if (Regex.IsMatch(result, @"^-(?!d)"))
{
tb.Text = result.Replace("-", "-1");
tb.CaretIndex = 1;
tb.SelectionStart = 1;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
//如果在末尾输入了. ,自动补全为.1 ,1为选中状态
if (Regex.IsMatch(result, @".$"))
{
var i = result.IndexOf('.');
tb.Text = result.Replace(".", ".1");
tb.CaretIndex = i + 1;
tb.SelectionStart = i + 1;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
//如果输入了.,但是没有整数部分,整数部分补0
if (Regex.IsMatch(result, @"^."))
{
tb.Text = "0" + result;
tb.CaretIndex = 0;
tb.SelectionStart = 0;
tb.SelectionLength = 1;
e.Handled = true;
return;
}
}
}
private static string TestFutureText(string previewText, TextBox tb, string deleteMode = null)
{
var cindex = tb.CaretIndex;
var sLen = tb.SelectionLength;
var sStartIndex = tb.SelectionStart;
var deleteStart = cindex >= sStartIndex ? sStartIndex : cindex;
string futureText = string.Empty;
//按删除的
if (!string.IsNullOrEmpty(deleteMode))
{
//按删除键,且有选择字符时,直接删除选择的字符
if (tb.SelectionLength > 0)
{
switch (deleteMode)
{
case "DeletePreviousWord":
case "DeleteNextWord":
case "Backspace":
case "Delete":
default:
futureText = tb.Text.Remove(deleteStart, sLen);
break;
}
}
//按删除键,没有选择字符时
else
{
switch (deleteMode)
{
//ctrl+backspace 删除到 单词左边
case "DeletePreviousWord":
if (cindex == 0)
return tb.Text;
var c = tb.Text[cindex - 1];
var isWord = Regex.IsMatch(c.ToString(), @"w");
if (!isWord)
{
futureText = tb.Text.Remove(cindex - 1, 1);
return futureText;
}
var startindex = 0;
for (int i = 0; i < cindex; i++)
{
if (Regex.IsMatch(tb.Text[i].ToString(), @"W"))
{
startindex = i + 1;
}
}
futureText = tb.Text.Remove(startindex, cindex - startindex);
break;
//ctrl+delete 删除到 单词右边
case "DeleteNextWord":
if (cindex == tb.Text.Length)
return tb.Text;
var c2 = tb.Text[cindex];
var isWord2 = Regex.IsMatch(c2.ToString(), @"w");
if (!isWord2)
{
futureText = tb.Text.Remove(cindex, 1);
return futureText;
}
var end = 0;
for (int i = cindex; i < tb.Text.Length; i++)
{
if (Regex.IsMatch(c2.ToString(), @"w"))
end = i;
else
break;
}
futureText = tb.Text.Remove(cindex, end - cindex);
break;
//删除光标左边的字符1个或0个
case "Backspace":
futureText = tb.Text.Remove(deleteStart - 1 <= 0 ? 0 : deleteStart - 1, deleteStart >= 1 ? 1 : 0);
break;
//删除光标左右的字符1个或0个
case "Delete":
futureText = tb.Text.Remove(deleteStart, tb.Text.Length - deleteStart >= 1 ? 1 : 0);
break;
default:
break;
}
}
}
//不是按删除的
else
{
futureText = tb.Text.Remove(deleteStart, sLen).Insert(deleteStart, previewText);
}
Console.WriteLine(futureText);
return futureText;
}
private static void Tb_TextChanged(object sender, TextChangedEventArgs e)
{
var tb = sender as TextBox;
var isNumber = GetIsNumber(tb);
var isAmount = GetIsAmount(tb);
if ((isNumber || isAmount) && string.IsNullOrWhiteSpace(tb.Text))
{
tb.Text = "0";
tb.SelectionStart = 0;
tb.SelectionLength = 1;
}
}
#endregion
}
}