123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- namespace FWindSoft.Wpf.Controls
- {
- /// <summary>
- /// 输入文本生效方式
- /// </summary>
- public enum InputTextForceType
- {
- /// <summary>
- /// 实时
- /// </summary>
- Time,
- /// <summary>
- /// 按键
- /// </summary>
- KeyDown
- }
- [TemplatePart(Name = PART_TextBox, Type = typeof(TextBox))]
- [TemplatePart(Name = PART_Up, Type = typeof(Button))]
- [TemplatePart(Name = PART_Down, Type = typeof(Button))]
- public class IntegerSpinner:Control
- {
- static IntegerSpinner()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(IntegerSpinner), new FrameworkPropertyMetadata(typeof(IntegerSpinner)));
- }
- public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(IntegerSpinner), new FrameworkPropertyMetadata(false));
- public bool IsReadOnly
- {
- get
- {
- return (bool)GetValue(IsReadOnlyProperty);
- }
- set
- {
- SetValue(IsReadOnlyProperty, value);
- }
- }
- #region 最大值最小值限定相关
- public static readonly RoutedEvent ValueChangedEvent=EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(IntegerSpinner));
- public static readonly DependencyProperty MinimumProperty=DependencyProperty.Register("Minimum", typeof(int), typeof(IntegerSpinner), new FrameworkPropertyMetadata(1, new PropertyChangedCallback(OnMinimumChanged)));
- public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(int), typeof(IntegerSpinner), new FrameworkPropertyMetadata(100, new PropertyChangedCallback(OnMaximumChanged), new CoerceValueCallback(CoerceMaximum)));
- public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(IntegerSpinner), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, new PropertyChangedCallback(OnValueChanged), new CoerceValueCallback(ConstrainToRange)));
- public static readonly DependencyProperty StepProperty = DependencyProperty.Register("Step", typeof(int), typeof(IntegerSpinner), new FrameworkPropertyMetadata(1));
- public event RoutedPropertyChangedEventHandler<int> ValueChanged
- {
- add
- {
- base.AddHandler(ValueChangedEvent, value);
- }
- remove
- {
- base.RemoveHandler(ValueChangedEvent, value);
- }
- }
- public int Minimum
- {
- get
- {
- return (int)base.GetValue(MinimumProperty);
- }
- set
- {
- base.SetValue(MinimumProperty, value);
- }
- }
- public int Maximum
- {
- get
- {
- return (int)base.GetValue(MaximumProperty);
- }
- set
- {
- base.SetValue(MaximumProperty, value);
- }
- }
- public int Value
- {
- get
- {
- return (int)base.GetValue(ValueProperty);
- }
- set
- {
- base.SetValue(ValueProperty, value);
- }
- }
- public int Step
- {
- get
- {
- return (int)base.GetValue(StepProperty);
- }
- set
- {
- base.SetValue(StepProperty, value);
- }
- }
- #region 最小值处理
- private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- IntegerSpinner rangeBase = (IntegerSpinner)d;
- rangeBase.CoerceValue(MaximumProperty);
- rangeBase.CoerceValue(ValueProperty);
- rangeBase.OnMinimumChanged((int)e.OldValue, (int)e.NewValue);
- }
- protected virtual void OnMinimumChanged(int oldMinimum, int newMinimum)
- {
- }
- #endregion
- #region 最大值处理
- private static object CoerceMaximum(DependencyObject d, object value)
- {
- IntegerSpinner rangeBase = (IntegerSpinner)d;
- int minimum = rangeBase.Minimum;
- if ((int)value < minimum)
- {
- return minimum;
- }
- return value;
- }
- private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- IntegerSpinner rangeBase = (IntegerSpinner)d;
- rangeBase.CoerceValue(ValueProperty);
- rangeBase.OnMaximumChanged((int)e.OldValue, (int)e.NewValue);
- }
- protected virtual void OnMaximumChanged(int oldMaximum, int newMaximum)
- {
- }
- #endregion
- #region 值处理
- internal static object ConstrainToRange(DependencyObject d, object value)
- {
- IntegerSpinner rangeBase = (IntegerSpinner)d;
- int minimum = rangeBase.Minimum;
- int num = (int)value;
- if (num < minimum)
- {
- //加入这个显示,可以强制的更新到绑定的数据源,但是会执行两次,这样保证了Value值,最后的正确性
- //但失去焦点,同样会达成这种效果
- //rangeBase.Value = minimum;
- return minimum;
- }
- int maximum = rangeBase.Maximum;
- if (num > maximum)
- {
- //
- //rangeBase.Value = maximum;
- return maximum;
- }
-
- return value;
- }
- private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- IntegerSpinner rangeBase = (IntegerSpinner)d;
- rangeBase.OnValueChanged((int)e.OldValue, (int)e.NewValue);
- }
- protected virtual void OnValueChanged(int oldValue, int newValue)
- {
- ValueToText(newValue);//value值变换更新Text值
- base.RaiseEvent(new RoutedPropertyChangedEventArgs<int>(oldValue, newValue)
- {
- RoutedEvent = IntegerSpinner.ValueChangedEvent
- });
- }
- #endregion
- #endregion
- #region 临时值存储相关
- protected TextBox TextBox
- {
- get; private set;
- }
- protected Button UpButton
- { get; private set; }
- protected Button DownButton
- { get; private set; }
- public static readonly DependencyProperty ForceTypeProperty = DependencyProperty.Register("ForceType", typeof(InputTextForceType), typeof(IntegerSpinner), new FrameworkPropertyMetadata(InputTextForceType.Time));
- public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(IntegerSpinner), new FrameworkPropertyMetadata(null, Text_Changed));
- public string Text
- {
- get { return (string)GetValue(TextProperty); }
- set
- {
- SetValue(TextProperty,value);
- }
- }
- /// <summary>
- /// 输入文本生效类型
- /// </summary>
- public InputTextForceType ForceType
- {
- get { return (InputTextForceType)GetValue(ForceTypeProperty); }
- set
- {
- SetValue(ForceTypeProperty, value);
- }
- }
- private bool m_OutChanged=true;//外部赋值引起的Text变化
- private bool m_UiChanged = false;//Ui引起的Text值发生变化
- public static void Text_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- IntegerSpinner spinner = d as IntegerSpinner;
- if (spinner == null)
- return;
- spinner.TextChanged(e);
- }
- private void TextChanged(DependencyPropertyChangedEventArgs e)
- {
- //如果是内部修改直接退出
- //var test = this.IsInitialized;
- if (!m_OutChanged)
- return;
- var newValue = (string) e.NewValue;
- if (ForceType == InputTextForceType.KeyDown)
- {
- return;
- }
-
- if (!m_UiChanged)
- {
- //外部修改,将Text转换成Value
- TextToValue(newValue);
- //通过约束的Value,返回TextBox
- ValueToText(this.Value);
-
- SetTextBoxText(TextBox, this);
- }
- else
- {
- //不回写TextBox,不强制计算
- TextToValue(newValue);
- }
- }
- #region Text和value交互
- /*
- 1、Text 的值外接赋值,需要强制刷新界面TextBox的值
- 2、存在将Value转换成Text的函数
- 3、Text只与Value发生交互
- */
- private void ValueToText(int value)
- {
- m_OutChanged = false;
- try
- {
- this.Text = value.ToString();
- }
- finally
- {
- m_OutChanged = true;
- }
- }
- /// <summary>
- /// 转换成Value
- /// </summary>
- /// <param name="text"></param>
- /// <returns>是否给Value赋值</returns>
- private void TextToValue(string text)
- {
- if (string.IsNullOrEmpty(text))
- return ;
- int result = 0;
- if (Int32.TryParse(text, out result))
- {
- this.Value = result;
- }
- }
- #region Text和TextBox交互
- private bool m_UseTextBoxChangeEvent = true;
- private void SetTextBoxText(TextBox textBox, IntegerSpinner spinner)
- {
- try
- {
- m_UseTextBoxChangeEvent = false;
- if (textBox == null)
- return;
- textBox.Text = spinner.Text;
- }
- finally
- {
- m_UseTextBoxChangeEvent = true;
- }
- }
- private void GetTextBoxText(TextBox textBox, IntegerSpinner spinner)
- {
- if (textBox == null)
- return;
- try
- {
- m_UiChanged = true;
- spinner.Text = textBox.Text;
- }
- finally
- {
- m_UiChanged = false;
- }
-
- }
- #endregion
- #endregion
- #endregion
- #region 键盘控制相关
- public const string PART_TextBox = "PART_TextBox";
- public const string PART_Up = "PART_Up";
- public const string PART_Down = "PART_Down";
- protected override void OnAccessKey(AccessKeyEventArgs e)
- {
- if (TextBox != null)
- TextBox.Focus();
- base.OnAccessKey(e);
- }
- #region 子空间事件相关
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- Detaching();
- TextBox = GetTemplateChild(PART_TextBox) as TextBox;
- UpButton = GetTemplateChild(PART_Up) as Button;
- DownButton = GetTemplateChild(PART_Down) as Button;
- Attached();
- }
- private void Attached()
- {
- if (TextBox != null)
- {
- SetTextBoxText(TextBox, this);
- TextBox.TextChanged += new TextChangedEventHandler(TextBox_TextChanged);
- }
- if (UpButton != null)
- {
- UpButton.Click += UpButton_Click;
- }
- if (DownButton != null)
- {
- DownButton.Click += DownButton_Click;
- }
- }
-
- private void Detaching()
- {
- if (TextBox != null)
- {
- TextBox.TextChanged -= new TextChangedEventHandler(TextBox_TextChanged);
- }
- if (UpButton != null)
- {
- UpButton.Click -= UpButton_Click;
- }
- if (DownButton != null)
- {
- DownButton.Click-= DownButton_Click;
- }
- }
- private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
- {
- if (!m_UseTextBoxChangeEvent)
- return;
- GetTextBoxText((TextBox)sender, this);
-
- }
- private void DownButton_Click(object sender, RoutedEventArgs e)
- {
- this.Value = this.Value - Step;
- SetTextBoxText(TextBox, this);
- }
- private void UpButton_Click(object sender, RoutedEventArgs e)
- {
- this.Value = this.Value + Step;
- SetTextBoxText(TextBox, this);
- }
- #endregion
- //输入生效模式为KeyDown时,当按下enter,或控件失去焦点,则执行强制提交。这是才修改Value值
- //Time时,是实时修改value值
- protected override void OnKeyDown(KeyEventArgs e)
- {
- switch (e.Key)
- {
- case Key.Enter:
- {
- this.CommitInput();
- if (TextBox != null)
- TextBox.Select((this.Text ?? string.Empty).Length, 0);
- break;
- }
- }
-
- }
- public void CommitInput()
- {
- TextToValue(this.Text);
- //通过约束的Value,返回TextBox
- ValueToText(this.Value);
- SetTextBoxText(TextBox, this);
- }
- #endregion
- public IntegerSpinner()
- {
- this.LostFocus += IntegerSpinner_LostFocus;
- this.Loaded += IntegerSpinner_Loaded;
- }
- private void IntegerSpinner_Loaded(object sender, RoutedEventArgs e)
- {
- this.Loaded -= IntegerSpinner_Loaded;
- this.CommitInput();
- }
- private void IntegerSpinner_LostFocus(object sender, RoutedEventArgs e)
- {
- //点击按钮也会发生焦点变化,这个暂时不需要过滤
- this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() =>
- {
- CommitInput();
- }));
- }
- protected override void OnLostFocus(RoutedEventArgs e)
- {
- //不知道重写Overide为什么不执行
- }
-
- }
- }
|