【问题标题】:ScrollViewer is visible?ScrollViewer 可见吗?
【发布时间】:2014-07-25 16:07:46
【问题描述】:

我正在使用 ComputedHorizo​​ntalScrollBarVisibility,但是当您将 Horizo​​ntalScrollBarVisibility 设置为“隐藏”时,这不起作用。

我想要实现的是知道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 >

【问题讨论】:

  • 您将HorizontalScrollBarVisibility 设置为Auto,我认为这将等于Visibility.Collapsed(不是Hidden)并且不会占用布局中的任何空间。
  • 是的,这是想要的效果,但是当它可见时,我想显示按钮而不是滚动查看器
  • 您可能需要创建自己的 ScrollViewer 控件,该控件仍可进行所需的测量,但不显示 ScrollViewer,

标签: c# wpf xaml


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    更多详情请参考link

    【讨论】:

      【解决方案3】:

      根据我的经验,滚动查看器属性值在下一次布局传递之前可能会过时。在我下面的简单示例中它是代码隐藏,但这确实可以按照您想要的方式工作。

      我创建了一个名为“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 >
      

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

      【讨论】:

      • 我的问题是所有这些代码都在 ItemsControl 中,所以我有几个带有按钮的 ScrollViewers 和 StackPanels,用你的方法我怎么知道哪个 Scroll 是?
      • 我最终做了一些非常相似但没有绑定可见性的事情。谢谢!
      【解决方案4】:

      感谢大家的回答,但最终得到了一个更简单的解决方法,而不是绑定按钮的StackPanel 的可见性,只需在ScrollViewer 中调用ScrollChanged,然后在代码中检查@ 987654324@ 并根据结果更改可见性。

      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;
            }
         }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-21
        • 2011-09-30
        相关资源
        最近更新 更多