所以我开始从http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part开始查看并构建MoveResizeRotate项目。
我添加了几件事:
然而,现在我在调整控件大小方面遇到了麻烦。它在旋转之前工作正常,但是当它旋转时,它似乎从中间而不是那个角/侧调整大小。当控件的ScaleX设置为-1时,这一点尤为明显。
这是ResizeThumb的代码:
namespace ResizeRotateFlip
{
public class ResizeThumb : Thumb
{
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 )
{
//variables
double deltaVertical = 0, deltaHorizontal = 0;
double newHeight = 0, newWidth = 0;
double startHeight = this.designerItem.Height;
double startWidth = this.designerItem.Width;
//calculate deltas
switch( VerticalAlignment )
{
case System.Windows.VerticalAlignment.Bottom:
deltaVertical = Math.Min( -e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight );
break;
case System.Windows.VerticalAlignment.Top:
deltaVertical = Math.Min( e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight );
break;
default:
break;
}
switch( HorizontalAlignment )
{
case System.Windows.HorizontalAlignment.Left:
deltaHorizontal = Math.Min( e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth );
break;
case System.Windows.HorizontalAlignment.Right:
deltaHorizontal = Math.Min( -e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth );
break;
default:
break;
}
// resize
if( dragging_from_corner() )
{
newHeight = this.designerItem.Height - deltaVertical;
newWidth = this.designerItem.Width - deltaHorizontal;
if( newHeight >= 0 && newWidth >= 0 )
{
aspect_ratio_resizing( this.designerItem.Height, this.designerItem.Width, newHeight, newWidth );
}
}
else
{
this.designerItem.Height -= deltaVertical;
this.designerItem.Width -= deltaHorizontal;
}
// translate
double verticalChange = startHeight - this.designerItem.Height;
double horizontalChange = startWidth - this.designerItem.Width;
TransformGroup transformGroup = designerItem.RenderTransform as TransformGroup;
ScaleTransform scaleTransform = transformGroup.Children[(int)TransformType.ScaleTransform] as ScaleTransform;
switch( VerticalAlignment )
{
case System.Windows.VerticalAlignment.Bottom:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
break;
case System.Windows.VerticalAlignment.Top:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
break;
default:
break;
}
switch( HorizontalAlignment )
{
case System.Windows.HorizontalAlignment.Left:
if( scaleTransform.ScaleX != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + horizontalChange * Math.Sin( this.angle ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + horizontalChange * Math.Cos( this.angle ) + ( this.transformOrigin.X * horizontalChange * ( 1 - Math.Cos( this.angle ) ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + ( horizontalChange * this.transformOrigin.X * ( 1 - Math.Cos( this.angle ) ) ) );
}
break;
case System.Windows.HorizontalAlignment.Right:
if( scaleTransform.ScaleX != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + ( horizontalChange * this.transformOrigin.X * ( 1 - Math.Cos( this.angle ) ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + horizontalChange * Math.Sin( this.angle ) - this.transformOrigin.X * horizontalChange * Math.Sin( this.angle ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + horizontalChange * Math.Cos( this.angle ) + ( this.transformOrigin.X * horizontalChange * ( 1 - Math.Cos( this.angle ) ) ) );
}
break;
default:
break;
}
}
e.Handled = true;
}
private bool dragging_from_corner()
{
if( ( VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom ) &&
( HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right ) )
{
return true;
}
return false;
}
private void aspect_ratio_resizing( double originalHeight, double originalWidth, double newHeight, double newWidth )
{
double ratioWidth = newWidth / originalWidth;
double ratioHeight = newHeight / originalHeight;
double ratio = Math.Min( ratioWidth, ratioHeight );
if( originalHeight * ratio > this.designerItem.MinHeight && originalWidth * ratio > this.designerItem.MinWidth )
{
this.designerItem.Height = originalHeight * ratio;
this.designerItem.Width = originalWidth * ratio;
}
}
}
}
这是我的RotateThumb代码:
namespace ResizeRotateFlip
{
public class RotateThumb : Thumb
{
private Point centerPoint;
private Vector startVector;
private double initialAngle;
private Canvas designerCanvas;
private ContentControl designerItem;
public RotateThumb()
{
DragDelta += new DragDeltaEventHandler( this.RotateThumb_DragDelta );
DragStarted += new DragStartedEventHandler( this.RotateThumb_DragStarted );
}
private void RotateThumb_DragStarted( object sender, DragStartedEventArgs e )
{
this.designerItem = DataContext as ContentControl;
if( this.designerItem != null )
{
this.designerCanvas = VisualTreeHelper.GetParent( this.designerItem ) as Canvas;
if( this.designerCanvas != null )
{
this.centerPoint = this.designerItem.TranslatePoint(
new Point( this.designerItem.Width * this.designerItem.RenderTransformOrigin.X,
this.designerItem.Height * this.designerItem.RenderTransformOrigin.Y ),
this.designerCanvas );
Point startPoint = Mouse.GetPosition( this.designerCanvas );
this.startVector = Point.Subtract( startPoint, this.centerPoint );
TransformGroup transformGroup = this.designerItem.RenderTransform as TransformGroup;
RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;
if( rotateTransform == null )
{
initialAngle = 0;
}
else
{
this.initialAngle = rotateTransform.Angle;
}
}
}
}
private void RotateThumb_DragDelta( object sender, DragDeltaEventArgs e )
{
if( this.designerItem != null && this.designerCanvas != null )
{
TransformGroup transformGroup = this.designerItem.RenderTransform as TransformGroup;
ScaleTransform scaleTransform = transformGroup.Children[(int)TransformType.ScaleTransform] as ScaleTransform;
double multiplier = scaleTransform.ScaleX * scaleTransform.ScaleY;
Point currentPoint = Mouse.GetPosition( this.designerCanvas );
Vector deltaVector = Point.Subtract( currentPoint, this.centerPoint );
double angle = Vector.AngleBetween( this.startVector, deltaVector );
RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;
rotateTransform.Angle = this.initialAngle + ( Math.Round( angle, 0 ) ) * multiplier;
this.designerItem.InvalidateMeasure();
}
}
}
}
我猜测我对X和Y的计算变化(在ResizeThumb中)是不正确的。因此,在调整大小后,翻译未正确应用。虽然我注意到我对RotateThumb的更改对调整大小有影响,但在RotateThumb中使用TransformGroup之前,控件在旋转时会正确调整大小。
我引用的项目用途:
case System.Windows.VerticalAlignment.Bottom:
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
break;
用于计算X&的新位置例如Y:但是我不知道如果翻转控件如何计算。 - 我应该注意到我在这里使用verticalChange而不是deltaVertical的原因是,当使用deltaHorizontal和deltaVertical时,控件往往会在画布上移动。
我想我的问题更多的是数学方面,我如何计算X&的新位置?是,当控件旋转并翻转时?
修改 我刚才注意到的一件事是在ResizeThumb的DragStarted方法中,我还没有访问过TransformGroup的RotateTransform。
我改变了:
RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform;
为:
TransformGroup transformGroup = designerItem.RenderTransform as TransformGroup;
RotateTransform rotateTransform = transformGroup.Children[(int)TransformType.RotateTransform] as RotateTransform;
这解决了当ScaleX和ScaleY没有被更改时调整大小错误的问题,但是当我翻转控件时,我仍然会调整大小问题。
答案 0 :(得分:1)
我想我已经解决了!现在看起来很明显......
对于翻译,我这样做:
switch( VerticalAlignment )
{
case System.Windows.VerticalAlignment.Bottom:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
break;
case System.Windows.VerticalAlignment.Top:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
break;
default:
break;
}
当ScaleY设置为-1时,我只使用VerticalAlignment.Top中的VeticalAlignment.Bottom计算。反之亦然。但是对于Canvas.SetLeft来说这是没有意义的。
所以我把它改成了:
switch( VerticalAlignment )
{
case System.Windows.VerticalAlignment.Bottom:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
}
if( scaleTransform.ScaleX != -1 )
{
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
else
{
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
break;
case System.Windows.VerticalAlignment.Top:
if( scaleTransform.ScaleY != -1 )
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + verticalChange * Math.Cos( -this.angle ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
}
else
{
Canvas.SetTop( this.designerItem, Canvas.GetTop( this.designerItem ) + ( this.transformOrigin.Y * verticalChange * ( 1 - Math.Cos( -this.angle ) ) ) );
}
if( scaleTransform.ScaleX != -1 )
{
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) + verticalChange * Math.Sin( -this.angle ) - ( this.transformOrigin.Y * verticalChange * Math.Sin( -this.angle ) ) );
}
else
{
Canvas.SetLeft( this.designerItem, Canvas.GetLeft( this.designerItem ) - verticalChange * this.transformOrigin.Y * Math.Sin( -this.angle ) );
}
break;
default:
break;
}
现在,SetTop和SetLeft会根据其比例进行适当设置。