繁体   English   中英

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

[英]How can i resize a rotated control without change the aspect ratio based on the current position X and 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):

    <Grid>
  <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"
                 VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
  <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"
                 VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
  <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"
                 VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
  <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"
                 VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
  <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"
                 VerticalAlignment="Top" HorizontalAlignment="Left"/>
  <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"
                 VerticalAlignment="Top" HorizontalAlignment="Right"/>
  <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"
                 VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
  <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"
                 VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
        <!-- ... -->
    </Grid>

就像我说的那样,它工作得很好,尤其是如果旋转控件,则无论旋转多少,组件的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类实现。 设计器项绑定到视图模型(位置,大小,角度旋转):

    /// <summary>
    /// Defines a thumb for resizing shapes.
    /// </summary>
    public class ResizeThumb : Thumb
    {  
    /// <summary>
    /// Holds a designer item.
    /// </summary>
    private DesignerItem _designerItem;

    /// <summary>
    /// Holds a collection of designer items.
    /// </summary>
    private DesignerItems _designerItems;

    /// <summary>
    /// holds a transform origin of the designer item 
    /// </summary>
    private Point _transformOrigin;

    /// <summary>
    /// holds an angle of the rotation transformation of the designer item
    /// </summary>
    private double _angle = 0.0;

    /// <summary>
    /// Initializes a new instance of the <see cref="ResizeThumb"/> class.
    /// </summary>
    public ResizeThumb()
    {
        DragStarted += ResizeThumbDragStarted;
        DragDelta += ResizeThumbDragDelta;
        DragCompleted += ResizeThumbDragCompleted;
    }

    /// <summary>
    /// Handles notifications when the dragging of the thumb starts.
    /// </summary>
    /// <param name="sender">the sender object</param>
    /// <param name="e">the event arguments</param>
    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;
    }

    /// <summary>
    /// Handles notifications when the dragging of the thumb completes.
    /// </summary>
    /// <param name="sender">the sender object</param>
    /// <param name="e">the event arguments</param>
    private void ResizeThumbDragCompleted(object sender, DragCompletedEventArgs e)
    {
        if (_designerItem != null)
        {
            _designerItem.IsResizing = false;
            _designerItem.IsDragging = false;
        }
    }

    /// <summary>
    /// Handles notifications when the thumb has been dragged.
    /// </summary>
    /// <param name="sender">the sender object</param>
    /// <param name="e">the event arguments</param>
    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;
    }

    /// <summary>
    /// Checks the values so that the ratio beween them has a defined value.
    /// </summary>
    /// <param name="dragDeltaHorizontal">horizontal delta</param>
    /// <param name="dragDeltaVertical">vertical delta</param>
    /// <param name="aspectRatio">horizontal to vertical ration</param>
    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;
        }
    }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM