WPF/Silverlight:裁剪到网格单元大小和 RenderTransform

Posted

技术标签:

【中文标题】WPF/Silverlight:裁剪到网格单元大小和 RenderTransform【英文标题】:WPF/Silverlight: Clipping to Grid Cell Size & RenderTransform 【发布时间】:2011-07-25 15:21:53 【问题描述】:

我有一个这样定义的简单网格:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="24" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="24" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
</Grid>

在网格的每个单元格(左上角单元格除外)中,我添加了一个网格或画布。在这些容器中,我添加了几个不同的对象。由于放大或缩小和滚动,其中一些控件可以更改查看大小。

原代码不是我自己的,但是我做了一个小测试程序来模拟这种情况:

<Grid Grid.Column="1" Grid.Row="1">
  <Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="20"/>
  </Grid.RowDefinitions>

<Grid x:Name="Frame" Grid.Row="0">
  <Canvas Width="200" Height="300" Background="Green" >
    <Canvas x:Name="Page" Width="200" Height="300" Background="Bisque" Margin="0 -20 0 0">
      <Canvas.RenderTransform>
        <ScaleTransform ScaleX="Binding ElementName=Zoom, Path=Value"
                        ScaleY="Binding ElementName=Zoom, Path=Value"
                        CenterX="100" CenterY="150" />
      </Canvas.RenderTransform>
    </Canvas>
  </Canvas>
</Grid>
<Slider x:Name="Zoom" Grid.Row="1" HorizontalAlignment="Right" Width="200"
        Minimum="0.1" Maximum="2" Value="1"
        TickPlacement="BottomRight" TickFrequency="0.1" IsSnapToTickEnabled="True" />

页面太大,超出范围,尤其是当我放大时。

我尝试添加剪辑,但我不知道如何动态设置值。

<Grid x:Name="Frame" Grid.Row="0">
  <Grid.Clip>
    <!-- I want to bind to the actual size of the cell -->
    <RectangleGeometry Rect="0 0 480 266" />
  </Grid.Clip>
  <Canvas Width="200" Height="300" Background="Green" >
  ....

此外,如何获得渲染画布的实际大小和位置。我插入 Zoom_ValueChanged 以读出缩放后的值,但 Width 和 Height 仍然是 200 或 300,ActualWidth 和 ActualHeight 都是零。

提前致谢。

【问题讨论】:

【参考方案1】:

Em1,确保在内容加载完成后(即引发 Loaded 事件后)检查画布的 ActualWidth 和 ActualHeight。

此外,考虑到所有已应用到它的缩放变换来获取画布大小的一种方法是向上走可视化树并将所有缩放变换应用到控件的 ActualWidth 和 ActualHeight:

public static Size GetActualSize(FrameworkElement control)

    Size startSize = new Size(control.ActualWidth, control.ActualHeight);

    // go up parent tree until reaching root
    var parent = LogicalTreeHelper.GetParent(control);
    while(parent != null && parent as FrameworkElement != null && parent.GetType() != typeof(Window))
    
        // try to find a scale transform
        FrameworkElement fp = parent as FrameworkElement;
        ScaleTransform scale = FindScaleTransform(fp.RenderTransform);
        if(scale != null)
        
            startSize.Width *= scale.ScaleX;
            startSize.Height *= scale.ScaleY;
        
        parent = LogicalTreeHelper.GetParent(parent);
    
    // return new size
    return startSize;


public static ScaleTransform FindScaleTransform(Transform hayStack)

    if(hayStack is ScaleTransform)
    
        return (ScaleTransform) hayStack;
    
    if(hayStack is TransformGroup)
    
        TransformGroup group = hayStack as TransformGroup;
        foreach (var child in group.Children)
        
            if(child is ScaleTransform)
            
                return (ScaleTransform) child;
            
        
    
    return null;

要获取控件的位置,您需要找到它相对于包含窗口的变换。方法如下:

    public static Point TransformToWindow(Visual control)
    
        var hwndSource = PresentationSource.FromVisual(control) as HwndSource;
        if (hwndSource == null)
            return new Point(-1, -1);
        Visual root = hwndSource.RootVisual; // Translate the point from the visual to the root.
        GeneralTransform transformToRoot = control.TransformToAncestor(root);
        return transformToRoot.Transform(new Point(0, 0));
    

【讨论】:

以上是关于WPF/Silverlight:裁剪到网格单元大小和 RenderTransform的主要内容,如果未能解决你的问题,请参考以下文章

剑道网格调整大小列不显示其标题单元格的调整大小句柄

您知道任何使用 MVVM 的真实、有用的 WPF/Silverlight 应用程序吗?

WPF Grid与Stackpanel

在 WPF、Silverlight 和 ASP.NET 之间共享一个公共 DAL

.NET 开发的未来:ASP.NET 还是 WPF/Silverlight/Winforms? [关闭]

如何使用WPF或Silverlight制作游戏?