diff --git a/HandyControl/Controls/TimeBar/SpeTextBlock.cs b/HandyControl/Controls/TimeBar/SpeTextBlock.cs new file mode 100644 index 00000000..d91ab67b --- /dev/null +++ b/HandyControl/Controls/TimeBar/SpeTextBlock.cs @@ -0,0 +1,51 @@ +using System; +using System.Windows.Controls; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + /// + /// 作为刻度使用的文字块 + /// + internal class SpeTextBlock : TextBlock + { + public double X { get; set; } + + public SpeTextBlock() => Width = 60; + + public SpeTextBlock(double x) : this() + { + X = x; + Canvas.SetLeft(this, X); + } + + /// + /// 时间 + /// + private DateTime _time; + + /// + /// 时间 + /// + public DateTime Time + { + get => _time; + set + { + _time = value; + Text = $"{value.ToString(TimeFormat)}\r\n|"; + } + } + + /// + /// 时间格式 + /// + public string TimeFormat { get; set; } = "HH:mm"; + + /// + /// 横向移动 + /// + /// + public void MoveX(double offsetX) => Canvas.SetLeft(this, X + offsetX); + } +} \ No newline at end of file diff --git a/HandyControl/Controls/TimeBar/TimeBar.xaml b/HandyControl/Controls/TimeBar/TimeBar.xaml new file mode 100644 index 00000000..051cbb01 --- /dev/null +++ b/HandyControl/Controls/TimeBar/TimeBar.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HandyControl/Controls/TimeBar/TimeBar.xaml.cs b/HandyControl/Controls/TimeBar/TimeBar.xaml.cs new file mode 100644 index 00000000..af1523de --- /dev/null +++ b/HandyControl/Controls/TimeBar/TimeBar.xaml.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using HandyControl.Data; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + /// + /// TimeBar.xaml 的交互逻辑 + /// + public partial class TimeBar + { + /// + /// 是否显示刻度字符串 + /// + public static readonly DependencyProperty ShowSpeStrProperty = DependencyProperty.Register( + "ShowSpeStr", typeof(bool), typeof(TimeBar), new PropertyMetadata(default(bool))); + + /// + /// 刻度字符串 + /// + private static readonly DependencyProperty SpeStrProperty = DependencyProperty.Register( + "SpeStr", typeof(string), typeof(TimeBar), new PropertyMetadata("间隔1小时")); + + /// + /// 选中时间 + /// + private static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register( + "SelectedTime", typeof(DateTime), typeof(TimeBar)); + + /// + /// 时间改变事件 + /// + public static readonly RoutedEvent TimeChangedEvent = + EventManager.RegisterRoutedEvent("ButtonCloseClick", RoutingStrategy.Bubble, + typeof(EventHandler>), typeof(TimeBar)); + + /// + /// 刻度集合 + /// + private readonly List _speBlockList = new List(); + + /// + /// 初始化时时间 + /// + private readonly DateTime _starTime; + + /// + /// 时间段集合 + /// + private readonly List _timeSpeList = new List + { + 7200000, + 3600000, + 1800000, + 600000, + 300000, + 60000, + 30000 + }; + + /// + /// 顶部border是否被按下 + /// + private bool _borderTopIsMouseLeftButtonDown; + + /// + /// 控件是否处于拖动中 + /// + private bool _isDragging; + + /// + /// 刻度单项宽度 + /// + private double _itemWidth; + + /// + /// 鼠标按下拖动时选中的时间 + /// + private DateTime _mouseDownTime; + + /// + /// 显示的刻度数目 + /// + private int _speCount = 13; + + /// + /// 刻度区间编号 + /// + private int _speIndex = 1; + + /// + /// 刻度单次偏移 + /// + private double _tempOffsetX; + + /// + /// 刻度总偏移 + /// + private double _totalOffsetX; + + public TimeBar() + { + InitializeComponent(); + + _starTime = DateTime.Now; + SelectedTime = new DateTime(_starTime.Year, _starTime.Month, _starTime.Day, 0, 0, 0); + _starTime = SelectedTime; + } + + /// + /// 是否显示刻度字符串 + /// + public bool ShowSpeStr + { + get => (bool)GetValue(ShowSpeStrProperty); + set => SetValue(ShowSpeStrProperty, value); + } + + /// + /// 刻度字符串 + /// + private string SpeStr + { + get => (string)GetValue(SpeStrProperty); + set => SetValue(SpeStrProperty, value); + } + + /// + /// 选中时间 + /// + private DateTime SelectedTime + { + get => (DateTime)GetValue(SelectedTimeProperty); + set => SetValue(SelectedTimeProperty, value); + } + + /// + /// 刻度区间编号 + /// + public int SpeIndex + { + get => _speIndex; + private set + { + if (_speIndex == value) return; + + if (value < 0) + { + SpeStr = "间隔2小时"; + _speIndex = 0; + return; + } + if (value > 6) + { + SpeStr = "间隔30秒"; + _speIndex = 6; + return; + } + SetSpeTimeFormat("HH:mm"); + switch (value) + { + case 0: + SpeStr = "间隔2小时"; + break; + case 1: + SpeStr = "间隔1小时"; + break; + case 2: + SpeStr = "间隔30分钟"; + break; + case 3: + SpeStr = "间隔10分钟"; + break; + case 4: + SpeStr = "间隔5分钟"; + break; + case 5: + SpeStr = "间隔1分钟"; + break; + case 6: + SetSpeTimeFormat("HH:mm:ss"); + SpeStr = "间隔30秒"; + break; + } + _speIndex = value; + } + } + + /// + /// 时间改变事件 + /// + public event EventHandler> TimeChanged + { + add => AddHandler(TimeChangedEvent, value); + remove => RemoveHandler(TimeChangedEvent, value); + } + + /// + /// 设置刻度时间格式 + /// + /// + private void SetSpeTimeFormat(string format) + { + foreach (var item in _speBlockList) + item.TimeFormat = format; + } + + /// + /// 设置显示的时间 + /// + /// + public void SetShowTime(DateTime time) + { + if (_isDragging || _borderTopIsMouseLeftButtonDown) return; + + SelectedTime = time; + _totalOffsetX = (_starTime - SelectedTime).TotalMilliseconds / _timeSpeList[SpeIndex] * _itemWidth; + Update(); + TimeBar_OnMouseMove(null, null); + } + + /// + /// 更新 + /// + private void Update() + { + var rest = (_totalOffsetX + _tempOffsetX) % _itemWidth; + for (var i = 0; i < _speCount; i++) + { + var item = _speBlockList[i]; + item.MoveX(rest + (_itemWidth - item.Width) / 2); + } + var sub = rest <= 0 ? _speCount / 2 : _speCount / 2 - 1; + + for (var i = 0; i < _speCount; i++) + _speBlockList[i].Time = TimeConvert(SelectedTime).AddMilliseconds((i - sub) * _timeSpeList[_speIndex]); + } + + /// + /// 时间转换 + /// + /// + /// + private DateTime TimeConvert(DateTime time) + { + switch (_speIndex) + { + case 0: + return new DateTime(time.Year, time.Month, time.Day, time.Hour / 2 * 2, 0, 0); + case 1: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, 0, 0); + case 2: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 30 * 30, 0); + case 3: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 10 * 10, 0); + case 4: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 5 * 5, 0); + case 5: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, 0); + case 6: + return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second / 30 * 30); + default: + return time; + } + } + + /// + /// 鼠标滚轮滚动时改变刻度区间 + /// + /// + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + base.OnMouseWheel(e); + if (Mouse.LeftButton == MouseButtonState.Pressed) return; + SpeIndex += e.Delta > 0 ? 1 : -1; + _totalOffsetX = (_starTime - SelectedTime).TotalMilliseconds / _timeSpeList[SpeIndex] * _itemWidth; + Update(); + TimeBar_OnMouseMove(null, null); + e.Handled = true; + } + + private void MouseDragElementBehavior_OnDragging(object sender, MouseEventArgs e) + { + _isDragging = true; + _tempOffsetX = BorderTop.RenderTransform.Value.OffsetX; + + SelectedTime = _mouseDownTime - + TimeSpan.FromMilliseconds(_tempOffsetX / _itemWidth * _timeSpeList[_speIndex]); + Update(); + _borderTopIsMouseLeftButtonDown = false; + } + + private void MouseDragElementBehavior_OnDragFinished(object sender, MouseEventArgs e) + { + _tempOffsetX = 0; + _totalOffsetX = (_totalOffsetX + BorderTop.RenderTransform.Value.OffsetX) % ActualWidth; + BorderTop.RenderTransform = new TranslateTransform(); + RaiseEvent(new FunctionEventArgs(TimeChangedEvent, this) + { + Info = SelectedTime + }); + _isDragging = false; + } + + private void DragElementBehavior_OnDragBegun(object sender, MouseEventArgs e) + { + _mouseDownTime = SelectedTime; + } + + private void TimeBar_OnSizeChanged(object sender, SizeChangedEventArgs e) + { + _speBlockList.Clear(); + CanvasSpe.Children.Clear(); + + _speCount = (int)(ActualWidth / 800 * 9) | 1; + + var itemWidthOld = _itemWidth; + _itemWidth = ActualWidth / _speCount; + _totalOffsetX = _itemWidth / itemWidthOld * _totalOffsetX % ActualWidth; + if (double.IsNaN(_totalOffsetX)) + _totalOffsetX = 0; + + var rest = (_totalOffsetX + _tempOffsetX) % _itemWidth; + var sub = rest <= 0 || double.IsNaN(rest) ? _speCount / 2 : _speCount / 2 - 1; + for (var i = 0; i < _speCount; i++) + { + var block = new SpeTextBlock + { + Time = TimeConvert(SelectedTime).AddMilliseconds((i - sub) * _timeSpeList[_speIndex]), + TextAlignment = TextAlignment.Center, + TimeFormat = "HH:mm" + }; + _speBlockList.Add(block); + CanvasSpe.Children.Add(block); + } + if (_speIndex == 6) + SetSpeTimeFormat("HH:mm:ss"); + ShowSpeStr = ActualWidth > 320; + for (var i = 0; i < _speCount; i++) + { + var item = _speBlockList[i]; + item.X = _itemWidth * i; + item.MoveX((_itemWidth - item.Width) / 2); + } + + Update(); + TimeBar_OnMouseMove(null, null); + } + + private void TimeBar_OnMouseMove(object sender, MouseEventArgs e) + { + var p = Mouse.GetPosition(this); + var mlliseconds = (p.X - ActualWidth / 2) / _itemWidth * _timeSpeList[_speIndex]; + if (double.IsInfinity(mlliseconds)) return; + TextBlockSelected.Text = mlliseconds < 0 + ? (SelectedTime - TimeSpan.FromMilliseconds(-mlliseconds)).ToString("yyyy-MM-dd HH:mm:ss") + : (SelectedTime + TimeSpan.FromMilliseconds(mlliseconds)).ToString("yyyy-MM-dd HH:mm:ss"); + TextBlockSelected.Margin = new Thickness(p.X - TextBlockSelected.ActualWidth / 2, 2, 0, 0); + } + + private void BorderTop_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + _borderTopIsMouseLeftButtonDown = true; + } + + private void BorderTop_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (_borderTopIsMouseLeftButtonDown) + { + _borderTopIsMouseLeftButtonDown = false; + + var p = Mouse.GetPosition(this); + _tempOffsetX = ActualWidth / 2 - p.X; + SelectedTime -= TimeSpan.FromMilliseconds(_tempOffsetX / _itemWidth * _timeSpeList[_speIndex]); + Update(); + _totalOffsetX = (_totalOffsetX + _tempOffsetX) % ActualWidth; + _tempOffsetX = 0; + TimeBar_OnMouseMove(null, null); + RaiseEvent(new FunctionEventArgs(TimeChangedEvent, this) + { + Info = SelectedTime + }); + } + } + } +} \ No newline at end of file diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index c4ad4433..392f2094 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -53,6 +53,10 @@ Pagination.xaml + + + TimeBar.xaml + @@ -89,6 +93,7 @@ Code + @@ -103,6 +108,7 @@ + @@ -130,6 +136,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/HandyControl/Tools/ArithmeticHelper.cs b/HandyControl/Tools/ArithmeticHelper.cs new file mode 100644 index 00000000..f7856388 --- /dev/null +++ b/HandyControl/Tools/ArithmeticHelper.cs @@ -0,0 +1,71 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace HandyControl.Tools +{ + public class ArithmeticHelper + { + /// + /// 获取布局范围框 + /// + /// + /// + internal static Rect GetLayoutRect(FrameworkElement element) + { + var num1 = element.ActualWidth; + var num2 = element.ActualHeight; + if (element is Image || element is MediaElement) + if (element.Parent is Canvas) + { + num1 = double.IsNaN(element.Width) ? num1 : element.Width; + num2 = double.IsNaN(element.Height) ? num2 : element.Height; + } + else + { + num1 = element.RenderSize.Width; + num2 = element.RenderSize.Height; + } + var width = element.Visibility == Visibility.Collapsed ? 0.0 : num1; + var height = element.Visibility == Visibility.Collapsed ? 0.0 : num2; + var margin = element.Margin; + var layoutSlot = LayoutInformation.GetLayoutSlot(element); + var x = 0.0; + var y = 0.0; + switch (element.HorizontalAlignment) + { + case HorizontalAlignment.Left: + x = layoutSlot.Left + margin.Left; + break; + case HorizontalAlignment.Center: + x = (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0; + break; + case HorizontalAlignment.Right: + x = layoutSlot.Right - margin.Right - width; + break; + case HorizontalAlignment.Stretch: + x = Math.Max(layoutSlot.Left + margin.Left, + (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0); + break; + } + switch (element.VerticalAlignment) + { + case VerticalAlignment.Top: + y = layoutSlot.Top + margin.Top; + break; + case VerticalAlignment.Center: + y = (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0; + break; + case VerticalAlignment.Bottom: + y = layoutSlot.Bottom - margin.Bottom - height; + break; + case VerticalAlignment.Stretch: + y = Math.Max(layoutSlot.Top + margin.Top, + (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0); + break; + } + return new Rect(x, y, width, height); + } + } +} \ No newline at end of file diff --git a/HandyControl/Tools/MouseDragElementBehaviorEx.cs b/HandyControl/Tools/MouseDragElementBehaviorEx.cs new file mode 100644 index 00000000..b0757a00 --- /dev/null +++ b/HandyControl/Tools/MouseDragElementBehaviorEx.cs @@ -0,0 +1,368 @@ +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using HandyControl.Interactivity; + +namespace HandyControl.Tools +{ + /// + /// 鼠标拖动行为,该类是反编译微软的System.Windows.Interactivity程序集得到的,并对其做了些扩展 + /// + internal class MouseDragElementBehaviorEx : Behavior + { + public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double), + typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnXChanged)); + + public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double), + typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnYChanged)); + + public static readonly DependencyProperty ConstrainToParentBoundsProperty = + DependencyProperty.Register(nameof(ConstrainToParentBounds), typeof(bool), + typeof(MouseDragElementBehaviorEx), new PropertyMetadata(false, OnConstrainToParentBoundsChanged)); + + private Transform _cachedRenderTransform; + private Point _relativePosition; + private bool _settingPosition; + + /// + /// 是否固定住Y轴 + /// + public bool LockY { get; set; } + + /// + /// 是否固定住X轴 + /// + public bool LockX { get; set; } + + public double X + { + get => (double)GetValue(MouseDragElementBehavior.XProperty); + set => SetValue(MouseDragElementBehavior.XProperty, value); + } + + public double Y + { + get => (double)GetValue(MouseDragElementBehavior.YProperty); + set => SetValue(MouseDragElementBehavior.YProperty, value); + } + + public bool ConstrainToParentBounds + { + get => (bool)GetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty); + set => SetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty, value); + } + + private Rect ElementBounds + { + get + { + var layoutRect = ArithmeticHelper.GetLayoutRect(AssociatedObject); + return new Rect(new Point(0.0, 0.0), new Size(layoutRect.Width, layoutRect.Height)); + } + } + + private FrameworkElement ParentElement => AssociatedObject.Parent as FrameworkElement; + + private UIElement RootElement + { + get + { + DependencyObject reference = AssociatedObject; + for (var dependencyObject = reference; + dependencyObject != null; + dependencyObject = VisualTreeHelper.GetParent(reference)) + reference = dependencyObject; + return reference as UIElement; + } + } + + private Transform RenderTransform + { + get + { + if (_cachedRenderTransform == null || + !ReferenceEquals(_cachedRenderTransform, AssociatedObject.RenderTransform)) + RenderTransform = CloneTransform(AssociatedObject.RenderTransform); + return _cachedRenderTransform; + } + set + { + if (Equals(_cachedRenderTransform, value)) + return; + _cachedRenderTransform = value; + AssociatedObject.RenderTransform = value; + } + } + + public event MouseEventHandler DragBegun; + + public event MouseEventHandler Dragging; + + public event MouseEventHandler DragFinished; + + private static void OnXChanged(object sender, DependencyPropertyChangedEventArgs args) + { + var dragElementBehavior = (MouseDragElementBehaviorEx)sender; + dragElementBehavior.UpdatePosition(new Point((double)args.NewValue, dragElementBehavior.Y)); + } + + private static void OnYChanged(object sender, DependencyPropertyChangedEventArgs args) + { + var dragElementBehavior = (MouseDragElementBehaviorEx)sender; + dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, (double)args.NewValue)); + } + + private static void OnConstrainToParentBoundsChanged(object sender, DependencyPropertyChangedEventArgs args) + { + var dragElementBehavior = (MouseDragElementBehaviorEx)sender; + dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, dragElementBehavior.Y)); + } + + private void UpdatePosition(Point point) + { + if (_settingPosition || AssociatedObject == null) + return; + var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement)); + ApplyTranslation(double.IsNaN(point.X) ? 0.0 : point.X - transformOffset.X, + double.IsNaN(point.Y) ? 0.0 : point.Y - transformOffset.Y); + } + + private void ApplyTranslation(double x, double y) + { + if (ParentElement == null) + return; + var point = TransformAsVector(RootElement.TransformToVisual(ParentElement), x, y); + x = point.X; + y = point.Y; + if (ConstrainToParentBounds) + { + var parentElement = ParentElement; + var rect1 = new Rect(0.0, 0.0, parentElement.ActualWidth, parentElement.ActualHeight); + var rect2 = AssociatedObject.TransformToVisual(parentElement).TransformBounds(ElementBounds); + rect2.X += x; + rect2.Y += y; + if (!RectContainsRect(rect1, rect2)) + { + if (rect2.X < rect1.Left) + { + var num = rect2.X - rect1.Left; + x -= num; + } + else if (rect2.Right > rect1.Right) + { + var num = rect2.Right - rect1.Right; + x -= num; + } + if (rect2.Y < rect1.Top) + { + var num = rect2.Y - rect1.Top; + y -= num; + } + else if (rect2.Bottom > rect1.Bottom) + { + var num = rect2.Bottom - rect1.Bottom; + y -= num; + } + } + } + ApplyTranslationTransform(x, y); + } + + internal void ApplyTranslationTransform(double x, double y) + { + var renderTransform = RenderTransform; + var translateTransform = renderTransform as TranslateTransform; + if (translateTransform == null) + { + var matrixTransform = renderTransform as MatrixTransform; + if (renderTransform is TransformGroup transformGroup1) + { + if (transformGroup1.Children.Count > 0) + translateTransform = + transformGroup1.Children[transformGroup1.Children.Count - 1] as TranslateTransform; + if (translateTransform == null) + { + translateTransform = new TranslateTransform(); + transformGroup1.Children.Add(translateTransform); + } + } + else + { + if (matrixTransform != null) + { + var matrix = matrixTransform.Matrix; + //在该处对微软的类进行了修改 + if (!LockX) + { + matrix.OffsetX += x; + } + if (!LockY) + { + matrix.OffsetY += y; + } + //修改结束 + RenderTransform = new MatrixTransform + { + Matrix = matrix + }; + return; + } + var transformGroup2 = new TransformGroup(); + translateTransform = new TranslateTransform(); + if (renderTransform != null) + transformGroup2.Children.Add(renderTransform); + transformGroup2.Children.Add(translateTransform); + RenderTransform = transformGroup2; + } + } + //在该处对微软的类进行了修改 + if (!LockX) + { + translateTransform.X += x; + } + if (!LockY) + { + translateTransform.Y += y; + } + //修改结束 + } + + internal static Transform CloneTransform(Transform transform) + { + if (transform == null) + return null; + if (transform is ScaleTransform scaleTransform) + return new ScaleTransform + { + CenterX = scaleTransform.CenterX, + CenterY = scaleTransform.CenterY, + ScaleX = scaleTransform.ScaleX, + ScaleY = scaleTransform.ScaleY + }; + if (transform is RotateTransform rotateTransform) + return new RotateTransform + { + Angle = rotateTransform.Angle, + CenterX = rotateTransform.CenterX, + CenterY = rotateTransform.CenterY + }; + if (transform is SkewTransform skewTransform) + return new SkewTransform + { + AngleX = skewTransform.AngleX, + AngleY = skewTransform.AngleY, + CenterX = skewTransform.CenterX, + CenterY = skewTransform.CenterY + }; + if (transform is TranslateTransform translateTransform) + return new TranslateTransform + { + X = translateTransform.X, + Y = translateTransform.Y + }; + if (transform is MatrixTransform matrixTransform) + return new MatrixTransform + { + Matrix = matrixTransform.Matrix + }; + if (!(transform is TransformGroup transformGroup1)) + return null; + var transformGroup2 = new TransformGroup(); + foreach (var child in transformGroup1.Children) + transformGroup2.Children.Add(CloneTransform(child)); + return transformGroup2; + } + + private void UpdatePosition() + { + var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement)); + X = transformOffset.X; + Y = transformOffset.Y; + } + + internal void StartDrag(Point positionInElementCoordinates) + { + _relativePosition = positionInElementCoordinates; + AssociatedObject.CaptureMouse(); + AssociatedObject.MouseMove += OnMouseMove; + AssociatedObject.LostMouseCapture += OnLostMouseCapture; + AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent, + new MouseButtonEventHandler(OnMouseLeftButtonUp), false); + } + + internal void HandleDrag(Point newPositionInElementCoordinates) + { + var point = TransformAsVector(AssociatedObject.TransformToVisual(RootElement), + newPositionInElementCoordinates.X - _relativePosition.X, + newPositionInElementCoordinates.Y - _relativePosition.Y); + _settingPosition = true; + ApplyTranslation(point.X, point.Y); + UpdatePosition(); + _settingPosition = false; + } + + internal void EndDrag() + { + AssociatedObject.MouseMove -= OnMouseMove; + AssociatedObject.LostMouseCapture -= OnLostMouseCapture; + AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent, + new MouseButtonEventHandler(OnMouseLeftButtonUp)); + } + + private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + StartDrag(e.GetPosition(AssociatedObject)); + DragBegun?.Invoke(this, e); + } + + private void OnLostMouseCapture(object sender, MouseEventArgs e) + { + EndDrag(); + DragFinished?.Invoke(this, e); + } + + private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + AssociatedObject.ReleaseMouseCapture(); + } + + private void OnMouseMove(object sender, MouseEventArgs e) + { + HandleDrag(e.GetPosition(AssociatedObject)); + Dragging?.Invoke(this, e); + } + + private static bool RectContainsRect(Rect rect1, Rect rect2) + { + if (rect1.IsEmpty || rect2.IsEmpty || rect1.X > rect2.X || rect1.Y > rect2.Y || + rect1.X + rect1.Width < rect2.X + rect2.Width) + return false; + return rect1.Y + rect1.Height >= rect2.Y + rect2.Height; + } + + private static Point TransformAsVector(GeneralTransform transform, double x, double y) + { + var point1 = transform.Transform(new Point(0.0, 0.0)); + var point2 = transform.Transform(new Point(x, y)); + return new Point(point2.X - point1.X, point2.Y - point1.Y); + } + + private static Point GetTransformOffset(GeneralTransform transform) + { + return transform.Transform(new Point(0.0, 0.0)); + } + + protected override void OnAttached() + { + AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent, + new MouseButtonEventHandler(OnMouseLeftButtonDown), false); + } + + protected override void OnDetaching() + { + AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent, + new MouseButtonEventHandler(OnMouseLeftButtonDown)); + } + } + +} \ No newline at end of file diff --git a/HandyControlDemo/MainWindow.xaml b/HandyControlDemo/MainWindow.xaml index ab14c10e..17ac7585 100644 --- a/HandyControlDemo/MainWindow.xaml +++ b/HandyControlDemo/MainWindow.xaml @@ -354,7 +354,7 @@ --> - + @@ -399,7 +399,7 @@ - + - + diff --git a/README.md b/README.md index 5e89a5bb..2aa57f29 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![logo](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/icon.png) -![c#-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/csharp-version.png) ![IDE-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/IDE-version.png) [![nuget-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/nuget-version.png)](https://www.nuget.org/packages/HandyControl) +![csharp-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/csharp-version.png) ![IDE-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/IDE-version.png) [![nuget-version](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/nuget-version.png)](https://www.nuget.org/packages/HandyControl) # 欢迎使用 HandyControl @@ -26,4 +26,8 @@ ### 5、展开折叠框Expander -![展开折叠框Expander](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/Expander.gif) \ No newline at end of file +![展开折叠框Expander](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/Expander.gif) + +### 6、时间条TimeBar + +![时间条TimeBar](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/TimeBar.gif) \ No newline at end of file diff --git a/Resources/Carousel.gif b/Resources/Carousel.gif index 6bd68263..00d30c61 100644 Binary files a/Resources/Carousel.gif and b/Resources/Carousel.gif differ diff --git a/Resources/Expander.gif b/Resources/Expander.gif index 7d85b984..8d0266d5 100644 Binary files a/Resources/Expander.gif and b/Resources/Expander.gif differ diff --git a/Resources/Loading.gif b/Resources/Loading.gif index 28e0c5f3..b3916949 100644 Binary files a/Resources/Loading.gif and b/Resources/Loading.gif differ diff --git a/Resources/TimeBar.gif b/Resources/TimeBar.gif new file mode 100644 index 00000000..0bba8301 Binary files /dev/null and b/Resources/TimeBar.gif differ