using HMI.UI.MDI; using System; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; namespace HMI.UI.DpUtil { public class Resize { private static readonly double MinWidth = 60; private static readonly double MinHeight = 60; public static double GetReMaxWidth(DependencyObject obj) { return (double)obj.GetValue(ReMaxWithProperty); } public static void SetReMaxWidth(DependencyObject obj, double value) { obj.SetValue(ReMaxWithProperty, value); } public static readonly DependencyProperty ReMaxWithProperty = DependencyProperty.RegisterAttached("ReMaxWith", typeof(double), typeof(Resize), new PropertyMetadata(0.0)); // 拖拽模板 public static ControlTemplate GetResizeTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(ResizeTemplateProperty); } public static void SetResizeTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(ResizeTemplateProperty, value); } public static readonly DependencyProperty ResizeTemplateProperty = DependencyProperty.RegisterAttached("ResizeTemplate", typeof(ControlTemplate), typeof(Resize), new PropertyMetadata(null, (d, e) => { FrameworkElement element = d as FrameworkElement; if (element == null) return; Resizeable resize = GetResizeable(element); if (resize == null) return; resize.Detach(); resize.Attach(); })); // 是否可以拖拽改变大小 public static bool GetCanMove(DependencyObject obj) { return (bool)obj.GetValue(CanMoveProperty); } public static void SetCanMove(DependencyObject obj, bool value) { obj.SetValue(CanMoveProperty, value); } public static readonly DependencyProperty CanMoveProperty = DependencyProperty.RegisterAttached("CanMove", typeof(bool), typeof(Resize), new PropertyMetadata(true)); // 是否可以拖拽改变大小 public static bool GetIsResizeable(DependencyObject obj) { return (bool)obj.GetValue(IsResizeableProperty); } public static void SetIsResizeable(DependencyObject obj, bool value) { obj.SetValue(IsResizeableProperty, value); } public static readonly DependencyProperty IsResizeableProperty = DependencyProperty.RegisterAttached("IsResizeable", typeof(bool), typeof(Resize), new PropertyMetadata(true, (d, e) => { FrameworkElement element = d as FrameworkElement; if (element == null) return; // 先取消之前的拖拽装饰 Resizeable resize = GetResizeable(element); if (resize != null) resize.Detach(); // 实现逻辑 // 判断属性设置的是不是true if (!(bool)e.NewValue) { SetResizeable(element, null); return; } if (!element.IsLoaded) { RoutedEventHandler Loaded_Resize = null; Loaded_Resize = (sender, e1) => { FrameworkElement senderElement = sender as FrameworkElement; Resizeable r = new Resizeable(senderElement); r.Attach(); SetResizeable(senderElement, r); senderElement.Loaded -= Loaded_Resize; }; element.Loaded += Loaded_Resize; } else { resize = new Resizeable(element); resize.Attach(); SetResizeable(element, resize); } })); public static Resizeable GetResizeable(DependencyObject obj) { return (Resizeable)obj.GetValue(ResizeableProperty); } public static void SetResizeable(DependencyObject obj, Resizeable value) { obj.SetValue(ResizeableProperty, value); } // Using a DependencyProperty as the backing store for Resizeable. This enables animation, styling, binding, etc... static readonly DependencyProperty ResizeableProperty = DependencyProperty.RegisterAttached("Resizeable", typeof(Resizeable), typeof(Resize), new PropertyMetadata(null)); static int i = 0; static SolidColorBrush[] colors = new SolidColorBrush[] { new SolidColorBrush(Colors.White), new SolidColorBrush(Colors.Red), new SolidColorBrush(Colors.Blue), new SolidColorBrush(Colors.Green), new SolidColorBrush(Colors.LightBlue), new SolidColorBrush(Colors.Orange), new SolidColorBrush(Colors.Yellow), new SolidColorBrush(Colors.Black), }; public class Resizeable { ResizeType _resizeType; enum ResizeType { None, Grid, Canvas, Window, Others, } FrameworkElement _resizeTarget; FrameworkElement _thumbsParent = null; public Resizeable(FrameworkElement resizeTarget) { _resizeTarget = resizeTarget; } public void Attach() { FrameworkElement thumbsRoot = null; ControlTemplate template = GetResizeTemplate(_resizeTarget); // 看不懂了,大概是拖拽模板 if (template != null) { Control control = new Control(); control.Template = template; control.ApplyTemplate(); thumbsRoot = control; _thumbsParent = VisualTreeHelper.GetChild(thumbsRoot, 0) as FrameworkElement; } if (thumbsRoot != null) { UIElement element = _resizeTarget is Window _windowTarget ? _windowTarget.Content as UIElement : _resizeTarget; if (element != null) { if (element is InnerWindow _inner) { AdornerLayer layer = _inner.ResizeAdornerDecorator.AdornerLayer; if (layer == null) throw new Exception("获取控件装饰层失败,控件可能没有装饰层!"); layer.Add(new ResizeAdorner(layer, thumbsRoot)); } else { AdornerLayer layer = AdornerLayer.GetAdornerLayer(element); if (layer == null) throw new Exception("获取控件装饰层失败,控件可能没有装饰层!"); layer.Add(new ResizeAdorner(element, thumbsRoot)); } } } // 使用缺省样式 if (thumbsRoot == null) { Thumb leftThumb = null, topThumb = null, rightThumb = null, bottomThumb = null, lefTopThumb = null, rightTopThumb = null, rightBottomThumb = null, leftbottomThumb = null; int thumnSize = 5; // 初始化thumb leftThumb = new Thumb(); leftThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; leftThumb.HorizontalAlignment = HorizontalAlignment.Left; leftThumb.VerticalAlignment = VerticalAlignment.Stretch; leftThumb.Cursor = Cursors.SizeWE; leftThumb.Width = thumnSize; leftThumb.Height = double.NaN; leftThumb.Margin = new Thickness(0, thumnSize, 0, thumnSize); topThumb = new Thumb(); topThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; topThumb.HorizontalAlignment = HorizontalAlignment.Stretch; topThumb.VerticalAlignment = VerticalAlignment.Top; topThumb.Cursor = Cursors.SizeNS; topThumb.Width = double.NaN; topThumb.Height = thumnSize; topThumb.Margin = new Thickness(thumnSize, 0, thumnSize, 0); rightThumb = new Thumb(); rightThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; rightThumb.HorizontalAlignment = HorizontalAlignment.Right; rightThumb.VerticalAlignment = VerticalAlignment.Stretch; rightThumb.Cursor = Cursors.SizeWE; rightThumb.Width = thumnSize; rightThumb.Height = double.NaN; rightThumb.Margin = new Thickness(0, thumnSize, 0, thumnSize); bottomThumb = new Thumb(); bottomThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; bottomThumb.HorizontalAlignment = HorizontalAlignment.Stretch; bottomThumb.VerticalAlignment = VerticalAlignment.Bottom; bottomThumb.Cursor = Cursors.SizeNS; bottomThumb.Width = double.NaN; bottomThumb.Height = thumnSize; bottomThumb.Margin = new Thickness(thumnSize, 0, thumnSize, 0); lefTopThumb = new Thumb(); lefTopThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left; lefTopThumb.VerticalAlignment = VerticalAlignment.Top; lefTopThumb.Cursor = Cursors.SizeNWSE; lefTopThumb.Width = thumnSize; lefTopThumb.Height = thumnSize; rightTopThumb = new Thumb(); rightTopThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right; rightTopThumb.VerticalAlignment = VerticalAlignment.Top; rightTopThumb.Cursor = Cursors.SizeNESW; rightTopThumb.Width = thumnSize; rightTopThumb.Height = thumnSize; rightBottomThumb = new Thumb(); rightBottomThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right; rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom; rightBottomThumb.Cursor = Cursors.SizeNWSE; rightBottomThumb.Width = thumnSize; rightBottomThumb.Height = thumnSize; leftbottomThumb = new Thumb(); leftbottomThumb.Template = new ControlTemplate(typeof(Thumb)) { VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent)) }; leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left; leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom; leftbottomThumb.Cursor = Cursors.SizeNESW; leftbottomThumb.Width = thumnSize; leftbottomThumb.Height = thumnSize; Grid grid = new Grid(); grid.Children.Add(leftThumb); grid.Children.Add(topThumb); grid.Children.Add(rightThumb); grid.Children.Add(bottomThumb); grid.Children.Add(lefTopThumb); grid.Children.Add(rightTopThumb); grid.Children.Add(rightBottomThumb); grid.Children.Add(leftbottomThumb); UIElement element; if (_resizeTarget is Window _resizeTargetWindow) { element = _resizeTargetWindow.Content as UIElement; } else { element = _resizeTarget; } if (element != null) { if (element is InnerWindow _inner) { AdornerLayer layer = _inner.ResizeAdornerDecorator?.AdornerLayer; if (layer == null) throw new Exception("获取控件装饰层失败,控件可能没有装饰层!"); layer.Add(new ResizeAdorner(layer, grid)); } else { AdornerLayer layer = AdornerLayer.GetAdornerLayer(element); if (layer == null) throw new Exception("获取控件装饰层失败,控件可能没有装饰层!"); layer.Add(new ResizeAdorner(element, grid)); } } thumbsRoot = grid; _thumbsParent = thumbsRoot; } //注册事件 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(_thumbsParent); i++) { Thumb thumb = VisualTreeHelper.GetChild(_thumbsParent, i) as Thumb; if (thumb != null) { thumb.DragStarted += Thumb_DragStarted; thumb.DragDelta += Thumb_DragDelta; } } } public void Detach() { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(_thumbsParent); i++) { Thumb thumb = VisualTreeHelper.GetChild(_thumbsParent, i) as Thumb; if (thumb != null) { thumb.DragStarted -= Thumb_DragStarted; thumb.DragDelta -= Thumb_DragDelta; } thumb.Cursor = Cursors.Arrow; } _thumbsParent = null; } private void Thumb_DragStarted(object sender, DragStartedEventArgs e) { _resizeType = GetResizeType(); if (_resizeType == ResizeType.Canvas && _resizeTarget is InnerWindow _inner) { Canvas parent = GetCanvas(_inner); // 如果是个InnerWindow,就把InnerWindowZIndex置顶 // TODO 可以改成接口或者DependencyPrope来做 CanvasHelper.SetTopZIndex(_inner, parent, _inner.GetType()); } } private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { switch (_resizeType) { case ResizeType.None: break; case ResizeType.Grid: { FrameworkElement element = _resizeTarget; FrameworkElement thumb = sender as FrameworkElement; double left, top, right, bottom, width, height; if (thumb.HorizontalAlignment == HorizontalAlignment.Left) { right = element.Margin.Right; left = element.Margin.Left + e.HorizontalChange; width = (double.IsNaN(element.Width) ? element.ActualWidth : element.Width) - e.HorizontalChange; } else { left = element.Margin.Left; right = element.Margin.Right - e.HorizontalChange; width = (double.IsNaN(element.Width) ? element.ActualWidth : element.Width) + e.HorizontalChange; } if (thumb.VerticalAlignment == VerticalAlignment.Top) { bottom = element.Margin.Bottom; top = element.Margin.Top + e.VerticalChange; height = (double.IsNaN(element.Height) ? element.ActualHeight : element.Height) - e.VerticalChange; } else { top = element.Margin.Top; bottom = element.Margin.Bottom - e.VerticalChange; height = (double.IsNaN(element.Height) ? element.ActualHeight : element.Height) + e.VerticalChange; } if (thumb.HorizontalAlignment != HorizontalAlignment.Center && thumb.HorizontalAlignment != HorizontalAlignment.Stretch) { if (width >= 0) { element.Margin = new Thickness(left, element.Margin.Top, right, element.Margin.Bottom); element.Width = width; } } if (thumb.VerticalAlignment != VerticalAlignment.Center && thumb.VerticalAlignment != VerticalAlignment.Stretch) { if (height >= 0) { element.Margin = new Thickness(element.Margin.Left, top, element.Margin.Right, bottom); element.Height = height; } } } break; case ResizeType.Canvas: { FrameworkElement target = _resizeTarget; Canvas parent = GetCanvas(target); FrameworkElement thumb = sender as FrameworkElement; if (parent == null) { // 一般不会出现这种情况,保险判断一下 return; } double oldLeft = double.IsNaN(Canvas.GetLeft(target)) ? 0 : Canvas.GetLeft(target), oldTop = double.IsNaN(Canvas.GetTop(target)) ? 0 : Canvas.GetTop(target), oldWidth = double.IsNaN(target.ActualWidth) ? 0 : target.ActualWidth, oldHeight = double.IsNaN(target.ActualHeight) ? 0 : target.ActualHeight; double left, top, width, height; double x = e.HorizontalChange, y = e.VerticalChange; bool toLeft = x < 0, toTop = y < 0; bool isLeft = thumb.HorizontalAlignment == HorizontalAlignment.Left, isTop = thumb.VerticalAlignment == VerticalAlignment.Top; if (isLeft) { // 左侧的拖拽 left = oldLeft + x; width = oldWidth - x; if (left < 0) { left = 0; width = oldWidth - (left - oldLeft); } width = width < MinWidth ? MinWidth : width; } else { // 右侧的拖拽 left = oldLeft >= 0 ? oldLeft : 0; width = oldWidth + x; width = width < MinWidth ? MinWidth : width; if (left + width > parent.ActualWidth) width = parent.ActualWidth - left; } if (isTop) { // 上边的拖拽 top = oldTop + y; height = oldHeight - y; if (top < 0) { top = 0; height = oldHeight - (top - oldTop); } height = height < MinHeight ? MinHeight : height; } else { // 下边的拖拽 top = oldTop > 0 ? oldTop : 0; height = oldHeight + y; height = height < MinHeight ? MinHeight : height; if (top + height > parent.ActualHeight) height = parent.ActualHeight - top; } if (thumb.HorizontalAlignment != HorizontalAlignment.Center && thumb.HorizontalAlignment != HorizontalAlignment.Stretch) { // 水平方向最终判断 Canvas.SetLeft(target, left); target.Width = width; //if ((isLeft && toLeft && left >= 0) || // (isLeft && !toLeft && width >= MinWidth) || // (!isLeft && toLeft && width >= MinWidth) || // (!isLeft && !toLeft && (left + width) <= parent.ActualWidth)) //{ // Canvas.SetLeft(target, left); // target.Width = width; //} } if (thumb.VerticalAlignment != VerticalAlignment.Center && thumb.VerticalAlignment != VerticalAlignment.Stretch) { // 垂直方向最终判断 Canvas.SetTop(target, top); target.Height = height; //if ((isTop && toTop && top >= 0) || // (isTop && !toTop && height >= MinHeight) || // (!isTop && toTop && height >= MinHeight) || // (!isTop && !toTop && (top + height) <= parent.ActualHeight)) //{ // Canvas.SetTop(target, top); // target.Height = height; //} } } break; case ResizeType.Window: { var c = _resizeTarget as Window; var thumb = sender as FrameworkElement; double left, top, width, height; if (thumb.HorizontalAlignment == HorizontalAlignment.Left) { left = c.Left + e.HorizontalChange; width = c.Width - e.HorizontalChange; } else { left = c.Left; width = c.Width + e.HorizontalChange; } if (thumb.VerticalAlignment == VerticalAlignment.Top) { top = c.Top + e.VerticalChange; height = c.Height - e.VerticalChange; } else { top = c.Top; height = c.Height + e.VerticalChange; } if (thumb.HorizontalAlignment != HorizontalAlignment.Center && thumb.HorizontalAlignment != HorizontalAlignment.Stretch) { if (width > 63) { c.Width = width; c.Left = left; } } if (thumb.VerticalAlignment != VerticalAlignment.Center && thumb.VerticalAlignment != VerticalAlignment.Stretch) { if (height > 63) { c.Top = top; c.Height = height; } } } break; case ResizeType.Others: break; } } ResizeType GetResizeType() { ResizeType rt; DependencyObject parent = VisualTreeHelper.GetParent(_resizeTarget); if (parent is Grid) { rt = ResizeType.Grid; } else if (parent is Canvas) { rt = ResizeType.Canvas; } else if (_resizeTarget is Window) { rt = ResizeType.Window; } else { rt = ResizeType.Grid; } return rt; } // 方形工厂 FrameworkElementFactory GetFactory(Brush back) { FrameworkElementFactory fac = new FrameworkElementFactory(typeof(Rectangle)); fac.SetValue(Rectangle.FillProperty, back); return fac; } // 装饰器 public class ResizeAdorner : Adorner { // 布局容器,如果不使用布局容器,则需要给上述8个控件布局,实现和Grid布局定位是一样的,会比较繁琐且意义不大。 UIElement _child; public ResizeAdorner(UIElement adornedElement, UIElement child) : base(adornedElement) { _child = child; AddVisualChild(child); } protected override Visual GetVisualChild(int index) { return _child; } protected override int VisualChildrenCount { get; } = 1; protected override Size ArrangeOverride(Size finalSize) { // 直接给grid布局,grid内部的thumb会自动布局。 _child.Arrange(new Rect(new Point(0, 0), finalSize)); return finalSize; } public void ttt(int index) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(_child); i++) { DependencyObject child = VisualTreeHelper.GetChild(_child, i); Canvas.SetZIndex(child as UIElement, index); } } } } static Canvas GetCanvas(DependencyObject element) { DependencyObject e = element; while (e != null && !(e is Canvas)) { e = VisualTreeHelper.GetParent(e); } return e == null ? null : e as Canvas; } } }