WPF/Silverlight: обрезка по размеру ячейки сетки и визуализация преобразования
Я простую сетку определил следующим образом:
<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, убедитесь, что вы проверяете 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));
}