在Control或UIElement上找到应用的ScaleTransform?

时间:2011-02-27 02:47:23

标签: wpf uielement scaletransform layouttransform

我有一个控件坐在窗口的某个地方。在这个窗口的根部是一个名为MainGrid的网格。我在MainGrid的LayoutTransform上应用了ScaleTransform,当窗口大小增加时,我用它来放大窗口的所有内容。但是,我的一个控件在其画布上使用BitmapCache来优化绘图性能。 BitmapCache没有考虑可能应用于控件的任何ScaleTransform,所以如果我放大了,控件就会显得模糊。

BitmapCache确实有一个RenderAtScale属性,我可以使用它来增加缓存图像的比例。但是,我遇到的问题是我不知道找出Scale值需要的优雅方法。现在,我在我的控件上有一个属性,以便我的Window可以将其缩放值传递给控件。但是,如果我不需要依赖一些传递比例值的外部源,我想要它。

控件是否可以获取应用于它的所有ScaleTransforms的摘要?

5 个答案:

答案 0 :(得分:3)

您可以使用PresentationSource的{​​{1}}来计算元素的总转换。查找在父项和子项之间应用的比例的一般模式是

RootVisual

答案 1 :(得分:2)

正如 Elad Katz 所说,我认为没有任何直接的方法可以确定ScaleTransform是否适用于任何父母而不经过它们。

但是,如果您知道ScaleTransform已应用于MainGrid,那么您可以将RenderAtScale绑定到MainGrid的ScaleXScaleY ScaleTransform }。也许这就是你已经在做的事情,但无论如何我把它扔进了

在Binding中引用ScaleTransform的最简单方法可能就是命名

<Grid Name="MainGrid">
    <Grid.LayoutTransform>
        <TransformGroup>
            <ScaleTransform x:Name="MainGridScaleTransform" .../>
        </TransformGroup>            
    </Grid.LayoutTransform>

Binding应该看起来与此类似

<BitmapCache RenderAtScale="{Binding ElementName=MainGridScaleTransform,
                                     Path=ScaleX}"/>

否则,您可以使用ScaleTransform

获取路径中的TransformGroup
<BitmapCache RenderAtScale="{Binding ElementName=MainGrid,
 Path=(LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)}"/>

或没有TransformGroup

<BitmapCache RenderAtScale="{Binding ElementName=MainGrid,
                              Path=(LayoutTransform).(ScaleTransform.ScaleX)}"/>

答案 2 :(得分:2)

根据Elad Katz的建议,我创建了一些代码来扫描VisualTree以尝试统一任何统一ScaleTransform。如果任何人对这种算法有一些优化,或者可以想到一些我可能没有考虑的事情,请告诉我。同样,我的目标是在给定当前应用的ScaleTransform的情况下获得实际上合适的RenderAtScale。 OnRenderSizeChanged似乎是一个可以做到这一点的好地方,因为它发生在所有布局的东西运行之后。但是,也许有更好的地方可以触发GetTotalTransformScale()?

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
    base.OnRenderSizeChanged(sizeInfo);
    double totalTransformScale = GetTotalTransformScale();
    BitmapCache bitmapCache = (BitmapCache)MyCachedCanvas.CacheMode;
    if (bitmapCache.RenderAtScale != totalTransformScale)
        bitmapCache.RenderAtScale = totalTransformScale;
}

private double GetTotalTransformScale()
{
    double totalTransform = 1.0d;    
    DependencyObject currentVisualTreeElement = this;            
    do
    {
        Visual visual = currentVisualTreeElement as Visual;
        if (visual != null)
        {
            Transform transform = VisualTreeHelper.GetTransform(visual);

            // This condition is a way of determining if it
            // was a uniform scale transform. Is there some better way?
            if ((transform != null) &&
                (transform.Value.M12 == 0) &&
                (transform.Value.M21 == 0) &&
                (transform.Value.OffsetX == 0) &&
                (transform.Value.OffsetY == 0) &&
                (transform.Value.M11 == transform.Value.M22))
            {                        
                totalTransform *= transform.Value.M11;
            }
        }
        currentVisualTreeElement = VisualTreeHelper.GetParent(currentVisualTreeElement);
    }
    while (currentVisualTreeElement != null);

    return totalTransform;
}

答案 3 :(得分:1)

您总是可以递归遍历所有Control的父母,并将他们的ScaleTransform相加。

我认为你不能以任何其他方式做到这一点。

答案 4 :(得分:0)

我知道这是一个老问题,但我自己也遇到过类似的问题:我需要进行一种控制来忽略顶层的ScaleTransform

UIElement具有RenderTransform属性,基本上是影响它的ScaleTransform