3

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

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

有什么方法可以让控件获得应用到它的所有 ScaleTransforms 的摘要?

4

5 回答 5

3

您可以使用PresentationSource'sRootVisual来计算元素的总变换。找到在父母和孩子之间应用的比例的一般模式是

Visual child = /* some visual */ this;
Visual parent = PresentationSource.FromVisual(child).RootVisual;

// calculate the transform needed to go from the parent to the child coordinate spaces
var childTransform = parent.TransformToDescendant(child);

// use the transform to scale a 1x1 rectangle
// use Inverse as the transform is from Parent coordinates to child, we want 
// child to parent
var unitRect = new Rectangle(0, 0, 1, 1);
var transformedUnit = childTransform.Inverse.TransformBounds(unitRect);

// transformedUnit.Width and transformedUnit.Height are now the scale factors (X and Y)
Debug.Assert(transformedUnit.Width == 0.25 && transformedUnit.Height == 0.25);
于 2013-10-05T07:44:40.513 回答
2

根据 Elad Katz 的建议,我创建了一些代码来扫描 VisualTree 以尝试总计任何 uniform ScaleTransforms。如果有人对此算法进行了一些优化,或者可以想到一些我可能没有考虑的事情,请告诉我。同样,我的目标是在给定当前应用的 s 的情况下获得实际上合适的 RenderAtScale ScaleTransformOnRenderSizeChanged似乎是一个可以执行此操作的地方,因为它发生在所有布局内容运行之后。但是,也许有更好的地方来触发 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;
}
于 2011-03-01T00:49:01.173 回答
2

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

但是,如果您知道ScaleTransform应用到 MainGrid,那么您可以绑定RenderAtScaleScaleXMainGridScaleYScaleTransform。也许这就是你已经在做的,但我还是把它作为小费

在 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)}"/>
于 2011-02-27T16:17:21.170 回答
1

您始终可以递归地遍历控件的所有父级并将它们的ScaleTransform.

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

于 2011-02-27T05:26:56.483 回答
0

我知道这是一个老问题,但我自己也有类似的问题:我需要制作一种类型的控件来忽略ScaleTransform顶层的。

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

于 2012-03-14T06:46:14.663 回答