From 9daa1a6ee16e7d7b91a6202463a1c8e08dc2d305 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Wed, 3 Oct 2018 21:27:15 +0800 Subject: [PATCH] update to v1.3.0 --- ChangeLog.txt | 10 + HandyControl/Controls/Attach/InfoElement.cs | 30 + HandyControl/Controls/CirclePanel.cs | 69 ++ HandyControl/Controls/Clock.cs | 418 ++++++++++++ HandyControl/Controls/ClockRadioButton.cs | 11 + HandyControl/Controls/Growl.xaml | 5 +- HandyControl/Controls/Info/InfoControl.cs | 2 +- .../Controls/Info/InfoNumericUpDown.xaml | 19 +- .../Controls/Info/InfoNumericUpDown.xaml.cs | 22 +- HandyControl/Controls/Info/InfoTextBox.xaml | 29 +- .../Controls/Info/InfoTextBox.xaml.cs | 2 +- HandyControl/Controls/Steps/StepBar.xaml.cs | 8 +- HandyControl/Controls/Steps/StepItem.xaml.cs | 4 +- HandyControl/Controls/TimePicker.cs | 625 ++++++++++++++++++ HandyControl/Controls/WatermarkTextBox.cs | 77 +++ HandyControl/Data/BooleanBoxes.cs | 13 + HandyControl/Data/FunctionEventArgs!1.cs | 5 + HandyControl/HandyControl.csproj | 31 + HandyControl/Interactivity/ControlCommands.cs | 35 + HandyControl/Interactivity/EventToCommand.cs | 194 ++++++ .../Interactivity/IEventArgsConverter.cs | 31 + .../Interactivity/RoutedEventTrigger.cs | 29 + HandyControl/Properties/AssemblyInfo.cs | 6 +- .../Properties/Langs/Lang.Designer.cs | 18 + HandyControl/Properties/Langs/Lang.en.resx | 6 + HandyControl/Properties/Langs/Lang.resx | 6 + HandyControl/Themes/Styles/Button.xaml | 2 +- HandyControl/Themes/Styles/Calendar.xaml | 241 +++++++ HandyControl/Themes/Styles/Clock.xaml | 105 +++ HandyControl/Themes/Styles/DatePicker.xaml | 62 ++ HandyControl/Themes/Styles/Style.xaml | 7 +- HandyControl/Themes/Styles/TextBox.xaml | 30 + HandyControl/Themes/Styles/TimePicker.xaml | 41 ++ HandyControl/Tools/ArithmeticHelper.cs | 8 + .../Converter/String2VisibilityConverter.cs | 4 +- .../Converter/String2VisibilityReConverter.cs | 4 +- HandyControl/Tools/ValidateHelper.cs | 19 + HandyControlDemo/Data/MessageToken.cs | 8 + HandyControlDemo/Data/MessageToken.tt | 8 +- HandyControlDemo/HandyControlDemo.csproj | 28 + HandyControlDemo/Properties/AssemblyInfo.cs | 6 +- .../Properties/Langs/Lang.Designer.cs | 20 +- .../Properties/Langs/Lang.en.resx | 8 +- HandyControlDemo/Properties/Langs/Lang.resx | 8 +- .../Resources/Themes/Styles/Label.xaml | 6 +- .../UserControl/Controls/ClockDemoCtl.xaml | 9 + .../UserControl/Controls/ClockDemoCtl.xaml.cs | 14 + .../Controls/ColorPickerDemoCtl.xaml | 7 +- .../Controls/DatePickerDemoCtl.xaml | 9 + .../Controls/DatePickerDemoCtl.xaml.cs | 14 + .../Controls/TimePickerDemoCtl.xaml | 9 + .../Controls/TimePickerDemoCtl.xaml.cs | 14 + .../UserControl/Main/LeftMainContent.xaml | 6 +- .../UserControl/Styles/CalendarDemoCtl.xaml | 9 + .../Styles/CalendarDemoCtl.xaml.cs | 14 + .../UserControl/Styles/DatePickerDemoCtl.xaml | 10 + .../Styles/DatePickerDemoCtl.xaml.cs | 14 + README.md | 18 +- Resources/Calendar.jpg | Bin 0 -> 10200 bytes Resources/Clock.jpg | Bin 0 -> 6643 bytes 60 files changed, 2391 insertions(+), 76 deletions(-) create mode 100644 HandyControl/Controls/Attach/InfoElement.cs create mode 100644 HandyControl/Controls/CirclePanel.cs create mode 100644 HandyControl/Controls/Clock.cs create mode 100644 HandyControl/Controls/ClockRadioButton.cs create mode 100644 HandyControl/Controls/TimePicker.cs create mode 100644 HandyControl/Controls/WatermarkTextBox.cs create mode 100644 HandyControl/Data/BooleanBoxes.cs create mode 100644 HandyControl/Interactivity/EventToCommand.cs create mode 100644 HandyControl/Interactivity/IEventArgsConverter.cs create mode 100644 HandyControl/Interactivity/RoutedEventTrigger.cs create mode 100644 HandyControl/Themes/Styles/Calendar.xaml create mode 100644 HandyControl/Themes/Styles/Clock.xaml create mode 100644 HandyControl/Themes/Styles/DatePicker.xaml create mode 100644 HandyControl/Themes/Styles/TextBox.xaml create mode 100644 HandyControl/Themes/Styles/TimePicker.xaml create mode 100644 HandyControl/Tools/ValidateHelper.cs create mode 100644 HandyControlDemo/UserControl/Controls/ClockDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Controls/ClockDemoCtl.xaml.cs create mode 100644 HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml.cs create mode 100644 HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml.cs create mode 100644 HandyControlDemo/UserControl/Styles/CalendarDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Styles/CalendarDemoCtl.xaml.cs create mode 100644 HandyControlDemo/UserControl/Styles/DatePickerDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Styles/DatePickerDemoCtl.xaml.cs create mode 100644 Resources/Calendar.jpg create mode 100644 Resources/Clock.jpg diff --git a/ChangeLog.txt b/ChangeLog.txt index 21ac03f4..796b7fc2 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,13 @@ +2018.10.03 Version 1.3.0 +* new controls + - add Clock + - add TimePicker + - add CirclePanel + +* new style + - add Calendar + - add DataPicker + 2018.09.18 Version 1.2.2 * new controls - add StepBar diff --git a/HandyControl/Controls/Attach/InfoElement.cs b/HandyControl/Controls/Attach/InfoElement.cs new file mode 100644 index 00000000..4af45fa7 --- /dev/null +++ b/HandyControl/Controls/Attach/InfoElement.cs @@ -0,0 +1,30 @@ +using System.Windows; +using HandyControl.Data.Enum; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + public class InfoElement : DependencyObject + { + public static readonly DependencyProperty TitleProperty = DependencyProperty.RegisterAttached( + "Title", typeof(string), typeof(InfoElement), new PropertyMetadata(default(string))); + + public static void SetTitle(DependencyObject element, string value) => element.SetValue(TitleProperty, value); + + public static string GetTitle(DependencyObject element) => (string) element.GetValue(TitleProperty); + + public static readonly DependencyProperty RequiredProperty = DependencyProperty.RegisterAttached( + "Required", typeof(bool), typeof(InfoElement), new PropertyMetadata(default(bool))); + + public static void SetRequired(DependencyObject element, bool value) => element.SetValue(RequiredProperty, value); + + public static bool GetRequired(DependencyObject element) => (bool)element.GetValue(RequiredProperty); + + public static readonly DependencyProperty TitleAlignmentProperty = DependencyProperty.RegisterAttached( + "TitleAlignment", typeof(TitleAlignment), typeof(InfoElement), new PropertyMetadata(default(TitleAlignment))); + + public static void SetTitleAlignment(DependencyObject element, TitleAlignment value) => element.SetValue(TitleAlignmentProperty, value); + + public static TitleAlignment GetTitleAlignment(DependencyObject element) => (TitleAlignment) element.GetValue(TitleAlignmentProperty); + } +} \ No newline at end of file diff --git a/HandyControl/Controls/CirclePanel.cs b/HandyControl/Controls/CirclePanel.cs new file mode 100644 index 00000000..ad766636 --- /dev/null +++ b/HandyControl/Controls/CirclePanel.cs @@ -0,0 +1,69 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace HandyControl.Controls +{ + public class CirclePanel : Panel + { + public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register( + "Diameter", typeof(double), typeof(CirclePanel), new PropertyMetadata(170.0)); + + public double Diameter + { + get => (double) GetValue(DiameterProperty); + set => SetValue(DiameterProperty, value); + } + + public static readonly DependencyProperty KeepVerticalProperty = DependencyProperty.Register( + "KeepVertical", typeof(bool), typeof(CirclePanel), new PropertyMetadata(default(bool))); + + public bool KeepVertical + { + get => (bool) GetValue(KeepVerticalProperty); + set => SetValue(KeepVerticalProperty, value); + } + + public static readonly DependencyProperty OffsetAngleProperty = DependencyProperty.Register( + "OffsetAngle", typeof(double), typeof(CirclePanel), new PropertyMetadata(default(double))); + + public double OffsetAngle + { + get => (double) GetValue(OffsetAngleProperty); + set => SetValue(OffsetAngleProperty, value); + } + + // ReSharper disable once RedundantAssignment + protected override Size MeasureOverride(Size availableSize) + { + if (Children.Count == 0) return new Size(Diameter, Diameter); + + availableSize = new Size(Diameter, Diameter); + var i = 0; + var perDeg = 360.0 / Children.Count; + var radius = Diameter / 2; + foreach (UIElement element in Children) + { + element.Measure(availableSize); + var centerX = element.DesiredSize.Width / 2.0; + var centerY = element.DesiredSize.Height / 2.0; + var angle = perDeg * i++ + OffsetAngle; + var transform = new RotateTransform + { + CenterX = centerX, + CenterY = centerY, + Angle = KeepVertical ? 0 : angle + }; + element.RenderTransform = transform; + var r = Math.PI * angle / 180.0; + var x = radius * Math.Cos(r); + var y = radius * Math.Sin(r); + var rectX = x + availableSize.Width / 2 - centerX; + var rectY = y + availableSize.Height / 2 - centerY; + element.Arrange(new Rect(rectX, rectY, element.DesiredSize.Width, element.DesiredSize.Height)); + } + return availableSize; + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Clock.cs b/HandyControl/Controls/Clock.cs new file mode 100644 index 00000000..b1b34cb0 --- /dev/null +++ b/HandyControl/Controls/Clock.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; +using HandyControl.Data; +using HandyControl.Tools; + +namespace HandyControl.Controls +{ + [TemplatePart(Name = ElementButtonAm, Type = typeof(RadioButton))] + [TemplatePart(Name = ElementButtonPm, Type = typeof(RadioButton))] + [TemplatePart(Name = ElementButtonConfirm, Type = typeof(Button))] + [TemplatePart(Name = ElementCanvas, Type = typeof(Canvas))] + [TemplatePart(Name = ElementBorderTitle, Type = typeof(Border))] + [TemplatePart(Name = ElementBorderClock, Type = typeof(Border))] + [TemplatePart(Name = ElementPanelNum, Type = typeof(CirclePanel))] + [TemplatePart(Name = ElementTimeStr, Type = typeof(TextBlock))] + public class Clock : Control + { + #region Constants + + private const string ElementButtonAm = "PART_ButtonAm"; + private const string ElementButtonPm = "PART_ButtonPm"; + private const string ElementButtonConfirm = "PART_ButtonConfirm"; + private const string ElementCanvas = "PART_Canvas"; + private const string ElementBorderTitle = "PART_BorderTitle"; + private const string ElementBorderClock = "PART_BorderClock"; + private const string ElementPanelNum = "PART_PanelNum"; + private const string ElementTimeStr = "PART_TimeStr"; + + #endregion Constants + + #region Data + + private RadioButton _buttonAm; + + private RadioButton _buttonPm; + + private Button _buttonConfirm; + + private Canvas _canvas; + + private Border _borderTitle; + + private Border _borderClock; + + private ClockRadioButton _currentButton; + + private RotateTransform _rotateTransformClock; + + private CirclePanel _circlePanel; + + private List _radioButtonList; + + private TextBlock _blockTime; + + private int _secValue; + + private bool _isLoaded; + + private bool _appliedTemplate; + + #endregion Data + + #region Public Events + + public static readonly RoutedEvent SelectedTimeChangedEvent = + EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Direct, + typeof(EventHandler>), typeof(Clock)); + + public event EventHandler> SelectedTimeChanged + { + add => AddHandler(SelectedTimeChangedEvent, value); + remove => RemoveHandler(SelectedTimeChangedEvent, value); + } + + public event EventHandler> DisplayTimeChanged; + + public event Action Confirmed; + + #endregion Public Events + + public Clock() + { + Loaded += (s, e) => + { + if (_isLoaded) return; + _isLoaded = true; + DisplayTime = DateTime.Now; + }; + } + + #region Public Properties + + public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register( + "SelectedTime", typeof(DateTime?), typeof(Clock), new PropertyMetadata(default(DateTime), OnSelectedTimeChanged)); + + private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (Clock)d; + var v = (DateTime?)e.NewValue; + ctl.OnSelectedTimeChanged(new FunctionEventArgs(SelectedTimeChangedEvent, ctl) + { + Info = v + }); + } + + public DateTime? SelectedTime + { + get => (DateTime?) GetValue(SelectedTimeProperty); + set => SetValue(SelectedTimeProperty, value); + } + + public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register( + "TimeFormat", typeof(string), typeof(Clock), new PropertyMetadata("HH:mm:ss")); + + public string TimeFormat + { + get => (string) GetValue(TimeFormatProperty); + set => SetValue(TimeFormatProperty, value); + } + + public static readonly DependencyProperty ClockRadioButtonStyleProperty = DependencyProperty.Register( + "ClockRadioButtonStyle", typeof(Style), typeof(Clock), new PropertyMetadata(default(Style))); + + public Style ClockRadioButtonStyle + { + get => (Style) GetValue(ClockRadioButtonStyleProperty); + set => SetValue(ClockRadioButtonStyleProperty, value); + } + + public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register( + "DisplayTime", typeof(DateTime), typeof(Clock), new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayTimeChanged)); + + private static void OnDisplayTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (Clock) d; + var v = (DateTime) e.NewValue; + ctl.Update(v); + ctl.OnDisplayTimeChanged(new FunctionEventArgs(v)); + } + + public DateTime DisplayTime + { + get => (DateTime) GetValue(DisplayTimeProperty); + set => SetValue(DisplayTimeProperty, value); + } + + internal static readonly DependencyProperty ShowConfirmButtonProperty = DependencyProperty.Register( + "ShowConfirmButton", typeof(bool), typeof(Clock), new PropertyMetadata(default(bool))); + + internal bool ShowConfirmButton + { + get => (bool)GetValue(ShowConfirmButtonProperty); + set => SetValue(ShowConfirmButtonProperty, value); + } + + private int SecValue + { + get => _secValue; + set + { + if (value < 0) + { + _secValue = 59; + } + else if (value > 59) + { + _secValue = 0; + } + else + { + _secValue = value; + } + } + } + + #endregion Public Properties + + #region Public Methods + + public override void OnApplyTemplate() + { + _appliedTemplate = false; + _buttonAm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonAm_OnClick)); + _buttonPm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPm_OnClick)); + _buttonConfirm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonConfirm_OnClick)); + _borderTitle?.RemoveHandler(MouseWheelEvent, new MouseWheelEventHandler(BorderTitle_OnMouseWheel)); + + if (_canvas != null) + { + _canvas.RemoveHandler(MouseWheelEvent, new MouseWheelEventHandler(MyCanvas_OnMouseWheel)); + _canvas.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(MyCanvas_OnClick)); + _canvas.RemoveHandler(MouseMoveEvent, new MouseEventHandler(MyCanvas_OnMouseMove)); + } + + base.OnApplyTemplate(); + + _buttonAm = GetTemplateChild(ElementButtonAm) as RadioButton; + _buttonPm = GetTemplateChild(ElementButtonPm) as RadioButton; + _buttonConfirm = GetTemplateChild(ElementButtonConfirm) as Button; + _borderTitle = GetTemplateChild(ElementBorderTitle) as Border; + _canvas = GetTemplateChild(ElementCanvas) as Canvas; + _borderClock = GetTemplateChild(ElementBorderClock) as Border; + _circlePanel = GetTemplateChild(ElementPanelNum) as CirclePanel; + _blockTime = GetTemplateChild(ElementTimeStr) as TextBlock; + + CheckNull(); + + _buttonAm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonAm_OnClick)); + _buttonPm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPm_OnClick)); + _buttonConfirm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonConfirm_OnClick)); + _borderTitle.AddHandler(MouseWheelEvent, new MouseWheelEventHandler(BorderTitle_OnMouseWheel)); + + _canvas.AddHandler(MouseWheelEvent, new MouseWheelEventHandler(MyCanvas_OnMouseWheel)); + _canvas.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(MyCanvas_OnClick)); + _canvas.AddHandler(MouseMoveEvent, new MouseEventHandler(MyCanvas_OnMouseMove)); + + _rotateTransformClock = new RotateTransform(); + _borderClock.RenderTransform = _rotateTransformClock; + + _radioButtonList = new List(); + for (var i = 0; i < 12; i++) + { + var num = i + 1; + var button = new ClockRadioButton + { + Num = num, + Content = num + }; + button.SetBinding(StyleProperty, new Binding(ClockRadioButtonStyleProperty.Name) { Source = this }); + _radioButtonList.Add(button); + _circlePanel.Children.Add(button); + } + + _appliedTemplate = true; + } + + #endregion Public Methods + + #region Protected Methods + + protected virtual void OnSelectedTimeChanged(FunctionEventArgs e) => RaiseEvent(e); + + protected virtual void OnDisplayTimeChanged(FunctionEventArgs e) + { + var handler = DisplayTimeChanged; + handler?.Invoke(this, e); + } + + #endregion Protected Methods + + #region Private Methods + + private void CheckNull() + { + + if (_buttonPm == null || _buttonAm == null || _buttonConfirm == null || _canvas == null || + _borderTitle == null || _borderClock == null || _circlePanel == null || + _blockTime == null) throw new Exception(); + } + + private void BorderTitle_OnMouseWheel(object sender, MouseWheelEventArgs e) + { + if (e.Delta < 0) + { + SecValue--; + Update(); + } + else + { + SecValue++; + Update(); + } + e.Handled = true; + } + + private void MyCanvas_OnMouseWheel(object sender, MouseWheelEventArgs e) + { + var value = (int)_rotateTransformClock.Angle; + if (e.Delta < 0) + { + value += 6; + } + else + { + value -= 6; + } + if (value < 0) + { + value = value + 360; + } + _rotateTransformClock.Angle = value; + + Update(); + e.Handled = true; + } + + private void MyCanvas_OnClick(object sender, RoutedEventArgs e) + { + _currentButton = e.OriginalSource as ClockRadioButton; + if (_currentButton != null) + { + Update(); + } + } + + private void MyCanvas_OnMouseMove(object sender, MouseEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + { + var value = ArithmeticHelper.CalAngle(new Point(85, 85), e.GetPosition(_canvas)) + 90; + if (value < 0) + { + value = value + 360; + } + value = value - value % 6; + _rotateTransformClock.Angle = value; + Update(); + } + } + + private void Update() + { + if (!_appliedTemplate) return; + var hValue = _currentButton.Num; + if (_buttonPm.IsChecked == true) + { + hValue += 12; + if (hValue == 24) hValue = 12; + } + else if (hValue == 12) + { + hValue = 0; + } + if (hValue == 12 && _buttonAm.IsChecked == true) + { + _buttonPm.IsChecked = true; + _buttonAm.IsChecked = false; + } + + if (_blockTime != null) + { + DisplayTime = GetDisplayTime(); + _blockTime.Text = DisplayTime.ToString(TimeFormat); + } + } + + /// + /// 更新 + /// + /// + private void Update(DateTime time) + { + if (!_appliedTemplate) return; + var h = time.Hour; + var m = time.Minute; + + if (h >= 12) + { + _buttonPm.IsChecked = true; + _buttonAm.IsChecked = false; + } + else + { + _buttonPm.IsChecked = false; + _buttonAm.IsChecked = true; + } + + _rotateTransformClock.Angle = m * 6; + + var hRest = h % 12; + if (hRest == 0) hRest = 12; + var ctl = _radioButtonList[hRest-1]; + ctl.IsChecked = true; + ctl.RaiseEvent(new RoutedEventArgs { RoutedEvent = ButtonBase.ClickEvent }); + + _secValue = time.Second; + Update(); + } + + private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e) + { + SelectedTime = DisplayTime; + Confirmed?.Invoke(); + } + + /// + /// 获取显示时间 + /// + /// + private DateTime GetDisplayTime() + { + var hValue = _currentButton.Num; + if (_buttonPm.IsChecked == true) + { + hValue += 12; + if (hValue == 24) hValue = 12; + } + else if (hValue == 12) + { + hValue = 0; + } + var now = DateTime.Now; + return new DateTime(now.Year, now.Month, now.Day, hValue, (int)Math.Abs(_rotateTransformClock.Angle) % 360 / 6, _secValue); + } + + private void ButtonAm_OnClick(object sender, RoutedEventArgs e) => Update(); + + private void ButtonPm_OnClick(object sender, RoutedEventArgs e) => Update(); + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/HandyControl/Controls/ClockRadioButton.cs b/HandyControl/Controls/ClockRadioButton.cs new file mode 100644 index 00000000..f6c030c1 --- /dev/null +++ b/HandyControl/Controls/ClockRadioButton.cs @@ -0,0 +1,11 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace HandyControl.Controls +{ + public class ClockRadioButton : RadioButton + { + public int Num { get; set; } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Growl.xaml b/HandyControl/Controls/Growl.xaml index f19a97b7..93e91112 100644 --- a/HandyControl/Controls/Growl.xaml +++ b/HandyControl/Controls/Growl.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:langs="clr-namespace:HandyControl.Properties.Langs" mc:Ignorable="d" MinHeight="60" Name="UserControlThis" @@ -50,10 +51,10 @@ diff --git a/HandyControl/Controls/Info/InfoControl.cs b/HandyControl/Controls/Info/InfoControl.cs index bbff8d29..2b7eace3 100644 --- a/HandyControl/Controls/Info/InfoControl.cs +++ b/HandyControl/Controls/Info/InfoControl.cs @@ -11,7 +11,7 @@ using HandyControl.Tools.Extension; // ReSharper disable once CheckNamespace namespace HandyControl.Controls { - public abstract class InfoControl : UserControl + internal abstract class InfoControl : UserControl { private bool _isFocused; diff --git a/HandyControl/Controls/Info/InfoNumericUpDown.xaml b/HandyControl/Controls/Info/InfoNumericUpDown.xaml index e9c40029..c1f94499 100644 --- a/HandyControl/Controls/Info/InfoNumericUpDown.xaml +++ b/HandyControl/Controls/Info/InfoNumericUpDown.xaml @@ -1,10 +1,11 @@  - + @@ -54,9 +55,9 @@ - + - + diff --git a/HandyControl/Controls/Info/InfoNumericUpDown.xaml.cs b/HandyControl/Controls/Info/InfoNumericUpDown.xaml.cs index 2195a6e9..de4606f6 100644 --- a/HandyControl/Controls/Info/InfoNumericUpDown.xaml.cs +++ b/HandyControl/Controls/Info/InfoNumericUpDown.xaml.cs @@ -3,6 +3,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media.Animation; using HandyControl.Data; +using HandyControl.Tools; // ReSharper disable once CheckNamespace namespace HandyControl.Controls @@ -10,7 +11,7 @@ namespace HandyControl.Controls /// /// InfoNumericUpDown.xaml 的交互逻辑 /// - public partial class InfoNumericUpDown + internal partial class InfoNumericUpDown { public InfoNumericUpDown() { @@ -44,7 +45,7 @@ namespace HandyControl.Controls var max = (double)value; if (max < info.Minimum) max = info.Minimum; return max; - }), ValidateValueCallback); + }), ValidateHelper.IsInRangeOfDouble); /// /// 最大值 @@ -69,7 +70,7 @@ namespace HandyControl.Controls var min = (double)value; if (min > info.Maximum) min = info.Maximum; return min; - }), ValidateValueCallback); + }), ValidateHelper.IsInRangeOfDouble); /// /// 最小值 @@ -102,18 +103,7 @@ namespace HandyControl.Controls if (current > info.Maximum) current = info.Maximum; return current; - }), ValidateValueCallback); - - /// - /// 值验证回调 - /// - /// - /// - private static bool ValidateValueCallback(object value) - { - var v = (double)value; - return !(double.IsNaN(v) || double.IsInfinity(v)); - } + }), ValidateHelper.IsInRangeOfDouble); /// /// 当前值 @@ -128,7 +118,7 @@ namespace HandyControl.Controls /// 最小改变值 /// public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register( - "SmallChange", typeof(double), typeof(InfoNumericUpDown), new PropertyMetadata(1.0), ValidateValueCallback); + "SmallChange", typeof(double), typeof(InfoNumericUpDown), new PropertyMetadata(1.0), ValidateHelper.IsInRangeOfDouble); /// /// 最小改变值 diff --git a/HandyControl/Controls/Info/InfoTextBox.xaml b/HandyControl/Controls/Info/InfoTextBox.xaml index 4889a9e2..d3e02923 100644 --- a/HandyControl/Controls/Info/InfoTextBox.xaml +++ b/HandyControl/Controls/Info/InfoTextBox.xaml @@ -1,15 +1,16 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:controls="clr-namespace:HandyControl.Controls" + x:ClassModifier="internal" + mc:Ignorable="d" + FontSize="14" + MinHeight="24" + Height="36" + MaxHeight="54" + d:DesignWidth="300"> @@ -43,7 +44,7 @@ - + @@ -52,9 +53,9 @@ - + - + diff --git a/HandyControl/Controls/Info/InfoTextBox.xaml.cs b/HandyControl/Controls/Info/InfoTextBox.xaml.cs index 1e3c114d..c633d476 100644 --- a/HandyControl/Controls/Info/InfoTextBox.xaml.cs +++ b/HandyControl/Controls/Info/InfoTextBox.xaml.cs @@ -7,7 +7,7 @@ namespace HandyControl.Controls /// /// InfoTextBox.xaml 的交互逻辑 /// - public partial class InfoTextBox + internal partial class InfoTextBox { /// /// 可输入的最大字符数 diff --git a/HandyControl/Controls/Steps/StepBar.xaml.cs b/HandyControl/Controls/Steps/StepBar.xaml.cs index 0359bea6..62e5901a 100644 --- a/HandyControl/Controls/Steps/StepBar.xaml.cs +++ b/HandyControl/Controls/Steps/StepBar.xaml.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Markup; @@ -50,6 +51,11 @@ namespace HandyControl.Controls UniformGridMain.Children.Add(item); index++; } + + if (list.FirstOrDefault() is StepItem stepItem) + { + stepItem.Status = false; + } } protected override void OnRender(DrawingContext drawingContext) @@ -63,8 +69,6 @@ namespace HandyControl.Controls ProgressBarBack.Maximum = colCount - 1; } - - public void Next() { StepIndex++; diff --git a/HandyControl/Controls/Steps/StepItem.xaml.cs b/HandyControl/Controls/Steps/StepItem.xaml.cs index 15ca33b2..1b0183df 100644 --- a/HandyControl/Controls/Steps/StepItem.xaml.cs +++ b/HandyControl/Controls/Steps/StepItem.xaml.cs @@ -57,11 +57,11 @@ namespace HandyControl.Controls { if (Status == true) { - Foreground = TryFindResource("PrimaryBrush") as Brush; + Foreground = TryFindResource("PrimaryTextBrush") as Brush; } else if (Status == false) { - Foreground = TryFindResource("PrimaryTextBrush") as Brush; + Foreground = TryFindResource("PrimaryBrush") as Brush; } else { diff --git a/HandyControl/Controls/TimePicker.cs b/HandyControl/Controls/TimePicker.cs new file mode 100644 index 00000000..28605a8c --- /dev/null +++ b/HandyControl/Controls/TimePicker.cs @@ -0,0 +1,625 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Threading; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + [TemplatePart(Name = ElementRoot, Type = typeof(Grid))] + [TemplatePart(Name = ElementTextBox, Type = typeof(WatermarkTextBox))] + [TemplatePart(Name = ElementButton, Type = typeof(Button))] + [TemplatePart(Name = ElementPopup, Type = typeof(Popup))] + [TemplatePart(Name = ElementClock, Type = typeof(Clock))] + public class TimePicker : Control + { + #region Constants + + private const string ElementRoot = "PART_Root"; + private const string ElementTextBox = "PART_TextBox"; + private const string ElementButton = "PART_Button"; + private const string ElementPopup = "PART_Popup"; + private const string ElementClock = "PART_Clock"; + + #endregion Constants + + #region Data + + private Clock _clock; + private string _defaultText; + private ButtonBase _dropDownButton; + private Popup _popUp; + private bool _disablePopupReopen; + private WatermarkTextBox _textBox; + private IDictionary _isHandlerSuspended; + private DateTime? _originalSelectedTime; + + #endregion Data + + #region Public Events + + public static readonly RoutedEvent SelectedTimeChangedEvent = + EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Direct, + typeof(EventHandler>), typeof(TimePicker)); + + public event EventHandler> SelectedTimeChanged + { + add => AddHandler(SelectedTimeChangedEvent, value); + remove => RemoveHandler(SelectedTimeChangedEvent, value); + } + + public event RoutedEventHandler ClockClosed; + + public event RoutedEventHandler ClockOpened; + + #endregion Public Events + + static TimePicker() + { + EventManager.RegisterClassHandler(typeof(TimePicker), GotFocusEvent, new RoutedEventHandler(OnGotFocus)); + KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); + KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(false)); + } + + #region Public Properties + + #region TimeFormat + + public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register( + "TimeFormat", typeof(string), typeof(TimePicker), new PropertyMetadata("HH:mm:ss")); + + public string TimeFormat + { + get => (string)GetValue(TimeFormatProperty); + set => SetValue(TimeFormatProperty, value); + } + + #endregion TimeFormat + + #region ClockStyle + + public Style ClockStyle + { + get => (Style)GetValue(ClockStyleProperty); + set => SetValue(ClockStyleProperty, value); + } + + public static readonly DependencyProperty ClockStyleProperty = DependencyProperty.Register("ClockStyle", typeof(Style), typeof(TimePicker)); + + #endregion CalendarStyle + + #region DisplayTime + + public DateTime DisplayTime + { + get => (DateTime)GetValue(DisplayTimeProperty); + set => SetValue(DisplayTimeProperty, value); + } + + public static readonly DependencyProperty DisplayTimeProperty = + DependencyProperty.Register( + "DisplayTime", + typeof(DateTime), + typeof(TimePicker), + new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceDisplayTime)); + + private static object CoerceDisplayTime(DependencyObject d, object value) + { + var dp = (TimePicker)d; + dp._clock.DisplayTime = (DateTime)value; + return dp._clock.DisplayTime; + } + + #endregion DisplayTime + + #region IsDropDownOpen + + public bool IsDropDownOpen + { + get => (bool)GetValue(IsDropDownOpenProperty); + set => SetValue(IsDropDownOpenProperty, value); + } + + public static readonly DependencyProperty IsDropDownOpenProperty = + DependencyProperty.Register( + "IsDropDownOpen", + typeof(bool), + typeof(TimePicker), + new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsDropDownOpenChanged, OnCoerceIsDropDownOpen)); + + private static object OnCoerceIsDropDownOpen(DependencyObject d, object baseValue) => d is TimePicker dp && !dp.IsEnabled ? false : baseValue; + + private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var dp = d as TimePicker; + + var newValue = (bool)e.NewValue; + if (dp?._popUp != null && dp._popUp.IsOpen != newValue) + { + dp._popUp.IsOpen = newValue; + if (newValue) + { + dp._originalSelectedTime = dp.SelectedTime; + + dp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate + { + dp._clock.Focus(); + }); + } + } + } + + #endregion IsDropDownOpen + + #region SelectedTime + + public DateTime? SelectedTime + { + get => (DateTime?)GetValue(SelectedTimeProperty); + set => SetValue(SelectedTimeProperty, value); + } + + public static readonly DependencyProperty SelectedTimeProperty = + DependencyProperty.Register( + "SelectedTime", + typeof(DateTime?), + typeof(TimePicker), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedTimeChanged, CoerceSelectedTime)); + + private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (!(d is TimePicker dp)) return; + + if (dp.SelectedTime.HasValue) + { + var time = dp.SelectedTime.Value; + dp.SetTextInternal(dp.DateTimeToString(time)); + } + + dp.RaiseEvent(new FunctionEventArgs(SelectedTimeChangedEvent, dp) + { + Info = dp.SelectedTime + }); + } + + private static object CoerceSelectedTime(DependencyObject d, object value) + { + var dp = (TimePicker)d; + dp._clock.SelectedTime = (DateTime?)value; + return dp._clock.SelectedTime; + } + + #endregion SelectedDate + + #region Text + + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register( + "Text", + typeof(string), + typeof(TimePicker), + new FrameworkPropertyMetadata(string.Empty, OnTextChanged)); + + private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is TimePicker dp && !dp.IsHandlerSuspended(TextProperty)) + { + if (e.NewValue is string newValue) + { + if (dp._textBox != null) + { + dp._textBox.Text = newValue; + } + else + { + dp._defaultText = newValue; + } + + dp.SetSelectedTime(); + } + else + { + dp.SetValueNoCallback(SelectedTimeProperty, null); + } + } + } + + /// + /// Sets the local Text property without breaking bindings + /// + /// + private void SetTextInternal(string value) + { + SetCurrentValue(TextProperty, value); + } + + #endregion Text + + #endregion Public Properties + + #region Public Methods + + public override void OnApplyTemplate() + { + if (_popUp != null) + { + _popUp.RemoveHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(PopUp_PreviewMouseLeftButtonDown)); + _popUp.Opened -= PopUp_Opened; + _popUp.Closed -= PopUp_Closed; + _popUp.Child = null; + } + + if (_dropDownButton != null) + { + _dropDownButton.Click -= DropDownButton_Click; + _dropDownButton.RemoveHandler(MouseLeaveEvent, new MouseEventHandler(DropDownButton_MouseLeave)); + } + + if (_textBox != null) + { + _textBox.RemoveHandler(KeyDownEvent, new KeyEventHandler(TextBox_KeyDown)); + _textBox.RemoveHandler(TextBoxBase.TextChangedEvent, new TextChangedEventHandler(TextBox_TextChanged)); + _textBox.RemoveHandler(LostFocusEvent, new RoutedEventHandler(TextBox_LostFocus)); + } + + if (_clock != null) + { + _clock.RemoveHandler(Clock.SelectedTimeChangedEvent, new EventHandler>(Clock_SelectedTimeChangedEvent)); + _clock.Confirmed -= Clock_Confirmed; + } + + base.OnApplyTemplate(); + + _clock = GetTemplateChild(ElementClock) as Clock; + _popUp = GetTemplateChild(ElementPopup) as Popup; + _dropDownButton = GetTemplateChild(ElementButton) as Button; + _textBox = GetTemplateChild(ElementTextBox) as WatermarkTextBox; + + CheckNull(); + + _clock.ApplyTemplate(); + _clock.AddHandler(Clock.SelectedTimeChangedEvent, new EventHandler>(Clock_SelectedTimeChangedEvent)); + _clock.Confirmed += Clock_Confirmed; + + _popUp.AddHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(PopUp_PreviewMouseLeftButtonDown)); + _popUp.Opened += PopUp_Opened; + _popUp.Closed += PopUp_Closed; + _popUp.Child = _clock; + + if (IsDropDownOpen) + { + _popUp.IsOpen = true; + } + + _dropDownButton.Click += DropDownButton_Click; + _dropDownButton.AddHandler(MouseLeaveEvent, new MouseEventHandler(DropDownButton_MouseLeave), true); + if (SelectedTime == null) + { + _textBox.Text = DateTime.Now.ToString(TimeFormat); + } + _textBox.AddHandler(KeyDownEvent, new KeyEventHandler(TextBox_KeyDown), true); + _textBox.AddHandler(TextBoxBase.TextChangedEvent, new TextChangedEventHandler(TextBox_TextChanged), true); + _textBox.AddHandler(LostFocusEvent, new RoutedEventHandler(TextBox_LostFocus), true); + + if (SelectedTime == null) + { + if (!string.IsNullOrEmpty(_defaultText)) + { + _textBox.Text = _defaultText; + SetSelectedTime(); + } + } + else + { + _textBox.Text = DateTimeToString((DateTime)SelectedTime); + } + + if (_originalSelectedTime == null) + { + _originalSelectedTime = DateTime.Now; + } + SetCurrentValue(DisplayTimeProperty, _originalSelectedTime); + } + + public override string ToString() => SelectedTime?.ToString(TimeFormat) ?? string.Empty; + + #endregion + + #region Protected Methods + + protected virtual void OnClockClosed(RoutedEventArgs e) + { + var handler = ClockClosed; + handler?.Invoke(this, e); + } + + protected virtual void OnClockOpened(RoutedEventArgs e) + { + var handler = ClockOpened; + handler?.Invoke(this, e); + } + + #endregion Protected Methods + + #region Private Methods + + private void CheckNull() + { + if (_clock == null || _dropDownButton == null || _popUp == null || _textBox == null) throw new Exception(); + } + + private void TextBox_LostFocus(object sender, RoutedEventArgs e) + { + SetSelectedTime(); + } + + private void SetIsHandlerSuspended(DependencyProperty property, bool value) + { + if (value) + { + if (_isHandlerSuspended == null) + { + _isHandlerSuspended = new Dictionary(2); + } + + _isHandlerSuspended[property] = true; + } + else + { + _isHandlerSuspended?.Remove(property); + } + } + + private void SetValueNoCallback(DependencyProperty property, object value) + { + SetIsHandlerSuspended(property, true); + try + { + SetCurrentValue(property, value); + } + finally + { + SetIsHandlerSuspended(property, false); + } + } + + private void TextBox_TextChanged(object sender, TextChangedEventArgs e) + { + SetValueNoCallback(TextProperty, _textBox.Text); + } + + private bool ProcessTimePickerKey(KeyEventArgs e) + { + switch (e.Key) + { + case Key.System: + { + switch (e.SystemKey) + { + case Key.Down: + { + if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) + { + TogglePopUp(); + return true; + } + + break; + } + } + + break; + } + + case Key.Enter: + { + SetSelectedTime(); + return true; + } + } + + return false; + } + + private void TextBox_KeyDown(object sender, KeyEventArgs e) + { + e.Handled = ProcessTimePickerKey(e) || e.Handled; + } + + private void DropDownButton_MouseLeave(object sender, MouseEventArgs e) + { + _disablePopupReopen = false; + } + + private bool IsHandlerSuspended(DependencyProperty property) + { + return _isHandlerSuspended != null && _isHandlerSuspended.ContainsKey(property); + } + + private void PopUp_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (sender is Popup popup && !popup.StaysOpen) + { + if (_dropDownButton?.InputHitTest(e.GetPosition(_dropDownButton)) != null) + { + _disablePopupReopen = true; + } + } + } + + private void Clock_SelectedTimeChangedEvent(object sender, FunctionEventArgs e) => SelectedTime = e.Info; + + private void Clock_Confirmed() => TogglePopUp(); + + private void PopUp_Opened(object sender, EventArgs e) + { + if (!IsDropDownOpen) + { + SetCurrentValue(IsDropDownOpenProperty, BooleanBoxes.TrueBox); + } + + _clock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); + + OnClockOpened(new RoutedEventArgs()); + } + + private void PopUp_Closed(object sender, EventArgs e) + { + if (IsDropDownOpen) + { + SetCurrentValue(IsDropDownOpenProperty, BooleanBoxes.FalseBox); + } + + if (_clock.IsKeyboardFocusWithin) + { + MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); + } + + OnClockClosed(new RoutedEventArgs()); + } + + private void DropDownButton_Click(object sender, RoutedEventArgs e) => TogglePopUp(); + + private void TogglePopUp() + { + if (IsDropDownOpen) + { + SetCurrentValue(IsDropDownOpenProperty, BooleanBoxes.FalseBox); + } + else + { + if (_disablePopupReopen) + { + _disablePopupReopen = false; + } + else + { + SetSelectedTime(); + SetCurrentValue(IsDropDownOpenProperty, BooleanBoxes.TrueBox); + } + } + } + + private void SafeSetText(string s) + { + if (string.Compare(Text, s, StringComparison.Ordinal) != 0) + { + SetCurrentValue(TextProperty, s); + } + } + + private DateTime? ParseText(string text) + { + try + { + return DateTime.Parse(text); + } + catch + { + // ignored + } + + return null; + } + + private DateTime? SetTextBoxValue(string s) + { + if (string.IsNullOrEmpty(s)) + { + SafeSetText(s); + return SelectedTime; + } + + var d = ParseText(s); + + if (d != null) + { + SafeSetText(DateTimeToString((DateTime)d)); + return d; + } + + if (SelectedTime != null) + { + var newtext = DateTimeToString((DateTime) SelectedTime); + SafeSetText(newtext); + return SelectedTime; + } + SafeSetText(DateTimeToString(DisplayTime)); + return DisplayTime; + } + + private void SetSelectedTime() + { + if (_textBox != null) + { + if (!string.IsNullOrEmpty(_textBox.Text)) + { + var s = _textBox.Text; + + if (SelectedTime != null) + { + var selectedTime = DateTimeToString(SelectedTime.Value); + + if (string.Compare(selectedTime, s, StringComparison.Ordinal) == 0) + { + return; + } + } + + var d = SetTextBoxValue(s); + if (!SelectedTime.Equals(d)) + { + SetCurrentValue(SelectedTimeProperty, d); + SetCurrentValue(DisplayTimeProperty, d); + } + } + else + { + if (SelectedTime.HasValue) + { + SetCurrentValue(SelectedTimeProperty, null); + } + } + } + else + { + var d = SetTextBoxValue(_defaultText); + if (!SelectedTime.Equals(d)) + { + SetCurrentValue(SelectedTimeProperty, d); + } + } + } + + private string DateTimeToString(DateTime d) => d.ToString(TimeFormat); + + private static void OnGotFocus(object sender, RoutedEventArgs e) + { + var picker = (TimePicker)sender; + if (!e.Handled && picker._textBox != null) + { + if (Equals(e.OriginalSource, picker)) + { + picker._textBox.Focus(); + e.Handled = true; + } + else if (Equals(e.OriginalSource, picker._textBox)) + { + picker._textBox.SelectAll(); + e.Handled = true; + } + } + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/HandyControl/Controls/WatermarkTextBox.cs b/HandyControl/Controls/WatermarkTextBox.cs new file mode 100644 index 00000000..56586688 --- /dev/null +++ b/HandyControl/Controls/WatermarkTextBox.cs @@ -0,0 +1,77 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace HandyControl.Controls +{ + [TemplatePart(Name = ElementContentName, Type = typeof(ContentControl))] + public class WatermarkTextBox : TextBox + { + #region Constants + + private const string ElementContentName = "PART_Watermark"; + + #endregion Constants + + #region Data + + private ContentControl _elementContent; + + #endregion Data + + #region Public Properties + + #region Watermark + + public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register( + "Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(default(object), OnWatermarkChanged)); + + private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (WatermarkTextBox) d; + ctl.OnWatermarkChanged(); + } + + public object Watermark + { + get => GetValue(WatermarkProperty); + set => SetValue(WatermarkProperty, value); + } + + #endregion Watermark + + #endregion Public Properties + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _elementContent = GetTemplateChild(ElementContentName) as ContentControl; + _elementContent?.SetBinding(ContentControl.ContentProperty, new Binding(WatermarkProperty.Name) {Source = this}); + + OnWatermarkChanged(); + } + + private void OnWatermarkChanged() + { + if (_elementContent == null) return; + if (Watermark is Control watermarkControl) + { + watermarkControl.IsTabStop = false; + watermarkControl.IsHitTestVisible = false; + } + } + + protected override void OnGotFocus(RoutedEventArgs e) + { + base.OnGotFocus(e); + if (IsEnabled) + { + if (!string.IsNullOrEmpty(Text)) + { + Select(0, Text.Length); + } + } + } + } +} \ No newline at end of file diff --git a/HandyControl/Data/BooleanBoxes.cs b/HandyControl/Data/BooleanBoxes.cs new file mode 100644 index 00000000..8681b16e --- /dev/null +++ b/HandyControl/Data/BooleanBoxes.cs @@ -0,0 +1,13 @@ +namespace HandyControl.Data +{ + /// + /// 装箱后的布尔值(用于提高效率) + /// + internal static class BooleanBoxes + { + internal static object TrueBox = true; + internal static object FalseBox = false; + + internal static object Box(bool value) => value ? TrueBox : FalseBox; + } +} \ No newline at end of file diff --git a/HandyControl/Data/FunctionEventArgs!1.cs b/HandyControl/Data/FunctionEventArgs!1.cs index 239f367a..f248a60c 100644 --- a/HandyControl/Data/FunctionEventArgs!1.cs +++ b/HandyControl/Data/FunctionEventArgs!1.cs @@ -5,6 +5,11 @@ namespace HandyControl.Data { public class FunctionEventArgs : RoutedEventArgs { + public FunctionEventArgs(T info) + { + Info = info; + } + public FunctionEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index 2920c019..90ef9689 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -37,12 +37,16 @@ + Carousel.xaml + + + ColorPicker.xaml @@ -78,7 +82,9 @@ TimeBar.xaml + + ImageBrowser.xaml @@ -86,6 +92,7 @@ PopupWindow.xaml + @@ -98,6 +105,7 @@ + @@ -107,12 +115,14 @@ + + @@ -153,6 +163,7 @@ + @@ -295,6 +306,14 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -303,6 +322,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -343,6 +366,14 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/HandyControl/Interactivity/ControlCommands.cs b/HandyControl/Interactivity/ControlCommands.cs index f8c0da9c..e2d8647a 100644 --- a/HandyControl/Interactivity/ControlCommands.cs +++ b/HandyControl/Interactivity/ControlCommands.cs @@ -31,5 +31,40 @@ namespace HandyControl.Interactivity /// 下一个 /// public static RoutedCommand Next { get; } = new RoutedCommand("Next", typeof(ControlCommands)); + + /// + /// 上午 + /// + public static RoutedCommand Am { get; } = new RoutedCommand("Am", typeof(ControlCommands)); + + /// + /// 下午 + /// + public static RoutedCommand Pm { get; } = new RoutedCommand("Pm", typeof(ControlCommands)); + + /// + /// 确认 + /// + public static RoutedCommand Sure { get; } = new RoutedCommand("Sure", typeof(ControlCommands)); + + /// + /// 小时改变 + /// + public static RoutedCommand HourChange { get; } = new RoutedCommand("HourChange", typeof(ControlCommands)); + + /// + /// 分钟改变 + /// + public static RoutedCommand MinuteChange { get; } = new RoutedCommand("MinuteChange", typeof(ControlCommands)); + + /// + /// 秒改变 + /// + public static RoutedCommand SecondChange { get; } = new RoutedCommand("SecondChange", typeof(ControlCommands)); + + /// + /// 鼠标移动 + /// + public static RoutedCommand MouseMove { get; } = new RoutedCommand("MouseMove", typeof(ControlCommands)); } } \ No newline at end of file diff --git a/HandyControl/Interactivity/EventToCommand.cs b/HandyControl/Interactivity/EventToCommand.cs new file mode 100644 index 00000000..9f8c403d --- /dev/null +++ b/HandyControl/Interactivity/EventToCommand.cs @@ -0,0 +1,194 @@ +/*refrence from https://github.com/lbugnion/mvvmlight*/ + +//The MIT License(MIT) + +//Copyright(c) 2009 - 2018 Laurent Bugnion + +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: + +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. + +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +using System; +using System.Windows; +using System.Windows.Input; + +namespace HandyControl.Interactivity +{ + public class EventToCommand : TriggerAction + { + public const string EventArgsConverterParameterPropertyName = "EventArgsConverterParameter"; + + public const string AlwaysInvokeCommandPropertyName = "AlwaysInvokeCommand"; + + public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( + nameof(CommandParameter), typeof(object), typeof(EventToCommand), new PropertyMetadata(null, + (s, e) => + { + var eventToCommand = s as EventToCommand; + if (eventToCommand?.AssociatedObject == null) + return; + eventToCommand.EnableDisableElement(); + })); + + public static readonly DependencyProperty CommandProperty = + DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(EventToCommand), + new PropertyMetadata(null, (s, e) => OnCommandChanged(s as EventToCommand, e))); + + public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register( + nameof(MustToggleIsEnabled), typeof(bool), typeof(EventToCommand), new PropertyMetadata(false, + (s, e) => + { + var eventToCommand = s as EventToCommand; + if (eventToCommand?.AssociatedObject == null) + return; + eventToCommand.EnableDisableElement(); + })); + + public static readonly DependencyProperty EventArgsConverterParameterProperty = + DependencyProperty.Register(nameof(EventArgsConverterParameter), typeof(object), + typeof(EventToCommand), new PropertyMetadata(null)); + + public static readonly DependencyProperty AlwaysInvokeCommandProperty = + DependencyProperty.Register(nameof(AlwaysInvokeCommand), typeof(bool), typeof(EventToCommand), + new PropertyMetadata(false)); + + private object _commandParameterValue; + + private bool? _mustToggleValue; + + public ICommand Command + { + get => (ICommand) GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + public object CommandParameter + { + get => GetValue(CommandParameterProperty); + set => SetValue(CommandParameterProperty, value); + } + + public object CommandParameterValue + { + get => _commandParameterValue ?? CommandParameter; + set + { + _commandParameterValue = value; + EnableDisableElement(); + } + } + + public bool MustToggleIsEnabled + { + get => (bool) GetValue(MustToggleIsEnabledProperty); + set => SetValue(MustToggleIsEnabledProperty, value); + } + + public bool MustToggleIsEnabledValue + { + get + { + if (_mustToggleValue.HasValue) + return _mustToggleValue.Value; + return MustToggleIsEnabled; + } + set + { + _mustToggleValue = value; + EnableDisableElement(); + } + } + + public bool PassEventArgsToCommand { get; set; } + + public IEventArgsConverter EventArgsConverter { get; set; } + + public object EventArgsConverterParameter + { + get => GetValue(EventArgsConverterParameterProperty); + set => SetValue(EventArgsConverterParameterProperty, value); + } + + public bool AlwaysInvokeCommand + { + get => (bool) GetValue(AlwaysInvokeCommandProperty); + set => SetValue(AlwaysInvokeCommandProperty, value); + } + + protected override void OnAttached() + { + base.OnAttached(); + EnableDisableElement(); + } + + private FrameworkElement GetAssociatedObject() => AssociatedObject as FrameworkElement; + + private ICommand GetCommand() => Command; + + public void Invoke() => Invoke(null); + + protected override void Invoke(object parameter) + { + if (AssociatedElementIsDisabled() && !AlwaysInvokeCommand) + return; + var command = GetCommand(); + var parameter1 = CommandParameterValue; + if (parameter1 == null && PassEventArgsToCommand) + parameter1 = EventArgsConverter == null + ? parameter + : EventArgsConverter.Convert(parameter, EventArgsConverterParameter); + if (command == null || !command.CanExecute(parameter1)) + return; + command.Execute(parameter1); + } + + private static void OnCommandChanged(EventToCommand element, DependencyPropertyChangedEventArgs e) + { + if (element == null) + return; + if (e.OldValue != null) + ((ICommand) e.OldValue).CanExecuteChanged -= element.OnCommandCanExecuteChanged; + var newValue = (ICommand) e.NewValue; + if (newValue != null) + newValue.CanExecuteChanged += element.OnCommandCanExecuteChanged; + element.EnableDisableElement(); + } + + private bool AssociatedElementIsDisabled() + { + var associatedObject = GetAssociatedObject(); + if (AssociatedObject == null) + return true; + if (associatedObject != null) + return !associatedObject.IsEnabled; + return false; + } + + private void EnableDisableElement() + { + var associatedObject = GetAssociatedObject(); + if (associatedObject == null) + return; + var command = GetCommand(); + if (!MustToggleIsEnabledValue || command == null) + return; + associatedObject.IsEnabled = command.CanExecute(CommandParameterValue); + } + + private void OnCommandCanExecuteChanged(object sender, EventArgs e) => EnableDisableElement(); + } +} \ No newline at end of file diff --git a/HandyControl/Interactivity/IEventArgsConverter.cs b/HandyControl/Interactivity/IEventArgsConverter.cs new file mode 100644 index 00000000..2f58cd27 --- /dev/null +++ b/HandyControl/Interactivity/IEventArgsConverter.cs @@ -0,0 +1,31 @@ +/*refrence from https://github.com/lbugnion/mvvmlight*/ + +//The MIT License(MIT) + +//Copyright(c) 2009 - 2018 Laurent Bugnion + +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: + +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. + +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +namespace HandyControl.Interactivity +{ + public interface IEventArgsConverter + { + object Convert(object value, object parameter); + } +} \ No newline at end of file diff --git a/HandyControl/Interactivity/RoutedEventTrigger.cs b/HandyControl/Interactivity/RoutedEventTrigger.cs new file mode 100644 index 00000000..d9c4971f --- /dev/null +++ b/HandyControl/Interactivity/RoutedEventTrigger.cs @@ -0,0 +1,29 @@ +using System; +using System.Windows; + +namespace HandyControl.Interactivity +{ + public class RoutedEventTrigger : EventTriggerBase + { + public RoutedEvent RoutedEvent { get; set; } + + protected override void OnAttached() + { + var behavior = AssociatedObject as Behavior; + var associatedElement = AssociatedObject as FrameworkElement; + if (behavior != null) associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement; + if (associatedElement == null) throw new ArgumentException(); + if (RoutedEvent != null) associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent)); + } + + private void OnRoutedEvent(object sender, RoutedEventArgs args) + { + OnEvent(args); + } + + protected override string GetEventName() + { + return RoutedEvent.Name; + } + } +} \ No newline at end of file diff --git a/HandyControl/Properties/AssemblyInfo.cs b/HandyControl/Properties/AssemblyInfo.cs index 3ab8d9c0..6b71d2a0 100644 --- a/HandyControl/Properties/AssemblyInfo.cs +++ b/HandyControl/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HandyControl")] -[assembly: AssemblyCopyright("Copyright © 纳边 2018")] +[assembly: AssemblyCopyright("Copyright © NaBian 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.2.2.1")] -[assembly: AssemblyFileVersion("1.2.2.1")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] diff --git a/HandyControl/Properties/Langs/Lang.Designer.cs b/HandyControl/Properties/Langs/Lang.Designer.cs index 910aa34a..1426b182 100644 --- a/HandyControl/Properties/Langs/Lang.Designer.cs +++ b/HandyControl/Properties/Langs/Lang.Designer.cs @@ -60,6 +60,15 @@ namespace HandyControl.Properties.Langs { } } + /// + /// 查找类似 上午 的本地化字符串。 + /// + public static string Am { + get { + return ResourceManager.GetString("Am", resourceCulture); + } + } + /// /// 查找类似 取消 的本地化字符串。 /// @@ -195,6 +204,15 @@ namespace HandyControl.Properties.Langs { } } + /// + /// 查找类似 下午 的本地化字符串。 + /// + public static string Pm { + get { + return ResourceManager.GetString("Pm", resourceCulture); + } + } + /// /// 查找类似 PNG图片 的本地化字符串。 /// diff --git a/HandyControl/Properties/Langs/Lang.en.resx b/HandyControl/Properties/Langs/Lang.en.resx index cd3e0ba2..dea3c047 100644 --- a/HandyControl/Properties/Langs/Lang.en.resx +++ b/HandyControl/Properties/Langs/Lang.en.resx @@ -177,4 +177,10 @@ Close other + + Am + + + Pm + \ No newline at end of file diff --git a/HandyControl/Properties/Langs/Lang.resx b/HandyControl/Properties/Langs/Lang.resx index 9cee4020..0cde7200 100644 --- a/HandyControl/Properties/Langs/Lang.resx +++ b/HandyControl/Properties/Langs/Lang.resx @@ -157,4 +157,10 @@ 关闭其他 + + 上午 + + + 下午 + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Button.xaml b/HandyControl/Themes/Styles/Button.xaml index c0137f70..618afb97 100644 --- a/HandyControl/Themes/Styles/Button.xaml +++ b/HandyControl/Themes/Styles/Button.xaml @@ -3,7 +3,7 @@ xmlns:controls="clr-namespace:HandyControl.Controls"> - + + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/DatePicker.xaml b/HandyControl/Themes/Styles/DatePicker.xaml new file mode 100644 index 00000000..4271e6cd --- /dev/null +++ b/HandyControl/Themes/Styles/DatePicker.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Style.xaml b/HandyControl/Themes/Styles/Style.xaml index 909d8d03..4813232c 100644 --- a/HandyControl/Themes/Styles/Style.xaml +++ b/HandyControl/Themes/Styles/Style.xaml @@ -13,7 +13,7 @@ - + @@ -27,7 +27,10 @@ - + + + + diff --git a/HandyControl/Themes/Styles/TextBox.xaml b/HandyControl/Themes/Styles/TextBox.xaml new file mode 100644 index 00000000..257b5c73 --- /dev/null +++ b/HandyControl/Themes/Styles/TextBox.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Tools/ArithmeticHelper.cs b/HandyControl/Tools/ArithmeticHelper.cs index 8d2c4780..9b846729 100644 --- a/HandyControl/Tools/ArithmeticHelper.cs +++ b/HandyControl/Tools/ArithmeticHelper.cs @@ -113,5 +113,13 @@ namespace HandyControl.Tools } return new Rect(x, y, width, height); } + + /// + /// 计算两点的连线和x轴的夹角 + /// + /// + /// + /// + public static double CalAngle(Point center, Point p) => Math.Atan2(p.Y - center.Y, p.X - center.X) * 180 / Math.PI; } } \ No newline at end of file diff --git a/HandyControl/Tools/Converter/String2VisibilityConverter.cs b/HandyControl/Tools/Converter/String2VisibilityConverter.cs index 7d420cef..70a72827 100644 --- a/HandyControl/Tools/Converter/String2VisibilityConverter.cs +++ b/HandyControl/Tools/Converter/String2VisibilityConverter.cs @@ -9,12 +9,12 @@ namespace HandyControl.Tools.Converter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return string.IsNullOrEmpty((string)value) ? Visibility.Visible : Visibility.Collapsed; + return string.IsNullOrEmpty((string)value) ? Visibility.Collapsed : Visibility.Visible; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return value != null && (Visibility)value == Visibility.Visible; + return value != null && (Visibility)value == Visibility.Collapsed; } } } \ No newline at end of file diff --git a/HandyControl/Tools/Converter/String2VisibilityReConverter.cs b/HandyControl/Tools/Converter/String2VisibilityReConverter.cs index 56e7be13..cb5e7e73 100644 --- a/HandyControl/Tools/Converter/String2VisibilityReConverter.cs +++ b/HandyControl/Tools/Converter/String2VisibilityReConverter.cs @@ -9,12 +9,12 @@ namespace HandyControl.Tools.Converter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return string.IsNullOrEmpty((string)value) ? Visibility.Collapsed : Visibility.Visible; + return string.IsNullOrEmpty((string)value) ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return value != null && (Visibility)value == Visibility.Visible; + return value != null && (Visibility)value == Visibility.Collapsed; } } } \ No newline at end of file diff --git a/HandyControl/Tools/ValidateHelper.cs b/HandyControl/Tools/ValidateHelper.cs new file mode 100644 index 00000000..fcff6392 --- /dev/null +++ b/HandyControl/Tools/ValidateHelper.cs @@ -0,0 +1,19 @@ +namespace HandyControl.Tools +{ + /// + /// 验证帮助类 + /// + internal class ValidateHelper + { + /// + /// 是否在浮点数范围内 + /// + /// + /// + internal static bool IsInRangeOfDouble(object value) + { + var v = (double)value; + return !(double.IsNaN(v) || double.IsInfinity(v)); + } + } +} \ No newline at end of file diff --git a/HandyControlDemo/Data/MessageToken.cs b/HandyControlDemo/Data/MessageToken.cs index 1d2bdb47..0d3b673a 100644 --- a/HandyControlDemo/Data/MessageToken.cs +++ b/HandyControlDemo/Data/MessageToken.cs @@ -22,6 +22,10 @@ public static readonly string StepBarDemoCtl = nameof(StepBarDemoCtl); + public static readonly string ClockDemoCtl = nameof(ClockDemoCtl); + + public static readonly string TimePickerDemoCtl = nameof(TimePickerDemoCtl); + public static readonly string ButtonDemoCtl = nameof(ButtonDemoCtl); public static readonly string ToggleButtonDemoCtl = nameof(ToggleButtonDemoCtl); @@ -32,6 +36,10 @@ public static readonly string TabControlDemoCtl = nameof(TabControlDemoCtl); + public static readonly string CalendarDemoCtl = nameof(CalendarDemoCtl); + + public static readonly string DatePickerDemoCtl = nameof(DatePickerDemoCtl); + public static readonly string LoadShowContent = nameof(LoadShowContent); } } \ No newline at end of file diff --git a/HandyControlDemo/Data/MessageToken.tt b/HandyControlDemo/Data/MessageToken.tt index e1095e8a..68956cc5 100644 --- a/HandyControlDemo/Data/MessageToken.tt +++ b/HandyControlDemo/Data/MessageToken.tt @@ -13,7 +13,9 @@ var controlList = new List "TimeBarDemoCtl", "PaginationDemoCtl", "AnimationPathDemoCtl", - "StepBarDemoCtl" + "StepBarDemoCtl", + "ClockDemoCtl", + "TimePickerDemoCtl" }; var styleList = new List { @@ -21,7 +23,9 @@ var styleList = new List "ToggleButtonDemoCtl", "ExpanderDemoCtl", "ProgressBarDemoCtl", - "TabControlDemoCtl" + "TabControlDemoCtl", + "CalendarDemoCtl", + "DatePickerDemoCtl" }; #> namespace HandyControlDemo.Data diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj index cf9f0538..bf29c945 100644 --- a/HandyControlDemo/HandyControlDemo.csproj +++ b/HandyControlDemo/HandyControlDemo.csproj @@ -84,6 +84,9 @@ CarouselDemoCtl.xaml + + ClockDemoCtl.xaml + ColorPickerDemoCtl.xaml @@ -102,12 +105,21 @@ StepBarDemoCtl.xaml + + TimePickerDemoCtl.xaml + NoUserContent.xaml ButtonDemoCtl.xaml + + CalendarDemoCtl.xaml + + + DatePickerDemoCtl.xaml + ExpanderDemoCtl.xaml @@ -180,6 +192,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -204,6 +220,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -212,6 +232,14 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/HandyControlDemo/Properties/AssemblyInfo.cs b/HandyControlDemo/Properties/AssemblyInfo.cs index bb2b78b4..c4043395 100644 --- a/HandyControlDemo/Properties/AssemblyInfo.cs +++ b/HandyControlDemo/Properties/AssemblyInfo.cs @@ -7,10 +7,10 @@ using System.Windows; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HandyControlDemo")] -[assembly: AssemblyCopyright("Copyright © 纳边 2018")] +[assembly: AssemblyCopyright("Copyright © NaBian 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("1.2.2.1")] -[assembly: AssemblyFileVersion("1.2.2.1")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] diff --git a/HandyControlDemo/Properties/Langs/Lang.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.Designer.cs index 7222ed50..ed5b1271 100644 --- a/HandyControlDemo/Properties/Langs/Lang.Designer.cs +++ b/HandyControlDemo/Properties/Langs/Lang.Designer.cs @@ -177,6 +177,15 @@ namespace HandyControlDemo.Properties.Langs { } } + /// + /// 查找类似 日期选择器 的本地化字符串。 + /// + public static string DatePicker { + get { + return ResourceManager.GetString("DatePicker", resourceCulture); + } + } + /// /// 查找类似 默认 的本地化字符串。 /// @@ -205,7 +214,7 @@ namespace HandyControlDemo.Properties.Langs { } /// - /// 查找类似 检测到有新版本! 的本地化字符串。 + /// 查找类似 检测到有新版本!是否更新? 的本地化字符串。 /// public static string GrowlAsk { get { @@ -402,6 +411,15 @@ namespace HandyControlDemo.Properties.Langs { } } + /// + /// 查找类似 时间选择器 的本地化字符串。 + /// + public static string TimePicker { + get { + return ResourceManager.GetString("TimePicker", resourceCulture); + } + } + /// /// 查找类似 标题 的本地化字符串。 /// diff --git a/HandyControlDemo/Properties/Langs/Lang.en.resx b/HandyControlDemo/Properties/Langs/Lang.en.resx index 95a1bcca..5573ee87 100644 --- a/HandyControlDemo/Properties/Langs/Lang.en.resx +++ b/HandyControlDemo/Properties/Langs/Lang.en.resx @@ -142,7 +142,7 @@ The program has crashed~~~ - A new version has been detected! + A new version has been detected!Do you want to update? Loading @@ -243,4 +243,10 @@ Calendar + + DatePicker + + + TimePicker + \ No newline at end of file diff --git a/HandyControlDemo/Properties/Langs/Lang.resx b/HandyControlDemo/Properties/Langs/Lang.resx index e3461202..29574bbd 100644 --- a/HandyControlDemo/Properties/Langs/Lang.resx +++ b/HandyControlDemo/Properties/Langs/Lang.resx @@ -122,7 +122,7 @@ 程序已崩溃~~~ - 检测到有新版本! + 检测到有新版本!是否更新? 加载条 @@ -223,4 +223,10 @@ 日历 + + 日期选择器 + + + 时间选择器 + \ No newline at end of file diff --git a/HandyControlDemo/Resources/Themes/Styles/Label.xaml b/HandyControlDemo/Resources/Themes/Styles/Label.xaml index a6138bfe..f60d6a8d 100644 --- a/HandyControlDemo/Resources/Themes/Styles/Label.xaml +++ b/HandyControlDemo/Resources/Themes/Styles/Label.xaml @@ -2,9 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">