3

很简单,我想创建一些调整大小/重新缩放装饰器以附加到 FrameworkElement,如果他们正常使用装饰器,则允许用户调整元素大小,如果他们使用底部,则允许他们重新缩放元素(不一定一致) - 右装饰并在这样做的同时按住 SHIFT 按钮。

我尝试了各种方法来实现这一点,但我总是以装饰器本身被缩放,所以它们最终变得巨大,或者有巨大的边界。从那以后,我开始使用相对于窗口的位置来定位它们并忽略了应用于 AdornedElement 的 RenderTransform,但是我得到了一些非常不寻常的行为。

首先,当我将元素缩放超过(大约)2 倍时,重新缩放行为会崩溃并开始在整个地方跳跃。

显然,这种行为比描述更容易看到,因此我附上了一个示例解决方案(VS 2010)来演示问题和导致它的代码。

示例 VS 2010 解决方案

如果有人可以给我任何正确方向的指示,请随时告诉我我做错了!哈哈。

另外,请记住,如果底层装饰元素被旋转,这个装饰器最终也必须正确显示,目前它不会。

更新:为了让 NVM 开心,这里是他的解决方案:NVM 的方式

4

2 回答 2

6

假设您在装饰器中有拇指用于拖动/旋转等,您首先要阻止它们缩放,以便在 GetDesiredTransform 覆盖中执行此操作。应用您在框架元素上应用的比例的倒数。这使您的拇指在调整大小时不会缩放。

public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
{
    double scaleFactor = GetCurrentScaleFactor(this._parent);

    if (this._visualChildren != null)
    {
        foreach (var thumb in this._visualChildren.OfType<Thumb>())
        {
            thumb.RenderTransform 
                = new ScaleTransform(1 / scaleFactor , 1 / scaleFactor );
            thumb.RenderTransformOrigin = new Point(0.5, 0.5);
        }
    }

    return base.GetDesiredTransform(transform);
}

下一个问题将是排列拇指,以便它们在缩放/旋转等之后最终位于正确的位置。由于您已经更改了拇指的渲染变换,您现在还必须使用 ArrangeOverride 手动排列它。

为此,请列出所有拇指以及它们应该处于的位置。如果您只处理方形元素,那么您的工作就完成了一半,因为您只需要处理角落和侧面。

protected override Size ArrangeOverride(Size finalSize)
{
    var adornedElement = this.AdornedElement as FrameworkElement;

    // Use the width/height etc of adorned element to arrange the thumbs here
    // Its been a long time so either its width/height or actualwidth/actualheight
    // you will need to use.
    this._leftTopThumb.Arrange(Get the Rect To arrange here);  
    this._rightTopThumb.Arrange(Get the Rect To arrange here); 
    // etc

    return finalSize;
}

如果您不知道如何安排工作,请参阅此代码项目文章。

如果您仍然无法让它工作,请向我们展示可能导致问题的相关代码(不是 Visual Studio 解决方案),我相信有人会帮助您。

编辑

首先简化您的代码以了解您的问题。

  1. 删除除 btmRight thumb 之外的所有拇指和事件处理程序。
  2. 将 DragCompleted 事件添加到 btmRight Thumb。(删除拖动增量)

本质上,问题代码的症结归结为注释行:

void _btmRight_DragCompleted(object sender, DragCompletedEventArgs e)
{
    var adornedElement = AdornedElement as FrameworkElement;
    var hitThumb = sender as Thumb;
    if (adornedElement == null || hitThumb == null) return;

    var transformGroup = new TransformGroup();
    transformGroup.Children.Add(adornedElement.RenderTransform);

    //---- This is the problem line
    transformGroup.Children.Add(new ScaleTransform(1 + e.HorizontalChange / adornedElement.Width, 1 + e.VerticalChange / adornedElement.Height));
    //-------------------------------

    adornedElement.RenderTransform = new MatrixTransform(transformGroup.Value);
    }

现在很容易找出问题所在。这段代码在您第一次拖动和调整大小时效果很好。这是因为 adornedElement.Width 和 adornedElement.Height 在您第一次拖动它时是正确的,因为尚未应用任何缩放变换。拖动完成后,您假设宽度和高度现在将是新的宽度和高度。他们不是!你看这只是一个渲染变换,它不会改变元素的宽度或高度。它只是使它更大。

所以你需要做的是首先将现有的比例变换应用于 Width 和 Height 以获得渲染的宽度和高度。然后使用这些新值计算比例变换并添加到变换组。然后你会得到你想要的。

在 DragDelta 中执行此操作时,您很可能还会遇到其他问题。但在这种情况下,你应该只用一小部分相关代码提出一个更具体的问题,我相信你会在几分钟内得到某人的答案。

于 2012-03-12T20:48:43.400 回答
1

Siyfion,你看到的现象是真实的。原因是您在处理装饰器拖动时没有使用相同的缩放比例进行补偿。除了 NVM 的答案,确保你也有这个:

double deltaX = args.HorizontalChange / CurrentDisplayScaleX;
double deltaY = args.VerticalChange / CurrentDisplayScaleX;

以相同方式获取当前显示比例。有了这些修正值,跳跃就会停止。跳跃实际上是双重绘制,首先由系统自动使用错误的缩放比例,其次使用您提供的修改后的正确尺寸。它出现在所有规模级别,只是一旦规模开始变大,它就会变得非常明显。

于 2014-05-11T10:19:24.000 回答