ScrollViewer的预留空间

时间:2014-07-11 09:40:51

标签: c# wpf wpf-controls

我有一个ScrollViewer围绕一些控件和

<ScrollViewer VerticalScrollBarVisibility="Auto">
   ...some controls here...
</ScrollViewer>

默认情况下,它不会保留显示滚动条所需的空间。这意味着当它显示/隐藏时,我的控件会被挤压并再次展开。

如何为滚动条预留空间?是否有某种属性或风格我可以设置,这意味着当它不需要它被设置为隐藏而不是崩溃?或者我的孩子控件需要填充&#39;还是在他们右手边的东西离开了空间?我应该将控件放在一个网格中,并使滚动条的滚动条显示在(某种程度上)吗?

我希望它在不需要时仍然是不可见的我只是想让它保留空间的最佳方式。

谢谢大家。

3 个答案:

答案 0 :(得分:9)

这是一个示例

如果使用边框作为占位符

,则会保留滚动条空格
    <ScrollViewer VerticalScrollBarVisibility="auto" x:Name="scroll">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="auto" />
            </Grid.ColumnDefinitions>
            <Border Background="LightGoldenrodYellow"
                    Height="300" />
            <Border Grid.Column="1"
                    Width="{x:Static SystemParameters.VerticalScrollBarWidth}">
                <Border.Style>
                    <Style TargetType="Border">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ComputedVerticalScrollBarVisibility, ElementName=scroll}"
                                         Value="Visible">
                                <Setter Property="Visibility"
                                        Value="Collapsed" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
        </Grid>
    </ScrollViewer>

第一个边框是内容,第二个边框是占位符,用于保留滚动条的空间。您可以选择替换您选择的元素

定义为可重复使用的模板

<Grid>
    <Grid.Resources>
        <ControlTemplate x:Key="ReservedSpaceScroller" TargetType="ContentControl">
            <ScrollViewer VerticalScrollBarVisibility="auto"
                          x:Name="scroll">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="auto" />
                    </Grid.ColumnDefinitions>
                    <ContentPresenter />
                    <Border Width="{x:Static SystemParameters.VerticalScrollBarWidth}"
                            x:Name="placeholder" Grid.Column="1" />
                </Grid>
            </ScrollViewer>
            <ControlTemplate.Triggers>
                <DataTrigger Binding="{Binding ComputedVerticalScrollBarVisibility, ElementName=scroll}"
                             Value="Visible">
                    <Setter TargetName="placeholder"
                            Property="Visibility"
                            Value="Collapsed" />
                </DataTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Grid.Resources>

    <ContentControl Template="{StaticResource ReservedSpaceScroller}">
        <Border Background="LightGoldenrodYellow"
                Height="300" />
    </ContentControl>
</Grid>

结果

result

答案 1 :(得分:0)

如果您希望ScrollViewer始终为其ScrollBar“预留空间”,则可以执行以下操作:

<ScrollViewer VerticalScrollBarVisibility="Visible">
    ...some controls here...
</ScrollViewer>

即使不需要ScrollBar,也会显示{{1}},但在需要时,它不会使您的控件压缩和展开

答案 2 :(得分:0)

我尝试了pushpraj的答案,但是发现,内容上仍在进行调整大小,因为SystemParameters.VerticalScrollBarWidth仅给您纯滚动条的宽度,尽管它可以有边距。

因此,我想到了一个Behavior(行为),该行为直接设置ScrollBar的可见性。首先只需创建一个名为ScrollViewerHiddenScrollbarsBehaviour的类,然后像这样实现它:

/// <summary>
/// Set the ScrollBars of a ScrollViewer to Hidden (instead of Collasped) when they are not needed.
/// </summary>
/// <seealso cref="MTM.UI.Behaviors.FrameworkElementBehaviorBase{System.Windows.Controls.ScrollViewer}" />
public class ScrollViewerHiddenScrollbarsBehaviour : FrameworkElementBehaviorBase<ScrollViewer>
{
    private ScrollBar _verticalScrollBar;
    private ScrollBar _horizontalScrollBar;

    /// <summary>
    /// Setup the Behaviour
    /// </summary>
    protected override void Setup()
    {
        AssociatedObject.Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        // Getting the ScrollBars IF they are set to ScrollBarVisibility.Auto
        _verticalScrollBar = AssociatedObject.VerticalScrollBarVisibility != ScrollBarVisibility.Auto ? null :
            AssociatedObject.Template.FindName("PART_VerticalScrollBar", AssociatedObject) as ScrollBar;
        _horizontalScrollBar = AssociatedObject.HorizontalScrollBarVisibility != ScrollBarVisibility.Auto ? null :
            AssociatedObject.Template.FindName("PART_HorizontalScrollBar", AssociatedObject) as ScrollBar;

        if (_verticalScrollBar != null) {
            // When changing the Visibility of the ScrollBar directly it won't get updated anymore when the ScrollViewer
            // needs it. So let's do this manually.
            DependencyPropertyDescriptor
              .FromProperty(ScrollViewer.ComputedVerticalScrollBarVisibilityProperty, typeof(ScrollViewer))
              .AddValueChanged(AssociatedObject, VerticalHandler);
            VerticalHandler(null, null);
        }
        if (_horizontalScrollBar != null) {
            // When changing the Visibility of the ScrollBar directly it won't get updated anymore when the ScrollViewer
            // needs it. So let's do this manually.
            DependencyPropertyDescriptor
                .FromProperty(ScrollViewer.ComputedHorizontalScrollBarVisibilityProperty, typeof(ScrollViewer))
                .AddValueChanged(AssociatedObject, HorizontalHandler);
            HorizontalHandler(null, null);
        }
    }

    /// <summary>
    /// Sets the Visibility of the vertical ScrollBar as needed by the ScrollViewer, BUT Hidden instead of collapsed
    /// </summary>
    private void VerticalHandler(object sender, EventArgs e)
    {
        if (_verticalScrollBar == null)
            return;

        _verticalScrollBar.Visibility = AssociatedObject.ComputedVerticalScrollBarVisibility == Visibility.Visible
            ? Visibility.Visible
            : Visibility.Hidden;
    }

    /// <summary>
    /// Sets the Visibility of the horizontal ScrollBar as needed by the ScrollViewer, BUT Hidden instead of collapsed
    /// </summary>
    private void HorizontalHandler(object sender, EventArgs e)
    {
        if (_horizontalScrollBar == null)
            return;

        _horizontalScrollBar.Visibility = AssociatedObject.ComputedHorizontalScrollBarVisibility == Visibility.Visible
            ? Visibility.Visible
            : Visibility.Hidden;
    }

    /// <summary>
    /// Cleanup the Behaviour
    /// </summary>
    protected override void Cleanup()
    {
        AssociatedObject.Loaded -= OnLoaded;

        DependencyPropertyDescriptor
            .FromProperty(ScrollViewer.ComputedVerticalScrollBarVisibilityProperty, typeof(ScrollViewer))
            .RemoveValueChanged(AssociatedObject, VerticalHandler);
        DependencyPropertyDescriptor
            .FromProperty(ScrollViewer.ComputedHorizontalScrollBarVisibilityProperty, typeof(ScrollViewer))
            .RemoveValueChanged(AssociatedObject, HorizontalHandler);
    }
}

用法很简单:

<ScrollViewer VerticalScrollBarVisibility="auto">
    <i:Interaction.Behaviors>
        <behaviors:ScrollViewerHiddenScrollbarsBehaviour />
    </i:Interaction.Behaviors>

    <Border Background="LightGoldenrodYellow"
            Height="300" />
    </Border>
</ScrollViewer>

希望这会有所帮助