如何在不改变基于当前位置X和Y的纵横比的情况下调整旋转控件的大小?

目前我使用了以下代码,它工作正常,但不尊重宽高比:

private double angle; private Point transformOrigin; private ContentControl designerItem; public ResizeThumb() { DragStarted += new DragStartedEventHandler(this.ResizeThumb_DragStarted); DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta); } private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e) { this.designerItem = DataContext as ContentControl; if (this.designerItem != null) { this.transformOrigin = this.designerItem.RenderTransformOrigin; RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform; if (rotateTransform != null) this.angle = rotateTransform.Angle * Math.PI / 180.0; else this.angle = 0; } } private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e) { if (this.designerItem != null) { double deltaVertical, deltaHorizontal; switch (VerticalAlignment) { case System.Windows.VerticalAlignment.Bottom: deltaVertical = Math.Min(-e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight); Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle)))); Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) - deltaVertical * this.transformOrigin.Y * Math.Sin(-this.angle)); this.designerItem.Height -= deltaVertical; break; case System.Windows.VerticalAlignment.Top: deltaVertical = Math.Min(e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight); Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaVertical * Math.Cos(-this.angle) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle)))); Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaVertical * Math.Sin(-this.angle) - (this.transformOrigin.Y * deltaVertical * Math.Sin(-this.angle))); this.designerItem.Height -= deltaVertical; break; default: break; } switch (HorizontalAlignment) { case System.Windows.HorizontalAlignment.Left: deltaHorizontal = Math.Min(e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth); Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaHorizontal * Math.Sin(this.angle) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle)); Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaHorizontal * Math.Cos(this.angle) + (this.transformOrigin.X * deltaHorizontal * (1 - Math.Cos(this.angle)))); this.designerItem.Width -= deltaHorizontal; break; case System.Windows.HorizontalAlignment.Right: deltaHorizontal = Math.Min(-e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth); Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle)); Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + (deltaHorizontal * this.transformOrigin.X * (1 - Math.Cos(this.angle)))); this.designerItem.Width -= deltaHorizontal; break; default: break; } } } } 

和它的视觉(xaml):

             

就像我说它工作得很好,特别是如果控制旋转,组件的x和y位置完全按预期工作,无论它旋转多少。

完整源代码: http : //www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part-1

如何保持纵横比并且X和Y位置没有问题?

从多方面来看,在保持纵横比的同时很容易获得新的尺寸。 但我不能使它正常工作,因为组件可以旋转,X和Y位置是一团糟。 我不知道如何调整和纠正新的X和Y保持比率。

  1. 计算deltaVertical和deltaHorizo​​ntal。
  2. 将纵横比应用于增量
  3. 更新designerItem的位置和大小

