如何创建不能使用AdornedElement扩展的装饰器?

时间:2012-03-12 17:52:31

标签: c# wpf scale adorner

很简单,我想创建一些调整大小/重新调整的装饰器以附加到FrameworkElement,如果他们正常使用装配器,则允许用户调整元素的大小,并允许他们重新调整元素(不一定是统一的),如果他们使用右下方的装饰器并按住SHIFT按钮。

我已经尝试了各种方法来实现这一目标,但我总是最终将装饰者自己缩放,因此他们最终会变得庞大,或者拥有巨大的边界。我已经开始使用相对于窗口的位置来定位它们并忽略应用于AdornedElement的RenderTransform,但是我得到了一些非常不寻常的行为。

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

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

Example VS 2010 solution

如果有人能指出正确方向,请随时告诉我,我做错了!洛尔。

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

更新:为了让NVM保持高兴,以下是解决方案:NVM's way

2 个答案:

答案 0 :(得分: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;
}

如果您不知道如何安排填写See This代码项目文章。

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

修改

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

  1. 删除除btmRight拇指以外的所有拇指和事件处理程序。
  2. 将一个DragCompleted事件添加到btmRight Thumb。 (删除拖动三角洲)
  3. 基本上问题代码的关键在于注释行:

    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中执行此操作时,您很可能还会遇到其他问题。但在这种情况下,你应该只用一小段相关代码来提出一个更具体的问题,你肯定会在几分钟内得到答案。

答案 1 :(得分:1)

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

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

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