From 3093d17db8bbe6bf401a1944e6fae527feb59161 Mon Sep 17 00:00:00 2001 From: Mahdi Hosseini Date: Sun, 21 Apr 2019 10:32:52 +0430 Subject: [PATCH 1/8] Color Dropper now we can select color from everywhere --- .../Controls/Other/ColorPicker.cs | 35 ++++++ .../Controls/Other/MouseHook.cs | 102 ++++++++++++++++++ .../HandyControl_Shared.projitems | 1 + .../Interactivity/ControlCommands.cs | 2 + .../Themes/Basic/Geometries.xaml | 1 + .../Themes/Basic/Paths.xaml | 3 + .../Themes/Styles/ColorPicker.xaml | 17 ++- 7 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Other/MouseHook.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Other/ColorPicker.cs b/src/Shared/HandyControl_Shared/Controls/Other/ColorPicker.cs index 96e2020d..009e2edd 100644 --- a/src/Shared/HandyControl_Shared/Controls/Other/ColorPicker.cs +++ b/src/Shared/HandyControl_Shared/Controls/Other/ColorPicker.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -337,6 +338,7 @@ namespace HandyControl.Controls CommandBindings.Add(new CommandBinding(ControlCommands.Confirm, ButtonConfirm_OnClick)); CommandBindings.Add(new CommandBinding(ControlCommands.Switch, ButtonSwitch_OnClick)); CommandBindings.Add(new CommandBinding(ControlCommands.Cancel, ButtonCancel_OnClick)); + CommandBindings.Add(new CommandBinding(ControlCommands.Dropper, ButtonDropper_OnClick)); Loaded += (s, e) => { @@ -678,5 +680,38 @@ namespace HandyControl.Controls public void Dispose() => System.Windows.Window.GetWindow(this)?.Close(); public bool CanDispose { get; } = true; + + private void ButtonDropper_OnClick(object sender, RoutedEventArgs e) + { + MouseHook.Start(); + MouseHook.MouseAction += MouseHook_MouseAction; + } + + private void MouseHook_MouseAction(object sender, MouseHook.RawMouseEventArgs e) + { + SelectedBrush = new SolidColorBrush(GetColorAt(e.Point.x, e.Point.y)); + if (e.Message == MouseHook.MouseMessages.WM_LBUTTONDOWN) + { + MouseHook.Stop(); + MouseHook.MouseAction -= MouseHook_MouseAction; + } + } + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetDesktopWindow(); + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetWindowDC(IntPtr window); + [DllImport("gdi32.dll", SetLastError = true)] + public static extern uint GetPixel(IntPtr dc, int x, int y); + [DllImport("user32.dll", SetLastError = true)] + public static extern int ReleaseDC(IntPtr window, IntPtr dc); + + public static Color GetColorAt(int x, int y) + { + IntPtr desk = GetDesktopWindow(); + IntPtr dc = GetWindowDC(desk); + int a = (int)GetPixel(dc, x, y); + ReleaseDC(desk, dc); + return Color.FromArgb(255, (byte)((a >> 0) & 0xff), (byte)((a >> 8) & 0xff), (byte)((a >> 16) & 0xff)); + } } } \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Other/MouseHook.cs b/src/Shared/HandyControl_Shared/Controls/Other/MouseHook.cs new file mode 100644 index 00000000..0ce9e0f9 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Other/MouseHook.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace HandyControl +{ + public static class MouseHook + { + //public static event EventHandler MouseAction = delegate { }; + public static event EventHandler MouseAction = delegate { }; + public class RawMouseEventArgs : EventArgs + { + internal MouseMessages Message { get; set; } + internal POINT Point { get; set; } + } + + public static void Start() + { + _hookID = SetHook(_proc); + } + public static void Stop() + { + UnhookWindowsHookEx(_hookID); + } + + private static LowLevelMouseProc _proc = HookCallback; + private static IntPtr _hookID = IntPtr.Zero; + + private static IntPtr SetHook(LowLevelMouseProc proc) + { + using (Process curProcess = Process.GetCurrentProcess()) + using (ProcessModule curModule = curProcess.MainModule) + { + return SetWindowsHookEx(WH_MOUSE_LL, proc, + GetModuleHandle(curModule.ModuleName), 0); + } + } + + private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); + + private static IntPtr HookCallback( + int nCode, IntPtr wParam, IntPtr lParam) + { + if (nCode < 0) return CallNextHookEx(_hookID, nCode, wParam, lParam); + MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); + MouseAction(null, new RawMouseEventArgs() { Message = (MouseMessages)wParam, Point = hookStruct.pt }); + + return CallNextHookEx(_hookID, nCode, wParam, lParam); + } + + private const int WH_MOUSE_LL = 14; + + public enum MouseMessages + { + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_MOUSEMOVE = 0x0200, + WM_MOUSEWHEEL = 0x020A, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205 + } + + [StructLayout(LayoutKind.Sequential)] + public struct POINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + private struct MSLLHOOKSTRUCT + { + public POINT pt; + public uint mouseData; + public uint flags; + public uint time; + public IntPtr dwExtraInfo; + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, + LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, + IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + + + } + +} diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index d648c863..b92f82a6 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -64,6 +64,7 @@ + diff --git a/src/Shared/HandyControl_Shared/Interactivity/ControlCommands.cs b/src/Shared/HandyControl_Shared/Interactivity/ControlCommands.cs index efee5e51..5f171d7c 100644 --- a/src/Shared/HandyControl_Shared/Interactivity/ControlCommands.cs +++ b/src/Shared/HandyControl_Shared/Interactivity/ControlCommands.cs @@ -22,6 +22,8 @@ namespace HandyControl.Interactivity /// public static RoutedCommand Switch { get; } = new RoutedCommand(nameof(Switch), typeof(ControlCommands)); + public static RoutedCommand Dropper { get; } = new RoutedCommand(nameof(Dropper), typeof(ControlCommands)); + /// /// 右转 /// diff --git a/src/Shared/HandyControl_Shared/Themes/Basic/Geometries.xaml b/src/Shared/HandyControl_Shared/Themes/Basic/Geometries.xaml index cd561108..39af489d 100644 --- a/src/Shared/HandyControl_Shared/Themes/Basic/Geometries.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Basic/Geometries.xaml @@ -38,5 +38,6 @@ M512 0 30.11843 240.941297l0 542.117406 481.88157 240.941297 481.88157-240.941297L993.88157 240.941297 512 0zM575.776472 768.799969 460.188012 768.799969 460.188012 656.222073l115.588459 0L575.776472 768.799969zM623.335603 509.329685c-52.375829 36.723353-59.600363 55.988096-59.600363 84.885211l0 19.866447L468.616977 614.081343l0-26.489278c0-45.754021 13.846342-80.67124 61.406497-116.791866 46.957428-36.723353 57.79423-62.0082 57.79423-84.282484 0-25.284848-21.67258-54.181962-55.386393-54.181962-42.743457 0-70.436142 26.489278-82.477374 85.486914l-105.956088-21.67258c24.683144-111.976192 82.477374-157.127486 205.289345-157.127486 98.12985 0 157.72919 63.212631 157.72919 131.842639C707.017407 423.240044 688.956071 461.76953 623.335603 509.329685z M 721.005 638.949 C 758.74 638.949 789.333 669.56 789.333 707.312 C 789.333 745.047 758.74 775.657 721.005 775.657 C 683.253 775.657 652.66 745.047 652.66 707.312 C 652.66 669.56 683.253 638.949 721.005 638.949 Z M 512.017 638.949 C 549.77 638.949 580.38 669.56 580.38 707.312 C 580.38 745.047 549.77 775.657 512.017 775.657 C 474.265 775.657 443.672 745.047 443.672 707.312 C 443.672 669.56 474.265 638.949 512.017 638.949 Z M 303.029 638.949 C 340.781 638.949 371.392 669.56 371.392 707.312 C 371.392 745.047 340.781 775.657 303.029 775.657 C 265.277 775.657 234.667 745.047 234.667 707.312 C 234.667 669.56 265.277 638.949 303.029 638.949 Z M 721.005 443.655 C 758.74 443.655 789.333 474.265 789.333 512.017 C 789.333 549.769 758.74 580.363 721.005 580.363 C 683.253 580.363 652.66 549.769 652.66 512.017 C 652.66 474.265 683.253 443.655 721.005 443.655 Z M 512.017 443.655 C 549.77 443.655 580.38 474.265 580.38 512.017 C 580.38 549.769 549.77 580.363 512.017 580.363 C 474.265 580.363 443.672 549.769 443.672 512.017 C 443.672 474.265 474.265 443.655 512.017 443.655 Z M 303.029 443.655 C 340.781 443.655 371.392 474.265 371.392 512.017 C 371.392 549.769 340.781 580.363 303.029 580.363 C 265.277 580.363 234.667 549.769 234.667 512.017 C 234.667 474.265 265.277 443.655 303.029 443.655 Z M 721.005 248.343 C 758.74 248.343 789.333 278.953 789.333 316.688 C 789.333 354.44 758.74 385.051 721.005 385.051 C 683.253 385.051 652.66 354.44 652.66 316.688 C 652.66 278.953 683.253 248.343 721.005 248.343 Z M 512.017 248.343 C 549.77 248.343 580.38 278.953 580.38 316.688 C 580.38 354.44 549.77 385.051 512.017 385.051 C 474.265 385.051 443.672 354.44 443.672 316.688 C 443.672 278.953 474.265 248.343 512.017 248.343 Z M 303.029 248.343 C 340.781 248.343 371.392 278.953 371.392 316.688 C 371.392 354.44 340.781 385.051 303.029 385.051 C 265.277 385.051 234.667 354.44 234.667 316.688 C 234.667 278.953 265.277 248.343 303.029 248.343 Z M384 896C384 825.307552 440.814697 768 512 768 582.692448 768 640 824.814694 640 896 640 966.692448 583.185303 1024 512 1024 441.307552 1024 384 967.185306 384 896ZM384 512C384 441.307552 440.814697 384 512 384 582.692448 384 640 440.814697 640 512 640 582.692448 583.185303 640 512 640 441.307552 640 384 583.185303 384 512ZM384 128C384 57.307552 440.814697 0 512 0 582.692448 0 640 56.814697 640 128 640 198.692448 583.185303 256 512 256 441.307552 256 384 199.185303 384 128Z + M 416 32 C 399.625 32 383.25 38.25 370.625 50.75 C 370.625 50.75 312.75 109.5 270.75 152.125 L 246.5 127.875 L 223.875 150.5 L 248.25 174.875 C 173.375 250.875 101.5 323.875 84.75 340.625 C 67.25 358.125 65.75 374.125 64.625 386.875 C 63.375 400.125 62.375 411.5 43 430.875 L 31.75 442.125 L 69.625 480.125 L 80.875 468.75 C 99.75 450 110.375 449.25 122.875 448.375 C 136 447.5 152.25 446.375 171.25 427.375 C 189.625 409 261.5 338.25 337.125 263.75 L 361.5 288.125 L 384.125 265.5 L 359.875 241.25 C 402.25 199.5 461.25 141.25 461.25 141.25 C 486.125 116.25 486.125 75.75 461.25 50.75 C 448.75 38.25 432.375 32 416 32 Z M 416 64 C 424.125 64 432.375 67.125 438.625 73.5 C 451.125 85.875 451.125 106.125 438.75 118.5 C 438.75 118.5 379.625 176.875 337.25 218.625 L 293.375 174.75 C 335.375 132.125 393.375 73.375 393.375 73.375 C 399.625 67.125 407.875 64 416 64 Z M 270.875 197.5 L 314.5 241.125 C 238.875 315.625 167 386.375 148.75 404.625 C 138.125 415.25 131.625 415.75 120.75 416.5 C 111.375 417.125 100.625 417.875 87.75 424.125 C 94.625 410.375 95.625 399 96.5 389.75 C 97.5 378.625 98 372.625 107.25 363.375 C 124.125 346.5 195.875 273.5 270.875 197.5 Z \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Basic/Paths.xaml b/src/Shared/HandyControl_Shared/Themes/Basic/Paths.xaml index 85d96506..3bd5fe99 100644 --- a/src/Shared/HandyControl_Shared/Themes/Basic/Paths.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Basic/Paths.xaml @@ -111,4 +111,7 @@ + \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml index 63917319..07876378 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml @@ -93,11 +93,18 @@ - + + + + From 7585d86fb540a2b074c6c81198825ab661eb9afe Mon Sep 17 00:00:00 2001 From: Mahdi Hosseini Date: Sat, 11 May 2019 19:17:10 +0430 Subject: [PATCH 2/8] add TimePickerList --- .../Controls/TimePickerDemoCtl.xaml | 2 + .../Controls/Time/ItemsControlExtensions.cs | 79 ++++ .../Controls/Time/TimeButton.cs | 42 ++ .../Controls/Time/TimePickerList.cs | 114 ++++++ .../Controls/Time/TimeSelector.cs | 380 ++++++++++++++++++ .../HandyControl_Shared.projitems | 12 + .../Themes/Styles/Style.xaml | 2 + .../Themes/Styles/TimePickerList.xaml | 88 ++++ .../Themes/Styles/TimeSelector.xaml | 89 ++++ 9 files changed, 808 insertions(+) create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs create mode 100644 src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml create mode 100644 src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml index 840acbb5..63143963 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml @@ -7,6 +7,8 @@ + + diff --git a/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs b/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs new file mode 100644 index 00000000..8cea4c60 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; + +namespace HandyControl.Controls +{ + /// + /// ItemsControl扩展方法 + /// + public static class ItemsControlExtensions + { + /// + /// 平滑滚动至指定元素 + /// + /// + /// + public static void AnimateScrollIntoView(this ItemsControl itemsControl, object item) + { + ScrollViewer scrollViewer = FindVisualChild(itemsControl); + if (scrollViewer == null) + { + return; + } + + UIElement container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement; + + if (container == null) + { + return; + } + + int index = itemsControl.ItemContainerGenerator.IndexFromContainer(container); + + //平滑滚动到元素所在位置 + //double toValue = scrollViewer.ScrollableHeight * ((double)index / itemsControl.Items.Count); + //平滑滚动,将选中的元素置顶 + double toValue = VisualTreeHelper.GetOffset(container).Y; + + DoubleAnimation verticalAnimation = new DoubleAnimation(); + verticalAnimation.From = scrollViewer.VerticalOffset; + verticalAnimation.To = toValue; + verticalAnimation.DecelerationRatio = .2; + verticalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(200)); + Storyboard storyboard = new Storyboard(); + storyboard.Children.Add(verticalAnimation); + Storyboard.SetTarget(verticalAnimation, scrollViewer); + Storyboard.SetTargetProperty(verticalAnimation, new PropertyPath(ScrollViewerBehavior.VerticalOffsetProperty)); + storyboard.Begin(); + } + + /// + /// 查找元素的子元素 + /// + /// 子元素类型 + /// + /// + public static T FindVisualChild(DependencyObject obj) where T : DependencyObject + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) + { + DependencyObject child = VisualTreeHelper.GetChild(obj, i); + if (child != null && child is T) + return (T)child; + else + { + T childOfChild = FindVisualChild(child); + if (childOfChild != null) + return childOfChild; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs new file mode 100644 index 00000000..751bb887 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace HandyControl.Controls +{ + public class TimeButton : ListBoxItem + { + #region Private属性 + #endregion + + #region 依赖属性定义 + + #endregion + + #region 依赖属性set get + + #endregion + + #region Constructors + static TimeButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeButton), new FrameworkPropertyMetadata(typeof(TimeButton))); + } + #endregion + + #region Override方法 + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + } + #endregion + + #region Private方法 + + #endregion + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs new file mode 100644 index 00000000..9605dfc0 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace HandyControl.Controls +{ + public class TimePickerList : Control + { + #region Private属性 + private TextBox PART_TextBox; + private TimeSelector PART_TimeSelector; + private Popup PART_Popup; + #endregion + + #region 依赖属性定义 + + #endregion + + #region 依赖属性set get + + #region TimeStringFormat + public string TimeStringFormat + { + get { return (string)GetValue(TimeStringFormatProperty); } + set { SetValue(TimeStringFormatProperty, value); } + } + + public static readonly DependencyProperty TimeStringFormatProperty = + DependencyProperty.Register("TimeStringFormat", typeof(string), typeof(TimePickerList), new PropertyMetadata("HH:mm:ss")); + #endregion + + #region SelectedTime + public DateTime? SelectedTime + { + get { return (DateTime?)GetValue(SelectedTimeProperty); } + set { SetValue(SelectedTimeProperty, value); } + } + + public static readonly DependencyProperty SelectedTimeProperty = + DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimePickerList), new PropertyMetadata(null, SelectedTimeChangedCallback)); + + private static void SelectedTimeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TimePickerList timePicker = d as TimePickerList; + DateTime dt = (DateTime)e.NewValue; + + timePicker.PART_TimeSelector.SelectedTime = dt; + } + #endregion + + #region DropDownHeight + + public double DropDownHeight + { + get { return (double)GetValue(DropDownHeightProperty); } + set { SetValue(DropDownHeightProperty, value); } + } + + public static readonly DependencyProperty DropDownHeightProperty = + DependencyProperty.Register("DropDownHeight", typeof(double), typeof(TimePickerList), new PropertyMetadata(168d)); + + #endregion + + #endregion + + #region Constructors + static TimePickerList() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePickerList), new FrameworkPropertyMetadata(typeof(TimePickerList))); + } + #endregion + + #region Override方法 + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + this.PART_TextBox = this.GetTemplateChild("PART_TextBox") as TextBox; + this.PART_TimeSelector = this.GetTemplateChild("PART_TimeSelector") as TimeSelector; + this.PART_Popup = this.GetTemplateChild("PART_Popup") as Popup; + if (this.PART_TimeSelector != null) + { + this.PART_TimeSelector.Owner = this; + this.PART_TimeSelector.SelectedTimeChanged += PART_TimeSelector_SelectedTimeChanged; + } + if (this.PART_Popup != null) + { + this.PART_Popup.Opened += PART_Popup_Opened; + } + } + + private void PART_Popup_Opened(object sender, EventArgs e) + { + this.PART_TimeSelector.SetButtonSelected(); + } + #endregion + + #region Private方法 + private void PART_TimeSelector_SelectedTimeChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (this.PART_TextBox != null && e.NewValue != null) + { + this.PART_TextBox.Text = e.NewValue.Value.ToString(this.TimeStringFormat); + this.SelectedTime = e.NewValue; + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs new file mode 100644 index 00000000..e2eb030a --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; + +namespace HandyControl.Controls +{ + public class TimeSelector : Control + { + private ObservableCollection HourButtons = new ObservableCollection(); + private ObservableCollection MinuteButtons = new ObservableCollection(); + private ObservableCollection SecondButtons = new ObservableCollection(); + + #region 控件内部元素 + private ListBox PART_Hour; + private ListBox PART_Minute; + private ListBox PART_Second; + #endregion + + #region 私有属性 + private int Hour = 0; + private int Minute = 0; + private int Second = 0; + #endregion + + #region Fields + public TimePickerList Owner { get; set; } + #endregion + + #region 事件定义 + + #region SelectedTimeChanged + public static readonly RoutedEvent SelectedTimeChangedEvent = EventManager.RegisterRoutedEvent("SelectedTimeChanged", + RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(TimeSelector)); + + public event RoutedPropertyChangedEventHandler SelectedTimeChanged + { + add + { + this.AddHandler(SelectedTimeChangedEvent, value); + } + remove + { + this.RemoveHandler(SelectedTimeChangedEvent, value); + } + } + + public virtual void OnSelectedTimeChanged(DateTime? oldValue, DateTime? newValue) + { + RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, SelectedTimeChangedEvent); + this.RaiseEvent(arg); + } + #endregion + + #endregion + + #region 依赖属性set get + + #region SelectedTime + public DateTime? SelectedTime + { + get { return (DateTime?)GetValue(SelectedTimeProperty); } + set { SetValue(SelectedTimeProperty, value); } + } + + public static readonly DependencyProperty SelectedTimeProperty = + DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimeSelector), new PropertyMetadata(null, SelectedTimeChangedCallback)); + + private static void SelectedTimeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TimeSelector timeSelector = d as TimeSelector; + DateTime dt = (DateTime)e.NewValue; + + timeSelector.SetButtonSelected(); + + timeSelector.OnSelectedTimeChanged((DateTime?)e.OldValue, (DateTime?)e.NewValue); + } + + public void SetButtonSelected() + { + if (!this.SelectedTime.HasValue) + { + return; + } + + this.Hour = this.SelectedTime.Value.Hour; + this.Minute = this.SelectedTime.Value.Minute; + this.Second = this.SelectedTime.Value.Second; + + if (this.PART_Hour != null) + { + for (int i = 0; i < this.PART_Hour.Items.Count; i++) + { + TimeButton timeButton = this.PART_Hour.Items[i] as TimeButton; + if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Hour))) + { + this.PART_Hour.SelectedIndex = i; + this.PART_Hour.AnimateScrollIntoView(timeButton); + break; + } + } + } + + if (this.PART_Minute != null) + { + for (int i = 0; i < this.PART_Minute.Items.Count; i++) + { + TimeButton timeButton = this.PART_Minute.Items[i] as TimeButton; + if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Minute))) + { + this.PART_Minute.SelectedIndex = i; + this.PART_Minute.AnimateScrollIntoView(timeButton); + break; + } + } + } + + if (this.PART_Second != null) + { + for (int i = 0; i < this.PART_Second.Items.Count; i++) + { + TimeButton timeButton = this.PART_Second.Items[i] as TimeButton; + if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Second))) + { + this.PART_Second.SelectedIndex = i; + this.PART_Second.AnimateScrollIntoView(timeButton); + break; + } + } + } + } + #endregion + + #region SelectedHour + public int? SelectedHour + { + get { return (int?)GetValue(SelectedHourProperty); } + set { SetValue(SelectedHourProperty, value); } + } + + public static readonly DependencyProperty SelectedHourProperty = + DependencyProperty.Register("SelectedHour", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedHourChanged)); + + private static void SelectedHourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TimeSelector timeSelector = d as TimeSelector; + timeSelector.Hour = e.NewValue == null ? 0 : (int)e.NewValue; + timeSelector.SetSelectedTime(); + } + #endregion + + #region SelectedMinute + + public int? SelectedMinute + { + get { return (int?)GetValue(SelectedMinuteProperty); } + set { SetValue(SelectedMinuteProperty, value); } + } + + public static readonly DependencyProperty SelectedMinuteProperty = + DependencyProperty.Register("SelectedMinute", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedMinuteChanged)); + + private static void SelectedMinuteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TimeSelector timeSelector = d as TimeSelector; + + timeSelector.Minute = e.NewValue == null ? 0 : (int)e.NewValue; + timeSelector.SetSelectedTime(); + } + + #endregion + + #region SelectedSecond + + public int? SelectedSecond + { + get { return (int?)GetValue(SelectedSecondProperty); } + set { SetValue(SelectedSecondProperty, value); } + } + + public static readonly DependencyProperty SelectedSecondProperty = + DependencyProperty.Register("SelectedSecond", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedSecondChanged)); + + private static void SelectedSecondChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TimeSelector timeSelector = d as TimeSelector; + + timeSelector.Second = e.NewValue == null ? 0 : (int)e.NewValue; + timeSelector.SetSelectedTime(); + } + + #endregion + + #region ItemHeight + public double ItemHeight + { + get { return (double)GetValue(ItemHeightProperty); } + set { SetValue(ItemHeightProperty, value); } + } + + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), typeof(TimeSelector), new PropertyMetadata(28.0)); + #endregion + + #endregion + + #region Constructors + static TimeSelector() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeSelector), new FrameworkPropertyMetadata(typeof(TimeSelector))); + } + #endregion + + #region Override方法 + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + this.PART_Hour = this.GetTemplateChild("PART_Hour") as ListBox; + this.PART_Minute = this.GetTemplateChild("PART_Minute") as ListBox; + this.PART_Second = this.GetTemplateChild("PART_Second") as ListBox; + + if (this.PART_Hour != null) + { + this.CreateHourButtons(); + this.PART_Hour.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(HourButton_Click), true); + } + + if (this.PART_Minute != null) + { + this.CreateMinuteButtons(); + this.PART_Minute.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(MinuteButton_Click), true); + } + + if (this.PART_Second != null) + { + this.CreateSecondButtons(); + this.PART_Second.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(SecondButton_Click), true); + } + } + #endregion + + #region Private方法 + + private void MinuteButton_Click(object sender, RoutedEventArgs e) + { + TimeButton selectedItem = this.PART_Minute.SelectedItem as TimeButton; + if (selectedItem == null) + { + return; + } + this.SelectedMinute = Convert.ToInt32(selectedItem.DataContext); + this.PART_Minute.AnimateScrollIntoView(selectedItem); + } + + private void SecondButton_Click(object sender, RoutedEventArgs e) + { + TimeButton selectedItem = this.PART_Second.SelectedItem as TimeButton; + if (selectedItem == null) + { + return; + } + this.SelectedSecond = Convert.ToInt32(selectedItem.DataContext); + this.PART_Second.AnimateScrollIntoView(selectedItem); + } + + private void HourButton_Click(object sender, RoutedEventArgs e) + { + TimeButton selectedItem = this.PART_Hour.SelectedItem as TimeButton; + if (selectedItem == null) + { + return; + } + this.SelectedHour = Convert.ToInt32(selectedItem.DataContext); + this.PART_Hour.AnimateScrollIntoView(selectedItem); + } + + private void CreateHourButtons() + { + this.CreateItems(24, this.HourButtons); + this.CreateExtraItem(this.HourButtons); + this.PART_Hour.ItemsSource = this.HourButtons; + } + + private void CreateMinuteButtons() + { + this.CreateItems(60, this.MinuteButtons); + this.CreateExtraItem(this.MinuteButtons); + this.PART_Minute.ItemsSource = this.MinuteButtons; + } + + private void CreateSecondButtons() + { + this.CreateItems(60, this.SecondButtons); + this.CreateExtraItem(this.SecondButtons); + this.PART_Second.ItemsSource = this.SecondButtons; + } + + private void CreateItems(int itemsCount, ObservableCollection list) + { + for (int i = 0; i < itemsCount; i++) + { + TimeButton timeButton = new TimeButton(); + timeButton.SetValue(TimeButton.HeightProperty, this.ItemHeight); + timeButton.SetValue(TimeButton.DataContextProperty, i); + timeButton.SetValue(TimeButton.ContentProperty, (i < 10) ? "0" + i : i.ToString()); + timeButton.SetValue(TimeButton.IsSelectedProperty, false); + list.Add(timeButton); + } + } + + private void CreateExtraItem(ObservableCollection list) + { + double height = this.ItemHeight; + if (this.Owner != null) + { + height = this.Owner.DropDownHeight; + } + else + { + height = double.IsNaN(this.Height) ? height : this.Height; + } + + for (int i = 0; i < (height - this.ItemHeight) / this.ItemHeight; i++) + { + TimeButton timeButton = new TimeButton(); + timeButton.SetValue(TimeButton.HeightProperty, this.ItemHeight); + timeButton.SetValue(TimeButton.IsEnabledProperty, false); + timeButton.SetValue(TimeButton.IsSelectedProperty, false); + list.Add(timeButton); + } + } + + private DateTime GetDateTime(int hour, int minute, int second) + { + DateTime dt = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, hour, minute, second); + return dt; + } + + /// + /// 设置选中的时间 + /// + private void SetSelectedTime() + { + DateTime dt = this.GetDateTime(this.Hour, this.Minute, this.Second); + this.SelectedTime = dt; + } + #endregion + } + public class ScrollViewerBehavior + { + public static DependencyProperty VerticalOffsetProperty = + DependencyProperty.RegisterAttached("VerticalOffset", + typeof(double), + typeof(ScrollViewerBehavior), + new UIPropertyMetadata(0.0, OnVerticalOffsetChanged)); + + public static void SetVerticalOffset(FrameworkElement target, double value) + { + target.SetValue(VerticalOffsetProperty, value); + } + public static double GetVerticalOffset(FrameworkElement target) + { + return (double)target.GetValue(VerticalOffsetProperty); + } + private static void OnVerticalOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) + { + ScrollViewer scrollViewer = target as ScrollViewer; + if (scrollViewer != null) + { + scrollViewer.ScrollToVerticalOffset((double)e.NewValue); + } + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 7006f532..801e85b4 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -98,8 +98,12 @@ + + + + @@ -698,6 +702,14 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + Designer MSBuild:Compile diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml index 5a971e9d..56d1f56c 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml @@ -63,6 +63,8 @@ + + \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml new file mode 100644 index 00000000..ff291905 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml new file mode 100644 index 00000000..3dd43aaa --- /dev/null +++ b/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml @@ -0,0 +1,89 @@ + + + + + + + + + \ No newline at end of file From cf879b9c83cdb4729198bf68936b633ce1572348 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 12 May 2019 01:22:31 +0800 Subject: [PATCH 3/8] temporarily evaded a amazing bug in demo --- .../UserControl/Main/LeftMainContent.xaml | 2 +- .../UserControl/Main/LeftMainContent.xaml.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml index 49b8368a..5ec9a609 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml @@ -161,7 +161,7 @@ - + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml.cs b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml.cs index 3eb55a71..f7a69289 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml.cs @@ -16,6 +16,13 @@ namespace HandyControlDemo.UserControl public LeftMainContent() { InitializeComponent(); + + /*You have to ask me why I made Border special. + What drives me crazy is that if you don't do this, + the content of ListBoxItemBorder will always be 1 ! + How amazing! + I wish someone could tell me why. */ + ListBoxItemBorder.Content = Properties.Langs.Lang.Border; } private void TabControl_OnSelectionChanged(object sender, SelectionChangedEventArgs e) From 583c6413023e91c606ab8fdfb2479326ad6a07d4 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 12 May 2019 20:20:04 +0800 Subject: [PATCH 4/8] modified the pr --- .../Controls/TimePickerDemoCtl.xaml | 8 +- .../Controls/Input/DateTimePicker.cs | 9 - .../Controls/Input/TimePicker.cs | 76 ++-- .../Controls/Other/ScrollViewer.cs | 8 +- .../Controls/Time/Clock/Clock.cs | 129 +----- .../Controls/Time/Clock/ClockBase.cs | 106 +++++ .../Controls/Time/Clock/ListClock.cs | 148 +++++++ .../Controls/Time/ItemsControlExtensions.cs | 79 ---- .../Controls/Time/TimeButton.cs | 42 -- .../Controls/Time/TimePickerList.cs | 114 ------ .../Controls/Time/TimeSelector.cs | 380 ------------------ .../Data/Gif/GifImageInfo.cs | 1 + .../HandyControl_Shared.projitems | 14 +- .../Themes/Styles/Clock.xaml | 73 +++- .../Themes/Styles/Style.xaml | 2 - .../Themes/Styles/TimePickerList.xaml | 88 ---- .../Themes/Styles/TimeSelector.xaml | 89 ---- .../Tools/GifImageAnimator.cs | 3 +- 18 files changed, 395 insertions(+), 974 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/Clock/ClockBase.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Time/Clock/ListClock.cs delete mode 100644 src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs delete mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs delete mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs delete mode 100644 src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs delete mode 100644 src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml delete mode 100644 src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml index 63143963..0c4355c8 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TimePickerDemoCtl.xaml @@ -7,8 +7,6 @@ - - @@ -19,7 +17,11 @@ - + + + + + diff --git a/src/Shared/HandyControl_Shared/Controls/Input/DateTimePicker.cs b/src/Shared/HandyControl_Shared/Controls/Input/DateTimePicker.cs index c32c83ec..c76112b6 100644 --- a/src/Shared/HandyControl_Shared/Controls/Input/DateTimePicker.cs +++ b/src/Shared/HandyControl_Shared/Controls/Input/DateTimePicker.cs @@ -99,15 +99,6 @@ namespace HandyControl.Controls set => SetValue(DateTimeFormatProperty, value); } - public static readonly DependencyProperty ClockStyleProperty = DependencyProperty.Register( - "ClockStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style))); - - public Style ClockStyle - { - get => (Style) GetValue(ClockStyleProperty); - set => SetValue(ClockStyleProperty, value); - } - public static readonly DependencyProperty CalendarStyleProperty = DependencyProperty.Register( "CalendarStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style))); diff --git a/src/Shared/HandyControl_Shared/Controls/Input/TimePicker.cs b/src/Shared/HandyControl_Shared/Controls/Input/TimePicker.cs index 25d005de..021d7f7a 100644 --- a/src/Shared/HandyControl_Shared/Controls/Input/TimePicker.cs +++ b/src/Shared/HandyControl_Shared/Controls/Input/TimePicker.cs @@ -34,8 +34,6 @@ namespace HandyControl.Controls #region Data - private Clock _clock; - private string _defaultText; private ButtonBase _dropDownButton; @@ -79,7 +77,7 @@ namespace HandyControl.Controls public TimePicker() { - InitClock(); + Clock = new Clock(); CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => { ClearValue(SelectedTimeProperty); @@ -103,18 +101,6 @@ namespace HandyControl.Controls #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 @@ -133,8 +119,8 @@ namespace HandyControl.Controls private static object CoerceDisplayTime(DependencyObject d, object value) { var dp = (TimePicker)d; - dp._clock.DisplayTime = (DateTime)value; - return dp._clock.DisplayTime; + dp.Clock.DisplayTime = (DateTime)value; + return dp.Clock.DisplayTime; } #endregion DisplayTime @@ -170,7 +156,7 @@ namespace HandyControl.Controls dp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate { - dp._clock.Focus(); + dp.Clock.Focus(); }); } } @@ -212,8 +198,8 @@ namespace HandyControl.Controls private static object CoerceSelectedTime(DependencyObject d, object value) { var dp = (TimePicker)d; - dp._clock.SelectedTime = (DateTime?)value; - return dp._clock.SelectedTime; + dp.Clock.SelectedTime = (DateTime?)value; + return dp.Clock.SelectedTime; } #endregion SelectedDate @@ -306,6 +292,35 @@ namespace HandyControl.Controls set => SetValue(ShowClearButtonProperty, value); } + public static readonly DependencyProperty ClockProperty = DependencyProperty.Register( + "Clock", typeof(ClockBase), typeof(TimePicker), new FrameworkPropertyMetadata(default(Clock), FrameworkPropertyMetadataOptions.NotDataBindable, OnClockChanged)); + + private static void OnClockChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (TimePicker) d; + var oldClock = e.OldValue as ClockBase; + var newClock = e.NewValue as ClockBase; + + if (oldClock != null) + { + oldClock.SelectedTimeChanged -= ctl.Clock_SelectedTimeChanged; + oldClock.Confirmed -= ctl.Clock_Confirmed; + } + + if (newClock != null) + { + newClock.ShowConfirmButton = true; + newClock.SelectedTimeChanged += ctl.Clock_SelectedTimeChanged; + newClock.Confirmed += ctl.Clock_Confirmed; + } + } + + public ClockBase Clock + { + get => (ClockBase) GetValue(ClockProperty); + set => SetValue(ClockProperty, value); + } + #endregion Public Properties #region Public Methods @@ -374,7 +389,7 @@ namespace HandyControl.Controls _popUp.PreviewMouseLeftButtonDown += PopUp_PreviewMouseLeftButtonDown; _popUp.Opened += PopUp_Opened; _popUp.Closed += PopUp_Closed; - _popUp.Child = _clock; + _popUp.Child = Clock; if (IsDropDownOpen) { @@ -439,20 +454,7 @@ namespace HandyControl.Controls throw new Exception(); } - private void InitClock() - { - _clock = new Clock - { - ShowConfirmButton = true - }; - _clock.SelectedTimeChanged += Clock_SelectedTimeChanged; - _clock.Confirmed += Clock_Confirmed; - } - - private void TextBox_LostFocus(object sender, RoutedEventArgs e) - { - SetSelectedTime(); - } + private void TextBox_LostFocus(object sender, RoutedEventArgs e) => SetSelectedTime(); private void SetIsHandlerSuspended(DependencyProperty property, bool value) { @@ -560,7 +562,7 @@ namespace HandyControl.Controls SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox); } - _clock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); + Clock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); OnClockOpened(new RoutedEventArgs()); } @@ -572,7 +574,7 @@ namespace HandyControl.Controls SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox); } - if (_clock.IsKeyboardFocusWithin) + if (Clock.IsKeyboardFocusWithin) { MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } diff --git a/src/Shared/HandyControl_Shared/Controls/Other/ScrollViewer.cs b/src/Shared/HandyControl_Shared/Controls/Other/ScrollViewer.cs index a6734670..764f4c3e 100644 --- a/src/Shared/HandyControl_Shared/Controls/Other/ScrollViewer.cs +++ b/src/Shared/HandyControl_Shared/Controls/Other/ScrollViewer.cs @@ -192,7 +192,7 @@ namespace HandyControl.Controls /// /// 当前垂直滚动偏移 /// - private static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register( + internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register( "CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentVerticalOffsetChanged)); private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -206,7 +206,7 @@ namespace HandyControl.Controls /// /// 当前垂直滚动偏移 /// - private double CurrentVerticalOffset + internal double CurrentVerticalOffset { // ReSharper disable once UnusedMember.Local get => (double) GetValue(CurrentVerticalOffsetProperty); @@ -216,7 +216,7 @@ namespace HandyControl.Controls /// /// 当前水平滚动偏移 /// - public static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register( + internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register( "CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentHorizontalOffsetChanged)); private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -230,7 +230,7 @@ namespace HandyControl.Controls /// /// 当前水平滚动偏移 /// - public double CurrentHorizontalOffset + internal double CurrentHorizontalOffset { get => (double) GetValue(CurrentHorizontalOffsetProperty); set => SetValue(CurrentHorizontalOffsetProperty, value); diff --git a/src/Shared/HandyControl_Shared/Controls/Time/Clock/Clock.cs b/src/Shared/HandyControl_Shared/Controls/Time/Clock/Clock.cs index ca43b8da..7c0dead1 100644 --- a/src/Shared/HandyControl_Shared/Controls/Time/Clock/Clock.cs +++ b/src/Shared/HandyControl_Shared/Controls/Time/Clock/Clock.cs @@ -6,26 +6,23 @@ 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 + public class Clock : ClockBase { #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"; @@ -40,8 +37,6 @@ namespace HandyControl.Controls private RadioButton _buttonPm; - private Button _buttonConfirm; - private Canvas _canvas; private Border _borderTitle; @@ -60,59 +55,10 @@ namespace HandyControl.Controls private int _secValue; - 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 - #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.DisplayTime = v ?? DateTime.Now; - 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))); @@ -122,32 +68,6 @@ namespace HandyControl.Controls set => SetValue(ClockRadioButtonStyleProperty, value); } - public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register( - "DisplayTime", typeof(DateTime), typeof(Clock), new FrameworkPropertyMetadata(DateTime.Now, 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(ValueBoxes.FalseBox)); - - internal bool ShowConfirmButton - { - get => (bool)GetValue(ShowConfirmButtonProperty); - set => SetValue(ShowConfirmButtonProperty, value); - } - private int SecValue { get => _secValue; @@ -174,7 +94,7 @@ namespace HandyControl.Controls public override void OnApplyTemplate() { - _appliedTemplate = false; + AppliedTemplate = false; if (_buttonAm != null) { _buttonAm.Click -= ButtonAm_OnClick; @@ -185,9 +105,9 @@ namespace HandyControl.Controls _buttonPm.Click -= ButtonPm_OnClick; } - if (_buttonConfirm != null) + if (ButtonConfirm != null) { - _buttonConfirm.Click -= ButtonConfirm_OnClick; + ButtonConfirm.Click -= ButtonConfirm_OnClick; } if (_borderTitle != null) @@ -206,18 +126,18 @@ namespace HandyControl.Controls _buttonAm = GetTemplateChild(ElementButtonAm) as RadioButton; _buttonPm = GetTemplateChild(ElementButtonPm) as RadioButton; - _buttonConfirm = GetTemplateChild(ElementButtonConfirm) as Button; + 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(); + if (!CheckNull()) return; _buttonAm.Click += ButtonAm_OnClick; _buttonPm.Click += ButtonPm_OnClick; - _buttonConfirm.Click += ButtonConfirm_OnClick; + ButtonConfirm.Click += ButtonConfirm_OnClick; _borderTitle.MouseWheel += BorderTitle_OnMouseWheel; _canvas.MouseWheel += Canvas_OnMouseWheel; @@ -241,7 +161,7 @@ namespace HandyControl.Controls _circlePanel.Children.Add(button); } - _appliedTemplate = true; + AppliedTemplate = true; if (SelectedTime.HasValue) { Update(SelectedTime.Value); @@ -255,26 +175,15 @@ namespace HandyControl.Controls #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() + private bool CheckNull() { - - if (_buttonPm == null || _buttonAm == null || _buttonConfirm == null || _canvas == null || + if (_buttonPm == null || _buttonAm == null || ButtonConfirm == null || _canvas == null || _borderTitle == null || _borderClock == null || _circlePanel == null || - _blockTime == null) throw new Exception(); + _blockTime == null) return false; + + return true; } private void BorderTitle_OnMouseWheel(object sender, MouseWheelEventArgs e) @@ -339,7 +248,7 @@ namespace HandyControl.Controls private void Update() { - if (!_appliedTemplate) return; + if (!AppliedTemplate) return; var hValue = _currentButton.Num; if (_buttonPm.IsChecked == true) { @@ -367,9 +276,9 @@ namespace HandyControl.Controls /// 更新 /// /// - internal void Update(DateTime time) + internal override void Update(DateTime time) { - if (!_appliedTemplate) return; + if (!AppliedTemplate) return; var h = time.Hour; var m = time.Minute; @@ -396,12 +305,6 @@ namespace HandyControl.Controls Update(); } - private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e) - { - SelectedTime = DisplayTime; - Confirmed?.Invoke(); - } - /// /// 获取显示时间 /// diff --git a/src/Shared/HandyControl_Shared/Controls/Time/Clock/ClockBase.cs b/src/Shared/HandyControl_Shared/Controls/Time/Clock/ClockBase.cs new file mode 100644 index 00000000..c2ef4420 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/Clock/ClockBase.cs @@ -0,0 +1,106 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + [TemplatePart(Name = ElementButtonConfirm, Type = typeof(Button))] + public abstract class ClockBase : Control + { + protected const string ElementButtonConfirm = "PART_ButtonConfirm"; + + protected Button ButtonConfirm; + + protected bool AppliedTemplate; + + public event Action Confirmed; + + public event EventHandler> DisplayTimeChanged; + + public static readonly RoutedEvent SelectedTimeChangedEvent = + EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Direct, + typeof(EventHandler>), typeof(ClockBase)); + + public event EventHandler> SelectedTimeChanged + { + add => AddHandler(SelectedTimeChangedEvent, value); + remove => RemoveHandler(SelectedTimeChangedEvent, value); + } + + public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register( + "TimeFormat", typeof(string), typeof(ClockBase), new PropertyMetadata("HH:mm:ss")); + + public string TimeFormat + { + get => (string)GetValue(TimeFormatProperty); + set => SetValue(TimeFormatProperty, value); + } + + public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register( + "SelectedTime", typeof(DateTime?), typeof(ClockBase), new PropertyMetadata(default(DateTime?), OnSelectedTimeChanged)); + + private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (ClockBase)d; + var v = (DateTime?)e.NewValue; + ctl.DisplayTime = v ?? DateTime.Now; + ctl.OnSelectedTimeChanged(new FunctionEventArgs(SelectedTimeChangedEvent, ctl) + { + Info = v + }); + } + + public DateTime? SelectedTime + { + get => (DateTime?) GetValue(SelectedTimeProperty); + set => SetValue(SelectedTimeProperty, value); + } + + public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register( + "DisplayTime", typeof(DateTime), typeof(ClockBase), + new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, + OnDisplayTimeChanged)); + + private static void OnDisplayTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (ClockBase)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(ClockBase), new PropertyMetadata(ValueBoxes.FalseBox)); + + internal bool ShowConfirmButton + { + get => (bool) GetValue(ShowConfirmButtonProperty); + set => SetValue(ShowConfirmButtonProperty, value); + } + + protected virtual void OnSelectedTimeChanged(FunctionEventArgs e) => RaiseEvent(e); + + protected virtual void OnDisplayTimeChanged(FunctionEventArgs e) + { + var handler = DisplayTimeChanged; + handler?.Invoke(this, e); + } + + protected void ButtonConfirm_OnClick(object sender, RoutedEventArgs e) + { + SelectedTime = DisplayTime; + Confirmed?.Invoke(); + } + + internal abstract void Update(DateTime time); + + protected void Clock_SelectedTimeChanged(object sender, FunctionEventArgs e) => SelectedTime = e.Info; + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/Clock/ListClock.cs b/src/Shared/HandyControl_Shared/Controls/Time/Clock/ListClock.cs new file mode 100644 index 00000000..80376a1d --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Time/Clock/ListClock.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; + +namespace HandyControl.Controls +{ + [TemplatePart(Name = ElementHourList, Type = typeof(ListBox))] + [TemplatePart(Name = ElementMinuteList, Type = typeof(ListBox))] + [TemplatePart(Name = ElementSecondList, Type = typeof(ListBox))] + public class ListClock : ClockBase + { + #region Constants + + private const string ElementHourList = "PART_HourList"; + private const string ElementMinuteList = "PART_MinuteList"; + private const string ElementSecondList = "PART_SecondList"; + + #endregion Constants + + #region Data + + private ListBox _hourList; + + private ListBox _minuteList; + + private ListBox _secondList; + + #endregion Data + + public override void OnApplyTemplate() + { + AppliedTemplate = false; + if (ButtonConfirm != null) + { + ButtonConfirm.Click -= ButtonConfirm_OnClick; + } + + if (_hourList != null) + { + _hourList.SelectionChanged -= HourList_SelectionChanged; + } + + if (_minuteList != null) + { + _minuteList.SelectionChanged -= MinuteList_SelectionChanged; + } + + if (_secondList != null) + { + _secondList.SelectionChanged -= SecondList_SelectionChanged; + } + + base.OnApplyTemplate(); + + _hourList = GetTemplateChild(ElementHourList) as ListBox; + if (_hourList != null) + { + CreateItemsSource(_hourList, 24); + _hourList.SelectionChanged += HourList_SelectionChanged; + } + + _minuteList = GetTemplateChild(ElementMinuteList) as ListBox; + if (_minuteList != null) + { + CreateItemsSource(_minuteList, 60); + _minuteList.SelectionChanged += MinuteList_SelectionChanged; + } + + _secondList = GetTemplateChild(ElementSecondList) as ListBox; + if (_secondList != null) + { + CreateItemsSource(_secondList, 60); + _secondList.SelectionChanged += SecondList_SelectionChanged; + } + + ButtonConfirm = GetTemplateChild(ElementButtonConfirm) as Button; + + if (ButtonConfirm != null) + { + ButtonConfirm.Click += ButtonConfirm_OnClick; + } + + AppliedTemplate = true; + if (SelectedTime.HasValue) + { + Update(SelectedTime.Value); + } + else + { + DisplayTime = DateTime.Now; + Update(DisplayTime); + } + } + + private void HourList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update(); + + private void MinuteList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update(); + + private void SecondList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update(); + + private void CreateItemsSource(ItemsControl selector, int count) + { + var list = new List(); + for (int i = 0; i < count; i++) + { + list.Add(i.ToString("#00")); + } + + selector.ItemsSource = list; + } + + private void Update() + { + if (_hourList.SelectedIndex >= 0 && _hourList.SelectedIndex < 24 && + _minuteList.SelectedIndex >= 0 && _minuteList.SelectedIndex < 60 && + _secondList.SelectedIndex >= 0 && _secondList.SelectedIndex < 60) + { + var now = DateTime.Now; + DisplayTime = new DateTime(now.Year, now.Month, now.Day, _hourList.SelectedIndex, + _minuteList.SelectedIndex, _secondList.SelectedIndex); + } + } + + /// + /// 更新 + /// + /// + internal override void Update(DateTime time) + { + if (!AppliedTemplate) return; + + var h = time.Hour; + var m = time.Minute; + var s = time.Second; + + _hourList.SelectedIndex = h; + _minuteList.SelectedIndex = m; + _secondList.SelectedIndex = s; + + _hourList.ScrollIntoView(_hourList.SelectedItem); + _minuteList.ScrollIntoView(_minuteList.SelectedItem); + _secondList.ScrollIntoView(_secondList.SelectedItem); + + DisplayTime = time; + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs b/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs deleted file mode 100644 index 8cea4c60..00000000 --- a/src/Shared/HandyControl_Shared/Controls/Time/ItemsControlExtensions.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Animation; - -namespace HandyControl.Controls -{ - /// - /// ItemsControl扩展方法 - /// - public static class ItemsControlExtensions - { - /// - /// 平滑滚动至指定元素 - /// - /// - /// - public static void AnimateScrollIntoView(this ItemsControl itemsControl, object item) - { - ScrollViewer scrollViewer = FindVisualChild(itemsControl); - if (scrollViewer == null) - { - return; - } - - UIElement container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement; - - if (container == null) - { - return; - } - - int index = itemsControl.ItemContainerGenerator.IndexFromContainer(container); - - //平滑滚动到元素所在位置 - //double toValue = scrollViewer.ScrollableHeight * ((double)index / itemsControl.Items.Count); - //平滑滚动,将选中的元素置顶 - double toValue = VisualTreeHelper.GetOffset(container).Y; - - DoubleAnimation verticalAnimation = new DoubleAnimation(); - verticalAnimation.From = scrollViewer.VerticalOffset; - verticalAnimation.To = toValue; - verticalAnimation.DecelerationRatio = .2; - verticalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(200)); - Storyboard storyboard = new Storyboard(); - storyboard.Children.Add(verticalAnimation); - Storyboard.SetTarget(verticalAnimation, scrollViewer); - Storyboard.SetTargetProperty(verticalAnimation, new PropertyPath(ScrollViewerBehavior.VerticalOffsetProperty)); - storyboard.Begin(); - } - - /// - /// 查找元素的子元素 - /// - /// 子元素类型 - /// - /// - public static T FindVisualChild(DependencyObject obj) where T : DependencyObject - { - for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) - { - DependencyObject child = VisualTreeHelper.GetChild(obj, i); - if (child != null && child is T) - return (T)child; - else - { - T childOfChild = FindVisualChild(child); - if (childOfChild != null) - return childOfChild; - } - } - return null; - } - } -} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs deleted file mode 100644 index 751bb887..00000000 --- a/src/Shared/HandyControl_Shared/Controls/Time/TimeButton.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; - -namespace HandyControl.Controls -{ - public class TimeButton : ListBoxItem - { - #region Private属性 - #endregion - - #region 依赖属性定义 - - #endregion - - #region 依赖属性set get - - #endregion - - #region Constructors - static TimeButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeButton), new FrameworkPropertyMetadata(typeof(TimeButton))); - } - #endregion - - #region Override方法 - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - } - #endregion - - #region Private方法 - - #endregion - } -} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs deleted file mode 100644 index 9605dfc0..00000000 --- a/src/Shared/HandyControl_Shared/Controls/Time/TimePickerList.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; - -namespace HandyControl.Controls -{ - public class TimePickerList : Control - { - #region Private属性 - private TextBox PART_TextBox; - private TimeSelector PART_TimeSelector; - private Popup PART_Popup; - #endregion - - #region 依赖属性定义 - - #endregion - - #region 依赖属性set get - - #region TimeStringFormat - public string TimeStringFormat - { - get { return (string)GetValue(TimeStringFormatProperty); } - set { SetValue(TimeStringFormatProperty, value); } - } - - public static readonly DependencyProperty TimeStringFormatProperty = - DependencyProperty.Register("TimeStringFormat", typeof(string), typeof(TimePickerList), new PropertyMetadata("HH:mm:ss")); - #endregion - - #region SelectedTime - public DateTime? SelectedTime - { - get { return (DateTime?)GetValue(SelectedTimeProperty); } - set { SetValue(SelectedTimeProperty, value); } - } - - public static readonly DependencyProperty SelectedTimeProperty = - DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimePickerList), new PropertyMetadata(null, SelectedTimeChangedCallback)); - - private static void SelectedTimeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TimePickerList timePicker = d as TimePickerList; - DateTime dt = (DateTime)e.NewValue; - - timePicker.PART_TimeSelector.SelectedTime = dt; - } - #endregion - - #region DropDownHeight - - public double DropDownHeight - { - get { return (double)GetValue(DropDownHeightProperty); } - set { SetValue(DropDownHeightProperty, value); } - } - - public static readonly DependencyProperty DropDownHeightProperty = - DependencyProperty.Register("DropDownHeight", typeof(double), typeof(TimePickerList), new PropertyMetadata(168d)); - - #endregion - - #endregion - - #region Constructors - static TimePickerList() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePickerList), new FrameworkPropertyMetadata(typeof(TimePickerList))); - } - #endregion - - #region Override方法 - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - this.PART_TextBox = this.GetTemplateChild("PART_TextBox") as TextBox; - this.PART_TimeSelector = this.GetTemplateChild("PART_TimeSelector") as TimeSelector; - this.PART_Popup = this.GetTemplateChild("PART_Popup") as Popup; - if (this.PART_TimeSelector != null) - { - this.PART_TimeSelector.Owner = this; - this.PART_TimeSelector.SelectedTimeChanged += PART_TimeSelector_SelectedTimeChanged; - } - if (this.PART_Popup != null) - { - this.PART_Popup.Opened += PART_Popup_Opened; - } - } - - private void PART_Popup_Opened(object sender, EventArgs e) - { - this.PART_TimeSelector.SetButtonSelected(); - } - #endregion - - #region Private方法 - private void PART_TimeSelector_SelectedTimeChanged(object sender, RoutedPropertyChangedEventArgs e) - { - if (this.PART_TextBox != null && e.NewValue != null) - { - this.PART_TextBox.Text = e.NewValue.Value.ToString(this.TimeStringFormat); - this.SelectedTime = e.NewValue; - } - } - #endregion - } -} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs b/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs deleted file mode 100644 index e2eb030a..00000000 --- a/src/Shared/HandyControl_Shared/Controls/Time/TimeSelector.cs +++ /dev/null @@ -1,380 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Animation; - -namespace HandyControl.Controls -{ - public class TimeSelector : Control - { - private ObservableCollection HourButtons = new ObservableCollection(); - private ObservableCollection MinuteButtons = new ObservableCollection(); - private ObservableCollection SecondButtons = new ObservableCollection(); - - #region 控件内部元素 - private ListBox PART_Hour; - private ListBox PART_Minute; - private ListBox PART_Second; - #endregion - - #region 私有属性 - private int Hour = 0; - private int Minute = 0; - private int Second = 0; - #endregion - - #region Fields - public TimePickerList Owner { get; set; } - #endregion - - #region 事件定义 - - #region SelectedTimeChanged - public static readonly RoutedEvent SelectedTimeChangedEvent = EventManager.RegisterRoutedEvent("SelectedTimeChanged", - RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(TimeSelector)); - - public event RoutedPropertyChangedEventHandler SelectedTimeChanged - { - add - { - this.AddHandler(SelectedTimeChangedEvent, value); - } - remove - { - this.RemoveHandler(SelectedTimeChangedEvent, value); - } - } - - public virtual void OnSelectedTimeChanged(DateTime? oldValue, DateTime? newValue) - { - RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, SelectedTimeChangedEvent); - this.RaiseEvent(arg); - } - #endregion - - #endregion - - #region 依赖属性set get - - #region SelectedTime - public DateTime? SelectedTime - { - get { return (DateTime?)GetValue(SelectedTimeProperty); } - set { SetValue(SelectedTimeProperty, value); } - } - - public static readonly DependencyProperty SelectedTimeProperty = - DependencyProperty.Register("SelectedTime", typeof(DateTime?), typeof(TimeSelector), new PropertyMetadata(null, SelectedTimeChangedCallback)); - - private static void SelectedTimeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TimeSelector timeSelector = d as TimeSelector; - DateTime dt = (DateTime)e.NewValue; - - timeSelector.SetButtonSelected(); - - timeSelector.OnSelectedTimeChanged((DateTime?)e.OldValue, (DateTime?)e.NewValue); - } - - public void SetButtonSelected() - { - if (!this.SelectedTime.HasValue) - { - return; - } - - this.Hour = this.SelectedTime.Value.Hour; - this.Minute = this.SelectedTime.Value.Minute; - this.Second = this.SelectedTime.Value.Second; - - if (this.PART_Hour != null) - { - for (int i = 0; i < this.PART_Hour.Items.Count; i++) - { - TimeButton timeButton = this.PART_Hour.Items[i] as TimeButton; - if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Hour))) - { - this.PART_Hour.SelectedIndex = i; - this.PART_Hour.AnimateScrollIntoView(timeButton); - break; - } - } - } - - if (this.PART_Minute != null) - { - for (int i = 0; i < this.PART_Minute.Items.Count; i++) - { - TimeButton timeButton = this.PART_Minute.Items[i] as TimeButton; - if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Minute))) - { - this.PART_Minute.SelectedIndex = i; - this.PART_Minute.AnimateScrollIntoView(timeButton); - break; - } - } - } - - if (this.PART_Second != null) - { - for (int i = 0; i < this.PART_Second.Items.Count; i++) - { - TimeButton timeButton = this.PART_Second.Items[i] as TimeButton; - if (Convert.ToString(timeButton.Content).Equals(Convert.ToString(this.SelectedTime.Value.Second))) - { - this.PART_Second.SelectedIndex = i; - this.PART_Second.AnimateScrollIntoView(timeButton); - break; - } - } - } - } - #endregion - - #region SelectedHour - public int? SelectedHour - { - get { return (int?)GetValue(SelectedHourProperty); } - set { SetValue(SelectedHourProperty, value); } - } - - public static readonly DependencyProperty SelectedHourProperty = - DependencyProperty.Register("SelectedHour", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedHourChanged)); - - private static void SelectedHourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TimeSelector timeSelector = d as TimeSelector; - timeSelector.Hour = e.NewValue == null ? 0 : (int)e.NewValue; - timeSelector.SetSelectedTime(); - } - #endregion - - #region SelectedMinute - - public int? SelectedMinute - { - get { return (int?)GetValue(SelectedMinuteProperty); } - set { SetValue(SelectedMinuteProperty, value); } - } - - public static readonly DependencyProperty SelectedMinuteProperty = - DependencyProperty.Register("SelectedMinute", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedMinuteChanged)); - - private static void SelectedMinuteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TimeSelector timeSelector = d as TimeSelector; - - timeSelector.Minute = e.NewValue == null ? 0 : (int)e.NewValue; - timeSelector.SetSelectedTime(); - } - - #endregion - - #region SelectedSecond - - public int? SelectedSecond - { - get { return (int?)GetValue(SelectedSecondProperty); } - set { SetValue(SelectedSecondProperty, value); } - } - - public static readonly DependencyProperty SelectedSecondProperty = - DependencyProperty.Register("SelectedSecond", typeof(int?), typeof(TimeSelector), new PropertyMetadata(null, SelectedSecondChanged)); - - private static void SelectedSecondChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TimeSelector timeSelector = d as TimeSelector; - - timeSelector.Second = e.NewValue == null ? 0 : (int)e.NewValue; - timeSelector.SetSelectedTime(); - } - - #endregion - - #region ItemHeight - public double ItemHeight - { - get { return (double)GetValue(ItemHeightProperty); } - set { SetValue(ItemHeightProperty, value); } - } - - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), typeof(TimeSelector), new PropertyMetadata(28.0)); - #endregion - - #endregion - - #region Constructors - static TimeSelector() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeSelector), new FrameworkPropertyMetadata(typeof(TimeSelector))); - } - #endregion - - #region Override方法 - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - this.PART_Hour = this.GetTemplateChild("PART_Hour") as ListBox; - this.PART_Minute = this.GetTemplateChild("PART_Minute") as ListBox; - this.PART_Second = this.GetTemplateChild("PART_Second") as ListBox; - - if (this.PART_Hour != null) - { - this.CreateHourButtons(); - this.PART_Hour.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(HourButton_Click), true); - } - - if (this.PART_Minute != null) - { - this.CreateMinuteButtons(); - this.PART_Minute.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(MinuteButton_Click), true); - } - - if (this.PART_Second != null) - { - this.CreateSecondButtons(); - this.PART_Second.AddHandler(ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(SecondButton_Click), true); - } - } - #endregion - - #region Private方法 - - private void MinuteButton_Click(object sender, RoutedEventArgs e) - { - TimeButton selectedItem = this.PART_Minute.SelectedItem as TimeButton; - if (selectedItem == null) - { - return; - } - this.SelectedMinute = Convert.ToInt32(selectedItem.DataContext); - this.PART_Minute.AnimateScrollIntoView(selectedItem); - } - - private void SecondButton_Click(object sender, RoutedEventArgs e) - { - TimeButton selectedItem = this.PART_Second.SelectedItem as TimeButton; - if (selectedItem == null) - { - return; - } - this.SelectedSecond = Convert.ToInt32(selectedItem.DataContext); - this.PART_Second.AnimateScrollIntoView(selectedItem); - } - - private void HourButton_Click(object sender, RoutedEventArgs e) - { - TimeButton selectedItem = this.PART_Hour.SelectedItem as TimeButton; - if (selectedItem == null) - { - return; - } - this.SelectedHour = Convert.ToInt32(selectedItem.DataContext); - this.PART_Hour.AnimateScrollIntoView(selectedItem); - } - - private void CreateHourButtons() - { - this.CreateItems(24, this.HourButtons); - this.CreateExtraItem(this.HourButtons); - this.PART_Hour.ItemsSource = this.HourButtons; - } - - private void CreateMinuteButtons() - { - this.CreateItems(60, this.MinuteButtons); - this.CreateExtraItem(this.MinuteButtons); - this.PART_Minute.ItemsSource = this.MinuteButtons; - } - - private void CreateSecondButtons() - { - this.CreateItems(60, this.SecondButtons); - this.CreateExtraItem(this.SecondButtons); - this.PART_Second.ItemsSource = this.SecondButtons; - } - - private void CreateItems(int itemsCount, ObservableCollection list) - { - for (int i = 0; i < itemsCount; i++) - { - TimeButton timeButton = new TimeButton(); - timeButton.SetValue(TimeButton.HeightProperty, this.ItemHeight); - timeButton.SetValue(TimeButton.DataContextProperty, i); - timeButton.SetValue(TimeButton.ContentProperty, (i < 10) ? "0" + i : i.ToString()); - timeButton.SetValue(TimeButton.IsSelectedProperty, false); - list.Add(timeButton); - } - } - - private void CreateExtraItem(ObservableCollection list) - { - double height = this.ItemHeight; - if (this.Owner != null) - { - height = this.Owner.DropDownHeight; - } - else - { - height = double.IsNaN(this.Height) ? height : this.Height; - } - - for (int i = 0; i < (height - this.ItemHeight) / this.ItemHeight; i++) - { - TimeButton timeButton = new TimeButton(); - timeButton.SetValue(TimeButton.HeightProperty, this.ItemHeight); - timeButton.SetValue(TimeButton.IsEnabledProperty, false); - timeButton.SetValue(TimeButton.IsSelectedProperty, false); - list.Add(timeButton); - } - } - - private DateTime GetDateTime(int hour, int minute, int second) - { - DateTime dt = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, hour, minute, second); - return dt; - } - - /// - /// 设置选中的时间 - /// - private void SetSelectedTime() - { - DateTime dt = this.GetDateTime(this.Hour, this.Minute, this.Second); - this.SelectedTime = dt; - } - #endregion - } - public class ScrollViewerBehavior - { - public static DependencyProperty VerticalOffsetProperty = - DependencyProperty.RegisterAttached("VerticalOffset", - typeof(double), - typeof(ScrollViewerBehavior), - new UIPropertyMetadata(0.0, OnVerticalOffsetChanged)); - - public static void SetVerticalOffset(FrameworkElement target, double value) - { - target.SetValue(VerticalOffsetProperty, value); - } - public static double GetVerticalOffset(FrameworkElement target) - { - return (double)target.GetValue(VerticalOffsetProperty); - } - private static void OnVerticalOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) - { - ScrollViewer scrollViewer = target as ScrollViewer; - if (scrollViewer != null) - { - scrollViewer.ScrollToVerticalOffset((double)e.NewValue); - } - } - } -} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Data/Gif/GifImageInfo.cs b/src/Shared/HandyControl_Shared/Data/Gif/GifImageInfo.cs index 6a786fec..2a1aedb3 100644 --- a/src/Shared/HandyControl_Shared/Data/Gif/GifImageInfo.cs +++ b/src/Shared/HandyControl_Shared/Data/Gif/GifImageInfo.cs @@ -1,5 +1,6 @@ using System; using HandyControl.Controls; +using HandyControl.Tools; namespace HandyControl.Data { diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 801e85b4..4a434741 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -95,15 +95,13 @@ + + - - - - @@ -702,14 +700,6 @@ Designer MSBuild:Compile - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - Designer MSBuild:Compile diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml index 21f81b18..c2051afd 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml @@ -6,6 +6,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml index 56d1f56c..5a971e9d 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml @@ -63,8 +63,6 @@ - - \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml deleted file mode 100644 index ff291905..00000000 --- a/src/Shared/HandyControl_Shared/Themes/Styles/TimePickerList.xaml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml deleted file mode 100644 index 3dd43aaa..00000000 --- a/src/Shared/HandyControl_Shared/Themes/Styles/TimeSelector.xaml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Tools/GifImageAnimator.cs b/src/Shared/HandyControl_Shared/Tools/GifImageAnimator.cs index 17e2219c..84586d8c 100644 --- a/src/Shared/HandyControl_Shared/Tools/GifImageAnimator.cs +++ b/src/Shared/HandyControl_Shared/Tools/GifImageAnimator.cs @@ -4,8 +4,9 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using HandyControl.Controls; +using HandyControl.Data; -namespace HandyControl.Data +namespace HandyControl.Tools { internal class ImageAnimator { From bc89baf2fa1c48e239441a4001bc3e6e08039a57 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 12 May 2019 20:27:02 +0800 Subject: [PATCH 5/8] update clock demo --- .../UserControl/Controls/ClockDemoCtl.xaml | 5 ++++- src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/ClockDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/ClockDemoCtl.xaml index 43122db0..95fd9b50 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/ClockDemoCtl.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/ClockDemoCtl.xaml @@ -4,6 +4,9 @@ xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl" Background="{DynamicResource RegionBrush}"> - + + + + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml index c2051afd..0d4012d0 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Clock.xaml @@ -137,7 +137,7 @@ @@ -165,8 +165,9 @@ - + +