目前我使用了以下代码,它工作正常,但不尊重宽高比:
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保持比率。
答案 0 :(得分:5)
更新:从工作解决方案中调整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;
}
}
}