ScrollViewer is visible?

本文关键字:visible is ScrollViewer | 更新日期: 2023-09-27 18:14:42

我使用的是ComputedHorizontalScrollBarVisibility,但是当你将HorizontalScrollBarVisibility设置为"Hidden"时,这就不起作用了。

我想要实现的是知道ScrollViewer是否应该可见,但不显示ScrollViewer。然后将结果绑定到显示控制ScrollViewer的按钮(在本例中为下面的StackPanel)。

XAML

<ScrollViewer HorizontalScrollBarVisibility="Auto" x:Name="Scroll">
   .....
</ScrollViewer>
<StackPanel Visibility="{Binding ElementName=Scroll, Path=ComputedHorizontalScrollBarVisibility}">
   <Button Grid.Column="0" Content="Left" HorizontalAlignment="Left" Click="..."/>
   <Button Grid.Column="1" Content="Right" HorizontalAlignment="Right" Click="..."/>
</StackPanel >

ScrollViewer is visible?

如果您需要控制ScrollViewer(或任何控件)的布局方式,请考虑使用ControlTemplate,它可以在任何控件的Template属性中访问。因为这将允许您绑定到对象本身和传递给它的值,并提供这样的模板。然而,这可能涉及到需要处理计算,以显示控件可见的确切部分。

你可以通过简单地将ScrollViewer中的内容元素的宽度相加来得到你想要的,例如,如果你在ScrollViewer中有StackPanel(与Orientation=Horizontal),那么将StackPanel中的每个子元素的宽度相加,并将其与ScrollViewerActualWidth进行比较。如果总和小于ScrollViewerActualWidth,那么你需要滚动它。

详细信息请参考此链接

根据我的经验,滚动查看器属性值可能会过时,直到下一个布局通过。在我下面的简单示例中,它是代码隐藏的,但它确实按照你想要的方式工作。

我创建了一个名为"ShowScrollButtons"的依赖属性。你可以观察范围和视口大小的变化,并自动重新计算属性。

当滚动内容大小改变时,我触发对ShowScrollButtons的重新评估。注意对UpdateLayout的调用,以确保范围和视口大小是最新的。同样,这是一个示例我只检查左/右滚动按钮的宽度

private void UpdateScrollButtonVis()
{
    UpdateLayout();
    ShowScrollButtons = (Scroll.ExtentHeight > Scroll.ViewportWidth);
}
在XAML…

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="boolvis"/>
</Window.Resources>
<Grid x:Name="theGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <ScrollViewer Grid.Row="0"  Width="100" Height="100" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" x:Name="Scroll">
        <Canvas x:Name="theCanvas"  Width="300" Height="300" Background="Green"/>
    </ScrollViewer>
    <StackPanel Grid.Row="1"  Visibility="{Binding ShowScrollButtons,Converter={StaticResource boolvis}}">
        <Button Grid.Column="0" Content="Left" HorizontalAlignment="Left" />
        <Button Grid.Column="1" Content="Right" HorizontalAlignment="Right" />
    </StackPanel >
    <Button x:Name="toggle" Grid.Row="2"  Height="25" Width="100" Click="toggle_Click">Toggle</Button>
</Grid>

更新:

一个新的方法如何与多个滚动查看器和stackpanel一起工作,而不需要隐藏代码。

使用附加属性来控制外部按钮的可见性:

public class ScrollViewWatcher
{
    public static readonly DependencyProperty HorizontalButtonVisibility = DependencyProperty.RegisterAttached(
       "HorizontalButtonVisibility",
       typeof(Visibility),
       typeof(ScrollViewWatcher),
       new FrameworkPropertyMetadata(Visibility.Visible,
           FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)
     );
    public static Visibility GetHorizontalButtonVisiblity(UIElement element)
    {
        return (Visibility)element.GetValue(HorizontalButtonVisibility);
    }
    public static void SetHorizontalButtonVisibility(UIElement element, Visibility value)
    {
        element.SetValue(HorizontalButtonVisibility, value);
        ScrollViewer sv = element as ScrollViewer;
        if (sv != null)
        {
            sv.ScrollChanged -= sv_ScrollChanged;
            sv.ScrollChanged += sv_ScrollChanged;
        }
    }
    static void sv_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        var sv = sender as ScrollViewer;
        if (sv != null)
        {
            var vis = sv.ExtentHeight > sv.ViewportWidth ? Visibility.Visible : Visibility.Hidden;
            sv.SetValue(HorizontalButtonVisibility, vis);
        }
    }
}
然后在XAML中,像这样绑定到相应的ScrollViewer:
<ScrollViewer 
    x:Name="sv1" local:ScrollViewWatcher.HorizontalButtonVisibility="Visible"  
    Grid.Row="0" Width="100" Height="100" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" >
    <Canvas x:Name="theCanvas"  Width="300" Height="300" Background="Green"/>
</ScrollViewer>
<StackPanel Grid.Row="1" Visibility="{Binding ElementName=sv1,Path=(local:ScrollViewWatcher.HorizontalButtonVisibility), Mode=OneWay}">
        <Button Grid.Column="0" Content="Left" HorizontalAlignment="Left" />
    <Button Grid.Column="1" Content="Right" HorizontalAlignment="Right" />
</StackPanel >

这在我的测试中效果很好。这是一个有趣的挑战。也许有人能给我们一个更好的方法,但我对此很满意。

感谢大家的回答,但最终得到了一个更容易的解决方案,而不是从StackPanel的按钮绑定可见性,只是调用ScrollViewer中的ScrollChanged,然后在代码检查ComputedHorizontalScrollBarVisibility和改变可见性取决于结果。

XAML

<ScrollViewer HorizontalScrollBarVisibility="Auto" x:Name="Scroll" ScrollChanged="Scroll_ScrollChanged">
       .....
    </ScrollViewer>
    <StackPanel x:Name="BPanel" Visibility="Hidden">
       <Button Grid.Column="0" Content="Left" HorizontalAlignment="Left" Click="..."/>
       <Button Grid.Column="1" Content="Right" HorizontalAlignment="Right" Click="..."/>
    </StackPanel >
c#

private void Scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
   ScrollViewer scroll = (ScrollViewer)sender;
   if(scroll.HorizontalScrollBarVisibility == ScrollBarVisibility.Auto)
   {
      if (scroll.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
      {
         scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
         BPanel.Visibility = Visibility.Visible;
      }
   }
}