WPF / Silverlight: обрезка по размеру ячейки сетки и визуализация преобразования - PullRequest
1 голос
/ 25 июля 2011

У меня есть простая Сетка, определенная следующим образом:

<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, чтобы считывать значения после масштабирования, но ширина и высота по-прежнему равны 200 или 300, ActualWidth и ActualHeight равны нулю.

1 Ответ

0 голосов
/ 31 августа 2012

Em1, убедитесь, что вы проверяете ActualWidth и ActualHeight холста после того, как ваш контент завершил загрузку (т. Е. После того, как событие Loaded было вызвано).

Кроме того, один из способов получить размерхолст, учитывающий все примененные к нему преобразования масштаба, состоит в том, чтобы пройтись по дереву визуалов и применить все преобразования масштаба к элементу 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));
    }
...