更新:从工作解决方案中调整ResizeThumb类。 设计器项绑定到视图模型(位置,大小,角度旋转):

  ///  /// Defines a thumb for resizing shapes. ///  public class ResizeThumb : Thumb { ///  /// Holds a designer item. ///  private DesignerItem _designerItem; ///  /// Holds a collection of designer items. ///  private DesignerItems _designerItems; ///  /// holds a transform origin of the designer item ///  private Point _transformOrigin; ///  /// holds an angle of the rotation transformation of the designer item ///  private double _angle = 0.0; ///  /// Initializes a new instance of the  class. ///  public ResizeThumb() { DragStarted += ResizeThumbDragStarted; DragDelta += ResizeThumbDragDelta; DragCompleted += ResizeThumbDragCompleted; } ///  /// Handles notifications when the dragging of the thumb starts. ///  /// the sender object /// the event arguments private void ResizeThumbDragStarted(object sender, DragStartedEventArgs e) { _designerItem = DataContext as DesignerItem; if (_designerItem == null) return; _designerItem.IsResizing = true; _designerItem.IsDragging = true; _designerItems = _designerItem.GetItemsControl(); _transformOrigin = _designerItem.RenderTransformOrigin; var rotateTransform = _designerItem.RenderTransform as RotateTransform; if (rotateTransform != null) _angle = rotateTransform.Angle * Math.PI / 180.0; else _angle = 0.0; } ///  /// Handles notifications when the dragging of the thumb completes. ///  /// the sender object /// the event arguments private void ResizeThumbDragCompleted(object sender, DragCompletedEventArgs e) { if (_designerItem != null) { _designerItem.IsResizing = false; _designerItem.IsDragging = false; } } ///  /// Handles notifications when the thumb has been dragged. ///  /// the sender object /// the event arguments private void ResizeThumbDragDelta(object sender, DragDeltaEventArgs e) { if (_designerItem == null || _designerItems == null || !_designerItem.IsSelected) { return; } var item = _designerItem; var minLeft = double.MaxValue; var minTop = double.MaxValue; var minDeltaHorizontal = double.MaxValue; var minDeltaVertical = double.MaxValue; minLeft = Math.Min(Canvas.GetLeft(item), minLeft); minTop = Math.Min(Canvas.GetTop(item), minTop); minDeltaVertical = Math.Min(minDeltaVertical, item.ActualHeight - item.MinHeight); minDeltaHorizontal = Math.Min(minDeltaHorizontal, item.ActualWidth - item.MinWidth); // stop moving when // at least one of the selected items is locked if (item.IsLocked) { return; } double? dragDeltaVertical = null; switch (VerticalAlignment) { case VerticalAlignment.Bottom: dragDeltaVertical = Math.Min(-e.VerticalChange, minDeltaVertical); break; case VerticalAlignment.Top: dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical); break; } double? dragDeltaHorizontal = null; switch (HorizontalAlignment) { case HorizontalAlignment.Left: dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal); break; case HorizontalAlignment.Right: dragDeltaHorizontal = Math.Min(-e.HorizontalChange, minDeltaHorizontal); break; } // in case the aspect ratio is kept then adjust both width and height if (item.KeepAspectRatio) { CheckAspectRatio(ref dragDeltaHorizontal, ref dragDeltaVertical, item.ActualHeight / item.ActualWidth); } if (dragDeltaVertical.HasValue) { switch (VerticalAlignment) { case System.Windows.VerticalAlignment.Bottom: Canvas.SetTop(item, Canvas.GetTop(item) + (_transformOrigin.Y * dragDeltaVertical.Value * (1 - Math.Cos(-_angle)))); Canvas.SetLeft(item, Canvas.GetLeft(item) - dragDeltaVertical.Value * _transformOrigin.Y * Math.Sin(-_angle)); break; case System.Windows.VerticalAlignment.Top: Canvas.SetTop(item, Canvas.GetTop(item) + dragDeltaVertical.Value * Math.Cos(-_angle) + (_transformOrigin.Y * dragDeltaVertical.Value * (1 - Math.Cos(-_angle)))); Canvas.SetLeft(item, Canvas.GetLeft(item) + dragDeltaVertical.Value * Math.Sin(-_angle) - (_transformOrigin.Y * dragDeltaVertical.Value * Math.Sin(-_angle))); break; default: break; } item.Height = item.ActualHeight - dragDeltaVertical.Value; } if (dragDeltaHorizontal.HasValue) { switch (HorizontalAlignment) { case System.Windows.HorizontalAlignment.Left: Canvas.SetTop(item, Canvas.GetTop(item) + dragDeltaHorizontal.Value * Math.Sin(_angle) - _transformOrigin.X * dragDeltaHorizontal.Value * Math.Sin(_angle)); Canvas.SetLeft(item, Canvas.GetLeft(item) + dragDeltaHorizontal.Value * Math.Cos(_angle) + (_transformOrigin.X * dragDeltaHorizontal.Value * (1 - Math.Cos(_angle)))); break; case System.Windows.HorizontalAlignment.Right: Canvas.SetTop(item, Canvas.GetTop(item) - _transformOrigin.X * dragDeltaHorizontal.Value * Math.Sin(_angle)); Canvas.SetLeft(item, Canvas.GetLeft(item) + (dragDeltaHorizontal.Value * _transformOrigin.X * (1 - Math.Cos(_angle)))); break; default: break; } item.Width = item.ActualWidth - dragDeltaHorizontal.Value; } e.Handled = true; } ///  /// Checks the values so that the ratio beween them has a defined value. ///  /// horizontal delta /// vertical delta /// horizontal to vertical ration private void CheckAspectRatio(ref double? dragDeltaHorizontal, ref double? dragDeltaVertical, double aspectRatio) { double? dragValue = null; if (dragDeltaVertical.HasValue && dragDeltaHorizontal.HasValue) { dragValue = Math.Max(dragDeltaVertical.Value, dragDeltaHorizontal.Value); } else if (dragDeltaVertical.HasValue) { dragValue = dragDeltaVertical; } else if (dragDeltaHorizontal.HasValue) { dragValue = dragDeltaHorizontal; } if (dragValue.HasValue) { dragDeltaVertical = dragValue.Value * aspectRatio; dragDeltaHorizontal = dragValue; } } }