From 8997e418f76f1b94072e8bc1e3352a98e29fd0e2 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Mon, 15 Oct 2018 18:03:33 +0800 Subject: [PATCH] refactor colorpicker --- HandyControl/Controls/NumericUpDown.cs | 52 ++++- .../{ColorPicker.xaml.cs => ColorPicker.cs} | 214 ++++++++++++++---- HandyControl/Controls/Picker/ColorPicker.xaml | 108 --------- HandyControl/HandyControl.csproj | 8 +- HandyControl/Interactivity/ControlCommands.cs | 5 + HandyControl/Themes/Styles/Button.xaml | 4 +- HandyControl/Themes/Styles/ColorPicker.xaml | 116 +++++++++- 7 files changed, 329 insertions(+), 178 deletions(-) rename HandyControl/Controls/Picker/{ColorPicker.xaml.cs => ColorPicker.cs} (67%) delete mode 100644 HandyControl/Controls/Picker/ColorPicker.xaml diff --git a/HandyControl/Controls/NumericUpDown.cs b/HandyControl/Controls/NumericUpDown.cs index 90dde33d..03b0d475 100644 --- a/HandyControl/Controls/NumericUpDown.cs +++ b/HandyControl/Controls/NumericUpDown.cs @@ -46,7 +46,8 @@ namespace HandyControl.Controls { if (_textBox != null) { - _textBox.PreviewTextInput -= TextBoxValue_TextInput; + _textBox.TextChanged -= TextBox_TextChanged; + _textBox.PreviewKeyDown -= TextBox_PreviewKeyDown; } base.OnApplyTemplate(); @@ -55,13 +56,27 @@ namespace HandyControl.Controls if (_textBox != null) { - _textBox.PreviewTextInput += TextBoxValue_TextInput; - _textBox.Text = Value.ToString($"#0.{new string('0', DecimalPlaces)}"); + _textBox.TextChanged += TextBox_TextChanged; + _textBox.PreviewKeyDown += TextBox_PreviewKeyDown; + _textBox.Text = CurrentText; } } - private void TextBoxValue_TextInput(object sender, TextCompositionEventArgs e) + private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) { + if (e.Key == Key.Up) + { + Value += Increment; + } + else if (e.Key == Key.Down) + { + Value -= Increment; + } + } + + private void TextBox_TextChanged(object sender, TextChangedEventArgs e) + { + if (string.IsNullOrEmpty(_textBox.Text)) return; if (double.TryParse(_textBox.Text, out var value)) { Value = value; @@ -69,8 +84,7 @@ namespace HandyControl.Controls if (_textBox != null) { - _textBox.Text = Value.ToString($"#0.{new string('0', DecimalPlaces)}"); - _textBox.Select(_textBox.Text.Length, 0); + _textBox.Text = CurrentText; } } @@ -85,6 +99,10 @@ namespace HandyControl.Controls } } + private string CurrentText => DecimalPlaces.HasValue + ? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}") + : Value.ToString("#0"); + protected virtual void OnValueChanged(FunctionEventArgs e) => RaiseEvent(e); /// @@ -113,11 +131,14 @@ namespace HandyControl.Controls { var ctl = (NumericUpDown) d; var v = (double) e.NewValue; + if (ctl._textBox != null) { - ctl._textBox.Text = v.ToString($"#0.{new string('0', ctl.DecimalPlaces)}"); - ctl._textBox.Select(ctl._textBox.Text.Length, 0); + ctl._textBox.Text = ctl.DecimalPlaces.HasValue + ? v.ToString($"#0.{new string('0', ctl.DecimalPlaces.Value)}") + : v.ToString("#0"); } + ctl.OnValueChanged(new FunctionEventArgs(ValueChangedEvent, ctl) { Info = v @@ -139,7 +160,14 @@ namespace HandyControl.Controls { ctl.Value = maximum; } - return num > maximum ? maximum : basevalue; + + var result = num > maximum ? maximum : num; + if (!ctl.DecimalPlaces.HasValue) + { + result = Math.Floor(result); + } + + return result; } /// @@ -234,14 +262,14 @@ namespace HandyControl.Controls /// 指示要显示的小数位数 /// public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register( - "DecimalPlaces", typeof(int), typeof(NumericUpDown), new PropertyMetadata(default(int))); + "DecimalPlaces", typeof(int?), typeof(NumericUpDown), new PropertyMetadata(default(int?))); /// /// 指示要显示的小数位数 /// - public int DecimalPlaces + public int? DecimalPlaces { - get => (int) GetValue(DecimalPlacesProperty); + get => (int?) GetValue(DecimalPlacesProperty); set => SetValue(DecimalPlacesProperty, value); } diff --git a/HandyControl/Controls/Picker/ColorPicker.xaml.cs b/HandyControl/Controls/Picker/ColorPicker.cs similarity index 67% rename from HandyControl/Controls/Picker/ColorPicker.xaml.cs rename to HandyControl/Controls/Picker/ColorPicker.cs index 396c48dd..a7d9fb47 100644 --- a/HandyControl/Controls/Picker/ColorPicker.xaml.cs +++ b/HandyControl/Controls/Picker/ColorPicker.cs @@ -6,6 +6,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using HandyControl.Data; +using HandyControl.Interactivity; using HandyControl.Tools.Extension; // ReSharper disable once CheckNamespace @@ -14,8 +15,43 @@ namespace HandyControl.Controls /// /// 颜色拾取器 /// - public partial class ColorPicker + [TemplatePart(Name = ElementBorderColor, Type = typeof(Border))] + [TemplatePart(Name = ElementBorderPicker, Type = typeof(Border))] + [TemplatePart(Name = ElementBorderDrag, Type = typeof(Border))] + [TemplatePart(Name = ElementPanelColor, Type = typeof(Panel))] + [TemplatePart(Name = ElementSliderColor, Type = typeof(Panel))] + [TemplatePart(Name = ElementSliderOpacity, Type = typeof(Panel))] + [TemplatePart(Name = ElementPanelRgb, Type = typeof(Panel))] + public class ColorPicker : Control { + #region Constants + + private const string ElementBorderColor = "PART_BorderColor"; + private const string ElementBorderPicker = "PART_BorderPicker"; + private const string ElementBorderDrag = "PART_BorderDrag"; + private const string ElementPanelColor = "PART_PanelColor"; + private const string ElementSliderColor = "PART_SliderColor"; + private const string ElementSliderOpacity = "PART_SliderOpacity"; + private const string ElementPanelRgb = "PART_PanelRgb"; + + #endregion Constants + + #region Data + + private Panel _panelRgb; + + private Border _borderColor; + + private Border _borderPicker; + + private Border _borderDrag; + + private Panel _panelColor; + + private Slider _sliderColor; + + private Slider _sliderOpacity; + /// /// 当前显示的颜色类型 /// @@ -127,29 +163,24 @@ namespace HandyControl.Controls Color.FromRgb(255, 255, 0) }; - internal static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( - "CornerRadius", typeof(CornerRadius), typeof(ColorPicker), new PropertyMetadata(new CornerRadius(2))); + #endregion Data - internal CornerRadius CornerRadius - { - get => (CornerRadius)GetValue(CornerRadiusProperty); - set => SetValue(CornerRadiusProperty, value); - } + #region Public Events /// /// 颜色改变事件 /// - public static readonly RoutedEvent ColorSelectedEvent = - EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, + public static readonly RoutedEvent SelectedColorChangedEvent = + EventManager.RegisterRoutedEvent("SelectedColorChanged", RoutingStrategy.Bubble, typeof(EventHandler>), typeof(ColorPicker)); /// /// 颜色改变事件 /// - public event EventHandler> ColorSelected + public event EventHandler> SelectedColorChanged { - add => AddHandler(ColorSelectedEvent, value); - remove => RemoveHandler(ColorSelectedEvent, value); + add => AddHandler(SelectedColorChangedEvent, value); + remove => RemoveHandler(SelectedColorChangedEvent, value); } /// @@ -168,6 +199,46 @@ namespace HandyControl.Controls remove => RemoveHandler(CanceledEvent, value); } + #endregion Public Events + + #region Properties + + internal static readonly DependencyProperty ChannelAProperty = DependencyProperty.Register( + "ChannelA", typeof(int), typeof(ColorPicker), new PropertyMetadata(255)); + + internal int ChannelA + { + get => (int)GetValue(ChannelAProperty); + set => SetValue(ChannelAProperty, value); + } + + internal static readonly DependencyProperty ChannelRProperty = DependencyProperty.Register( + "ChannelR", typeof(int), typeof(ColorPicker), new PropertyMetadata(255)); + + internal int ChannelR + { + get => (int)GetValue(ChannelRProperty); + set => SetValue(ChannelRProperty, value); + } + + internal static readonly DependencyProperty ChannelGProperty = DependencyProperty.Register( + "ChannelG", typeof(int), typeof(ColorPicker), new PropertyMetadata(255)); + + internal int ChannelG + { + get => (int)GetValue(ChannelGProperty); + set => SetValue(ChannelGProperty, value); + } + + internal static readonly DependencyProperty ChannelBProperty = DependencyProperty.Register( + "ChannelB", typeof(int), typeof(ColorPicker), new PropertyMetadata(255)); + + internal int ChannelB + { + get => (int)GetValue(ChannelBProperty); + set => SetValue(ChannelBProperty, value); + } + public static readonly DependencyProperty SelectedBrushProperty = DependencyProperty.Register( "SelectedBrush", typeof(SolidColorBrush), typeof(ColorPicker), new PropertyMetadata(Brushes.White, (o, args) => @@ -175,15 +246,13 @@ namespace HandyControl.Controls var ctl = (ColorPicker)o; var v = (SolidColorBrush)args.NewValue; - if (ctl.ChannelR == null) return; - if (ctl.IsNeedUpdateInfo) { ctl.IsNeedUpdateInfo = false; - ctl.ChannelR.Value = v.Color.R; - ctl.ChannelG.Value = v.Color.G; - ctl.ChannelB.Value = v.Color.B; - ctl.SliderOpacity.Value = v.Color.A; + ctl.ChannelR = v.Color.R; + ctl.ChannelG = v.Color.G; + ctl.ChannelB = v.Color.B; + ctl.ChannelA = v.Color.A; ctl.IsNeedUpdateInfo = true; } ctl.UpdateStatus(v.Color); @@ -199,36 +268,38 @@ namespace HandyControl.Controls set => SetValue(SelectedBrushProperty, value); } - private static readonly DependencyProperty SelectedBrushWithoutOpacityProperty = DependencyProperty.Register( + internal static readonly DependencyProperty SelectedBrushWithoutOpacityProperty = DependencyProperty.Register( "SelectedBrushWithoutOpacity", typeof(SolidColorBrush), typeof(ColorPicker), new PropertyMetadata(Brushes.White)); - private SolidColorBrush SelectedBrushWithoutOpacity + internal SolidColorBrush SelectedBrushWithoutOpacity { get => (SolidColorBrush)GetValue(SelectedBrushWithoutOpacityProperty); set => SetValue(SelectedBrushWithoutOpacityProperty, value); } - private static readonly DependencyProperty BackColorProperty = DependencyProperty.Register( + internal static readonly DependencyProperty BackColorProperty = DependencyProperty.Register( "BackColor", typeof(SolidColorBrush), typeof(ColorPicker), new PropertyMetadata(Brushes.Red)); - private SolidColorBrush BackColor + internal SolidColorBrush BackColor { get => (SolidColorBrush)GetValue(BackColorProperty); set => SetValue(BackColorProperty, value); } - private static readonly DependencyProperty ShowListProperty = DependencyProperty.Register( + internal static readonly DependencyProperty ShowListProperty = DependencyProperty.Register( "ShowList", typeof(List), typeof(ColorPicker), new PropertyMetadata(new List { true, false, false })); - private List ShowList + internal List ShowList { get => (List)GetValue(ShowListProperty); set => SetValue(ShowListProperty, value); } + #endregion Properties + /// /// 当前显示的颜色类型 /// @@ -262,9 +333,9 @@ namespace HandyControl.Controls public ColorPicker() { - InitializeComponent(); - - UpdateStatus(SelectedBrush.Color); + CommandBindings.Add(new CommandBinding(ControlCommands.Confirm, ButtonConfirm_OnClick)); + CommandBindings.Add(new CommandBinding(ControlCommands.Switch, ButtonSwitch_OnClick)); + CommandBindings.Add(new CommandBinding(ControlCommands.Cancel, ButtonCancel_OnClick)); Loaded += (s, e) => { @@ -276,14 +347,62 @@ namespace HandyControl.Controls }; } + public override void OnApplyTemplate() + { + if (_sliderColor != null) + { + _sliderColor.ValueChanged -= SliderColor_OnValueChanged; + } + + if (_sliderOpacity != null) + { + _sliderOpacity.ValueChanged -= SliderOpacity_OnValueChanged; + } + + _panelRgb?.RemoveHandler(NumericUpDown.ValueChangedEvent, new EventHandler>(NumericUpDownRgb_OnValueChanged)); + + base.OnApplyTemplate(); + + _borderColor = GetTemplateChild(ElementBorderColor) as Border; + _borderDrag = GetTemplateChild(ElementBorderDrag) as Border; + _borderPicker = GetTemplateChild(ElementBorderPicker) as Border; + _panelColor = GetTemplateChild(ElementPanelColor) as Panel; + _sliderColor = GetTemplateChild(ElementSliderColor) as Slider; + _sliderOpacity = GetTemplateChild(ElementSliderOpacity) as Slider; + _panelRgb = GetTemplateChild(ElementPanelRgb) as Panel; + + if (_sliderColor != null) + { + _sliderColor.ValueChanged += SliderColor_OnValueChanged; + } + + if (_sliderOpacity != null) + { + _sliderOpacity.ValueChanged += SliderOpacity_OnValueChanged; + } + + if (_borderDrag != null) + { + var behavior = new MouseDragElementBehavior(); + behavior.DragFinished += MouseDragElementBehavior_OnDragFinished; + behavior.DragBegun += MouseDragElementBehavior_OnDragging; + behavior.Dragging += MouseDragElementBehavior_OnDragging; + var collection = Interaction.GetBehaviors(_borderDrag); + collection.Add(behavior); + } + + _panelRgb?.AddHandler(NumericUpDown.ValueChangedEvent, new EventHandler>(NumericUpDownRgb_OnValueChanged)); + } + /// /// 初始化 /// private void Init() { + UpdateStatus(SelectedBrush.Color); foreach (var item in _colorPresetList) { - PanelColor.Children.Add(CreateColorButton(item)); + _panelColor.Children.Add(CreateColorButton(item)); } } @@ -317,7 +436,7 @@ namespace HandyControl.Controls button.Click += (s, e) => { SelectedBrush = brush; - SliderOpacity.Value = SliderOpacity.Maximum; + ChannelA = byte.MaxValue; }; return button; @@ -349,9 +468,9 @@ namespace HandyControl.Controls { BackColor = Brushes.Red; IsNeedUpdateInfo = false; - if (!SliderColor.IsMouseOver && !SliderOpacity.IsMouseOver) + if (!_sliderColor.IsMouseOver && !_sliderOpacity.IsMouseOver) { - SliderColor.Value = 0; + _sliderColor.Value = 0; } IsNeedUpdateInfo = true; } @@ -365,9 +484,9 @@ namespace HandyControl.Controls { BackColor = Brushes.Red; IsNeedUpdateInfo = false; - if (!SliderColor.IsMouseOver && !SliderOpacity.IsMouseOver) + if (!_sliderColor.IsMouseOver && !_sliderOpacity.IsMouseOver) { - SliderColor.Value = 0; + _sliderColor.Value = 0; } IsNeedUpdateInfo = true; } @@ -415,20 +534,20 @@ namespace HandyControl.Controls var scale = sub / 255.0; var scaleTotal = cIndex - direc + scale; IsNeedUpdateInfo = false; - if (!SliderColor.IsMouseOver && !SliderOpacity.IsMouseOver) + if (!_sliderColor.IsMouseOver && !_sliderOpacity.IsMouseOver) { - SliderColor.Value = scaleTotal; + _sliderColor.Value = scaleTotal; } IsNeedUpdateInfo = true; } } - var matrix = BorderPicker.RenderTransform.Value; + var matrix = _borderPicker.RenderTransform.Value; var x = max == 0 ? 0 : (1 - min / (double)max) * ColorPanelWidth; var y = (1 - max / 255.0) * ColorPanelHeight; if (_isNeedUpdatePicker) { - BorderPicker.RenderTransform = new MatrixTransform(matrix.M11, matrix.M12, matrix.M21, matrix.M22, x, y); + _borderPicker.RenderTransform = new MatrixTransform(matrix.M11, matrix.M12, matrix.M21, matrix.M22, x, y); } } @@ -441,7 +560,7 @@ namespace HandyControl.Controls var color = range.GetColor(sub); BackColor = new SolidColorBrush(color); - var matrix = BorderPicker.RenderTransform.Value; + var matrix = _borderPicker.RenderTransform.Value; _isNeedUpdatePicker = false; UpdateColorWhenDrag(new Point(matrix.OffsetX, matrix.OffsetY)); _isNeedUpdatePicker = true; @@ -451,12 +570,12 @@ namespace HandyControl.Controls { if (!_isLoaded || !IsNeedUpdateInfo) return; var color = SelectedBrush.Color; - SelectedBrush = new SolidColorBrush(Color.FromArgb((byte)SliderOpacity.Value, color.R, color.G, color.B)); + SelectedBrush = new SolidColorBrush(Color.FromArgb((byte)_sliderOpacity.Value, color.R, color.G, color.B)); } private void MouseDragElementBehavior_OnDragging(object sender, MouseEventArgs e) { - var p = e.GetPosition(BorderColor); + var p = e.GetPosition(_borderColor); _isOnDragging = true; UpdateColorWhenDrag(p); _isOnDragging = false; @@ -467,7 +586,7 @@ namespace HandyControl.Controls /// private void UpdateColorWhenDrag(Point p) { - var matrix = BorderPicker.RenderTransform.Value; + var matrix = _borderPicker.RenderTransform.Value; if (p.X < 0) { @@ -489,7 +608,7 @@ namespace HandyControl.Controls if (_isNeedUpdatePicker) { - BorderPicker.RenderTransform = new MatrixTransform(matrix.M11, matrix.M12, matrix.M21, matrix.M22, p.X, p.Y); + _borderPicker.RenderTransform = new MatrixTransform(matrix.M11, matrix.M12, matrix.M21, matrix.M22, p.X, p.Y); } var scaleX = p.X / ColorPanelWidth; @@ -502,15 +621,16 @@ namespace HandyControl.Controls var subG = colorYLeft.G - colorYRight.G; var subB = colorYLeft.B - colorYRight.B; - var color = Color.FromArgb((byte)SliderOpacity.Value, (byte)(colorYLeft.R - subR * scaleX), + var color = Color.FromArgb((byte)_sliderOpacity.Value, (byte)(colorYLeft.R - subR * scaleX), (byte)(colorYLeft.G - subG * scaleX), (byte)(colorYLeft.B - subB * scaleX)); SelectedBrush = new SolidColorBrush(color); } - private void MouseDragElementBehavior_OnDragFinished(object sender, MouseEventArgs e) => BorderDrag.RenderTransform = new MatrixTransform(); + private void MouseDragElementBehavior_OnDragFinished(object sender, MouseEventArgs e) => _borderDrag.RenderTransform = new MatrixTransform(); private void ButtonSwitch_OnClick(object sender, RoutedEventArgs e) => ColorType++; + // ReSharper disable once UnusedParameter.Local private void NumericUpDownRgb_OnValueChanged(object sender, FunctionEventArgs e) { if (!_isLoaded || !IsNeedUpdateInfo) return; @@ -542,8 +662,8 @@ namespace HandyControl.Controls } } - private void ButtonSure_OnClick(object sender, RoutedEventArgs e) - => RaiseEvent(new FunctionEventArgs(ColorSelectedEvent, this) + private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e) + => RaiseEvent(new FunctionEventArgs(SelectedColorChangedEvent, this) { Info = SelectedBrush.Color }); diff --git a/HandyControl/Controls/Picker/ColorPicker.xaml b/HandyControl/Controls/Picker/ColorPicker.xaml deleted file mode 100644 index 3ca152cb..00000000 --- a/HandyControl/Controls/Picker/ColorPicker.xaml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public static class ControlCommands { + /// + /// 切换 + /// + public static RoutedCommand Switch { get; } = new RoutedCommand("Switch", typeof(ControlCommands)); + /// /// 右转 /// diff --git a/HandyControl/Themes/Styles/Button.xaml b/HandyControl/Themes/Styles/Button.xaml index bf8d5964..a0a3b426 100644 --- a/HandyControl/Themes/Styles/Button.xaml +++ b/HandyControl/Themes/Styles/Button.xaml @@ -45,11 +45,11 @@ - + diff --git a/HandyControl/Themes/Styles/ColorPicker.xaml b/HandyControl/Themes/Styles/ColorPicker.xaml index 825650eb..0f3e5c0f 100644 --- a/HandyControl/Themes/Styles/ColorPicker.xaml +++ b/HandyControl/Themes/Styles/ColorPicker.xaml @@ -1,4 +1,116 @@  - + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:langs="clr-namespace:HandyControl.Properties.Langs" + xmlns:controls="clr-namespace:HandyControl.Controls" + xmlns:interactivity="clr-namespace:HandyControl.Interactivity"> + + + + + + + + + + \ No newline at end of file