public partial class UC_NumberBox : TextBox
{
#region ctor
/// <summary>
/// Конструктор
/// </summary>
public UC_NumberBox()
{
InitializeComponent();
//привязываемся к событию на вставку в текстбокс
DataObject.AddPastingHandler(this, this.OnPaste);
}
#endregion ctor
#region Dependency Properties
#region DeltaProperty
/// <summary>
/// Значение инкремента
/// </summary>
public int Delta
{
get { return (int)GetValue(DeltaProperty); }
set { SetValue(DeltaProperty, value); }
}
public static readonly DependencyProperty DeltaProperty =
DependencyProperty.Register("Delta", typeof(int), typeof(UC_NumberBox), new PropertyMetadata(1));
#endregion
#region MinValueProperty
/// <summary>
/// Минимальное значение
/// </summary>
public int MinValue
{
get { return (int)GetValue(MinValueProperty); }
set
{
if (value > Value)
Value = value;
SetValue(MinValueProperty, value);
}
}
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(int), typeof(UC_NumberBox), new PropertyMetadata(0));
#endregion
#region MaxValueProperty
/// <summary>
/// Максимальное значение
/// </summary>
public int MaxValue
{
get { return (int)GetValue(MaxValueProperty); }
set
{
if (value < Value)
Value = value;
SetValue(MaxValueProperty, value);
}
}
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(int), typeof(UC_NumberBox), new PropertyMetadata(100));
#endregion
#region ValueProperty
/// <summary>
/// Целочисленное значение
/// </summary>
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(int),
typeof(UC_NumberBox),
new FrameworkPropertyMetadata(
0,
new PropertyChangedCallback(OnChangeValue),
new CoerceValueCallback(OnCoerceValue)
));
#endregion ValueProperty
#endregion Dependency Properties
#region Events
/// <summary>
/// Обработчик события на изменение значения
/// </summary>
/// <param name="sender">Отправитель</param>
/// <param name="e">Аргументы</param>
private static void OnChangeValue(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
//Включаем зависимость значения от свойств максимума и минимума
sender.CoerceValue(MinValueProperty);
sender.CoerceValue(MaxValueProperty);
}
/// <summary>
/// Обработчик события корректировки значений
/// </summary>
/// <param name="sender">Отправитель</param>
/// <param name="value">Значение</param>
/// <returns>скорректированное значение</returns>
private static object OnCoerceValue(DependencyObject sender, object value)
{
var nb = (UC_NumberBox)sender;
int current;
string str = Convert.ToString(value);
try
{
current = Convert.ToInt32(str);
if (current < nb.MinValue) current = nb.MinValue;
if (current > nb.MaxValue) current = nb.MaxValue;
}
catch (OverflowException)
{
if (str[0] == '-')
current = nb.MinValue;
else
current = nb.MaxValue;
}
return current;
}
/// <summary>
/// Обработчик события при команде Paste
/// </summary>
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
if (e.SourceDataObject.GetDataPresent(DataFormats.Text,true))
{
string pasteText = (string)e.SourceDataObject.GetData(DataFormats.Text);
string futureText = GetFutureText(pasteText);
if (IsIntValid(futureText))
{
try
{
Value = Convert.ToInt32(futureText);
}
catch (OverflowException)
{
if (futureText[0] == '-')
Value = MinValue;
else
Value = MaxValue;
}
}
}
e.CancelCommand();
}
/// <summary>
/// Обработчик события на ввод текста с клавиатуры
/// </summary>
/// <param name="sender">Отправитель</param>
/// <param name="e">Аргументы</param>
private void tb_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = true;
string futureText = GetFutureText(e.Text);
if (IsIntValid(futureText))
{
e.Handled = false;
}
}
/// <summary>
/// Обработчик события на нажатие кнопок клавиатуры
/// (в данный момент ловит только стрелки вверх и вниз)
/// </summary>
/// <param name="sender">Отправитель</param>
/// <param name="e">Аргументы</param>
private void tb_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up) Plus();
if (e.Key == Key.Down) Minus();
}
/// <summary>
/// Обработчик событий вращения колесика мыши
/// </summary>
/// <param name="sender">Отправитель</param>
/// <param name="e">Аргументы</param>
public void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0) Plus();
if (e.Delta < 0) Minus();
}
#endregion Events
#region Methods
/// <summary>
/// Получить текст с учетом введенных или вставленных командой Paste строк
/// </summary>
/// <param name="s">Добавленная строка</param>
/// <returns>готовый текст</returns>
private string GetFutureText(string s)
{
return (this.SelectionLength>0 ? Text.Remove(SelectionStart,SelectionLength).Insert(SelectionStart,s) : Text.Insert(CaretIndex,s));
}
/// <summary>
/// Прибавить значение
/// </summary>
/// <param name="value">Значение которое нужно прибавить (если отрицательное, то отнимется)</param>
private void AddIncrement(int value)
{
Value += value;
}
public void Plus()
{
AddIncrement(Delta);
}
public void Minus()
{
AddIncrement(-Delta);
}
/// <summary>
/// Проверка на валидность текста для приведения к Int32
/// </summary>
/// <param name="s">Текст для проверки</param>
/// <returns>истину, если текст валидный</returns>
private bool IsIntValid(string s)
{
if (s[0] == '+' || s[0] == '-')
s = s.Substring(1);
foreach (char c in s)
if (!"0123456789".Contains(c))
return false;
return true;
}
#endregion Methods
}
public class IntToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is int)
return System.Convert.ToString(value);
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string)
{
int res;
try
{
res = System.Convert.ToInt32(value);
}
catch (Exception)
{
res = 0;
}
return res;
}
return 0;
}
}