WPF缩放&x2B;滚动条?
我正在尝试缩放scrollviewer中的一些内容 我正在寻找的缩放行为是RenderTransform+ScaleTransform。但这不适用于ScrollViewer 使用LayoutTransform+ScaleTransform,scrollviewer确实会受到影响(仅限ContentTemplate1),但其行为不像缩放 假设不能更改ContentTemplate1/ContentTemplate2(即,第三方控件),如何让zoom与scrollviewer一起工作WPF缩放&x2B;滚动条?,wpf,xaml,zooming,Wpf,Xaml,Zooming,我正在尝试缩放scrollviewer中的一些内容 我正在寻找的缩放行为是RenderTransform+ScaleTransform。但这不适用于ScrollViewer 使用LayoutTransform+ScaleTransform,scrollviewer确实会受到影响(仅限ContentTemplate1),但其行为不像缩放 假设不能更改ContentTemplate1/ContentTemplate2(即,第三方控件),如何让zoom与scrollviewer一起工作 <Gri
<Grid>
<Grid.Resources>
<!-- Content type 1 -->
<DataTemplate x:Key="ContentTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Background="DodgerBlue" Text="Left"/>
<TextBlock Grid.Column="1" Background="DarkGray" Text="Right"/>
</Grid>
</DataTemplate>
<!-- Content type 2 -->
<DataTemplate x:Key="ContentTemplate2">
<Viewbox>
<TextBlock Background="DodgerBlue" Text="Scale to fit" Width="100" Height="70" Foreground="White" TextAlignment="Center"/>
</Viewbox>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TabControl>
<!-- Content 1 -->
<TabControl.Resources>
<ScaleTransform x:Key="ScaleTransform"
ScaleX="{Binding ElementName=ZoomSlider,Path=Value}"
ScaleY="{Binding ElementName=ZoomSlider,Path=Value}" />
</TabControl.Resources>
<TabItem Header="Content 1">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ContentControl ContentTemplate="{StaticResource ContentTemplate1}" Margin="10" RenderTransformOrigin=".5,.5">
<!-- Affects scrollviewer, but does not behave like a zoom -->
<!--<FrameworkElement.LayoutTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.LayoutTransform>-->
<!-- Expected zoom behavior, but doesn't affect scrollviewer -->
<FrameworkElement.RenderTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.RenderTransform>
</ContentControl>
</ScrollViewer>
</TabItem>
<!-- Content 2 -->
<TabItem Header="Content 2">
<ContentControl ContentTemplate="{StaticResource ContentTemplate2}" Margin="10" RenderTransformOrigin=".5,.5">
<!-- Affects scrollviewer, but does not behave like a zoom -->
<!--<FrameworkElement.LayoutTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.LayoutTransform>-->
<!-- Expected zoom behavior, but doesn't affect scrollviewer -->
<FrameworkElement.RenderTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.RenderTransform>
</ContentControl>
</TabItem>
</TabControl>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<!-- Zoom -->
<Slider x:Name="ZoomSlider"
Width="100"
Maximum="5"
Minimum="0.1"
Orientation="Horizontal"
Value="1" />
<!-- Autofit -->
<CheckBox Content="Autofit?" x:Name="AutoFitCheckBox" />
</StackPanel>
</Grid>
如果我理解正确:
- 是否要使用
进行缩放缩放滑块
- 如果内容太大,无法放入其选项卡中,是否希望显示滚动条
layoututtransform
。这种转换是在所有元素被测量和布局之前完成的,并且ScrollViewer
将能够判断是否需要滚动条
在我的机器上,如果您只需切换到LayoutTransform
,则“内容1”选项卡将按预期工作(请注意,在“右”从屏幕上消失之前,您必须进行大量缩放,切换滚动条):
“内容2”需要更多的工作。首先,该选项卡中没有ScrollViewer
,因此需要添加它。其次,ContentTemplate2
使用一个默认拉伸的ViewBox
,因此,在真正放大之前,缩放不会产生效果。要禁用ViewBox内置的“缩放”,您可以将ContentControl
容器居中(使用HorizontalAlignment/VerticalAlignment
),这将迫使它占用尽可能少的空间:
<TabItem Header="Content 2">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ContentControl ContentTemplate="{StaticResource ContentTemplate2}" ...
HorizontalAlignment="Center" VerticalAlignment="Center" >
<FrameworkElement.LayoutTransform>
...
...
要使缩放的元素获得准确的
渲染转换
外观,我们不妨坚持使用渲染转换
,而是告诉滚动查看器
如何实现我们自己的滚动逻辑。此方法基于以下优秀教程:
我们创建了自己的自定义“ZoomableContentControl”
,它实现了IScrollInfo
,并告诉ScrollViewer
从那里获取其滚动逻辑(ScrollViewer.CanContentScroll=True)。魔法发生在ArrangeOverride()
中,我们在这里玩extendwidth/ExtentHeight
和rendertransferormorigin
public class ZoomableContentControl : ContentControl, IScrollInfo
{
public ZoomableContentControl()
{
this.RenderTransformOrigin = new Point(0.5, 0.5);
}
private ScaleTransform _scale = null;
private ScaleTransform Scale
{
get
{
if (_scale == null)
{
_scale = this.RenderTransform as ScaleTransform;
//RenderTransforms don't update the layout, so we need to trigger that ourselves:
_scale.Changed += (s, e) => { InvalidateArrange(); };
}
return _scale;
}
}
protected override Size ArrangeOverride(Size arrangeBounds)
{
Statics.MessageIfDebug("Arranging");
var layout = base.ArrangeOverride(arrangeBounds);
var scale = this.Scale;
if (scale != null)
{
//Because RenderTransforms don't update the layout,
//we need to pretend we're bigger than we are to make room for our zoomed content:
_extent = new Size(layout.Width * scale.ScaleX, layout.Height * scale.ScaleY);
_viewport = layout;
//Coerce offsets..
var maxOffset = new Vector(ExtentWidth - ViewportWidth, ExtentHeight - ViewportHeight);
_offset.X = Math.Max(0, Math.Min(_offset.X, maxOffset.X));
_offset.Y = Math.Max(0, Math.Min(_offset.Y, maxOffset.Y));
//..and move the zoomed content within the ScrollViewer:
var renderOffsetX = (maxOffset.X > 0) ? (_offset.X / maxOffset.X) : 0.5;
var renderOffsetY = (maxOffset.Y > 0) ? (_offset.Y / maxOffset.Y) : 0.5;
this.RenderTransformOrigin = new Point(renderOffsetX, renderOffsetY);
if (ScrollOwner != null)
{
ScrollOwner.InvalidateScrollInfo();
}
}
return layout;
}
#region IScrollInfo
//This is the boilerplate IScrollInfo implementation,
//which can be found in *the first half* of this tutorial:
//https://web.archive.org/web/20140809230047/http://tech.pro/tutorial/907/wpf-tutorial-implementing-iscrollinfo
//(down to and including SetHorizontalOffset()/SetVerticalOffset()).
//Note the bug reported by "Martin" in the comments.
...
用法:
<TabItem Header="Content 1">
<ScrollViewer CanContentScroll="True"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<v:ZoomableContentControl ContentTemplate="{StaticResource ContentTemplate1}" Margin="10" >
<FrameworkElement.RenderTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.RenderTransform>
</v:ZoomableContentControl>
</ScrollViewer>
</TabItem>
<TabItem Header="Content 2">
<ScrollViewer CanContentScroll="True"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<v:ZoomableContentControl ContentTemplate="{StaticResource ContentTemplate2}" Margin="10" >
<FrameworkElement.RenderTransform>
<StaticResource ResourceKey="ScaleTransform" />
</FrameworkElement.RenderTransform>
</v:ZoomableContentControl>
</ScrollViewer>
</TabItem>
我的第一个建议是,使用已经支持ScrollViewer并具有许多附加缩放和平移功能的商业第三方,检查您可以使用哪种缩放功能 现在来解决您的问题: 您可以使用LayoutTransform使代码正常工作,但需要将ScrollViewer内容的大小设置为固定值 当前,在ScrollViewer中有一个网格。网格没有定义其大小,因此它占用了它所能获得的所有空间。因此,如果您现在缩放网格,例如按因子2缩放,这意味着网格的内容按因子2缩放,但网格仍将占用它可以获得的所有空间。如果将栅格的宽度指定为500,然后将其缩放2,将使栅格的宽度为1000。但是如果你说:Grid,你可以占据父母给你的所有空间,然后缩放网格,它仍然是一样的。这意味着缩放ScrollViewer的自动调整大小的内容将不会显示滚动条 在您的示例中,直到网格的内容(第一列的宽度=150+第二列中“右”文本的宽度)超过可用的大小,网格的所需大小将大于ScrollViewer可以提供的大小,ScrollViewer将显示滚动条,这才是真的 例如: 1) 假设启动应用程序时,scale设置为1,ScrollViewer为网格水平提供500个点。网格显示第一列,宽度为150点,显示“右”文本,没有任何比例。第二列设置为填充剩余空间,因此第二列使用500-150=350个点 2) 现在用户将比例设置为2。栅格将第一列缩放为300点。这意味着第二列现在只能获得200点。网格也会缩放“右”文本,但内容(第一列300+文本宽度)仍然不超过ScrollViewer提供的500点 3) 用户现在将比例设置为3。现在网格内容的总宽度超过500点,这意味着ScrollViewer将显示滚动条 因此,使用自动调整大小的控件、ScrollViewer和缩放功能并不能很好地工作 但是,如果将网格的大小固定为500,则在缩放和使用ScrollViewer时,将获得更可预测的结果。例如,如果按10%的比例缩放,网格的大小将为550,并且已经超过ScrollViewer的大小,因此ScrollViewer将显示滚动条。这也会给你预期的行为,当你
<ContentControl Name="ContentControl1"
ContentTemplate="{StaticResource ContentTemplate1}"
Margin="10"
Loaded="ContentControl1_OnLoaded" >
private void ContentControl1_OnLoaded(object sender, RoutedEventArgs e)
{
ContentControl1.Width = ContentControl1.ActualWidth;
ContentControl1.Height = ContentControl1.ActualHeight;
}