2013-02-19 2 views
0

У меня есть WPF UserControl (внутри ElementHost) с ScrollViewer, который содержит ItemsControl. Значение HorizontalScrollbarVisibility установлено на Auto, поэтому, если прокрутка не требуется, ScrollBar будет скрыт.WPF Scrollviewer DesiredSize не увеличивается, когда ScrollBar становится видимым

Мое требование: если ScrollBar будет отображаться/скрываться, то ElementHost отрегулирует его соответственно. Для этого я слушаю событие SizeChanged, я получаю DesiredSizeScrollViewer в EventHandler, затем передаю DesiredSize.Height на номер ElementHost.

  1. visible 2. hidden 3. incorrect, overlaid

Один из способов, это работает: С ScrollBar видимой (положение 1), я увеличиваю мое окно, пока все пункты ItemsControl не видно, ScrollBar исчезает, ElementHost настраивается на уменьшенную высоту (ситуация 2). DesiredSize фактически получил меньше момента, когда ScrollBar скрыт.

Другой способ, однако, не работает: с ScrollBar не видно (ситуация 2), я уменьшаю размер окна до тех пор, пока не появится ScrollBar. DesiredSize остается неизменным, а ElementHost не регулируется (ситуация 3).

Любые идеи?

Это XAML из Scrollviewer, с некоторыми MVVM вещи, но не зацикливаться на этом, точка на самом деле, почему DesiredSize не увеличивается, когда ScrollBar появляется? Почему он только сокращается?

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden" > 
    <i:Interaction.Behaviors> 
     <beh:HeightChangedBehavior HeightChangedCommand="{Binding HeightChangedCommand}" /> 
    </i:Interaction.Behaviors> 
    <ItemsControl ItemsSource="{Binding TabHeaders}" > 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel IsItemsHost="True" Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate DataType="models:TabHeaderButtonModel"> 
       <RadioButton Content="{Binding Caption}" IsChecked="{Binding IsChecked, Mode=TwoWay}" GroupName="Tabs" 
          Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding}" 
          Style="{StaticResource TabHeaderToggleButtonStyle}"> 
       </RadioButton> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</ScrollViewer> 

ScrollViewer стиль (в основном по умолчанию WPF):

<Style x:Key="ScrollViewerStyle1" TargetType="{x:Type ScrollViewer}"> 
    <Setter Property="Template" > 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type ScrollViewer}"> 
       <Grid x:Name="Grid" Background="{TemplateBinding Background}"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="Auto"/> 
        </Grid.ColumnDefinitions> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="*"/> 
         <RowDefinition Height="Auto"/> 
        </Grid.RowDefinitions> 
        <Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/> 
        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/> 
        <ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/> 
        <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}" Style="{DynamicResource ScrollBarStyle1}"/> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    <Style.Triggers> 
     <Trigger Property="IsEnabled" Value="false"> 
      <Setter Property="Foreground" Value="White"/> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

ответ

0

Я должен был рассчитать требуемую высоту, получая содержание желаемой высоты ScrollViewer и добавляя высоту ScrollBar, если видны.

Это все еще немного неудобно для меня, поэтому, если у вас есть лучшее решение, я с радостью изменю принятый ответ.

public class HeightChangedBehavior : Behavior<ScrollViewer> 
{ 
    public ICommand HeightChangedCommand { get { return (ICommand)GetValue(HeightChangedCommandProperty); } set { SetValue(HeightChangedCommandProperty, value); } } 
    public static readonly DependencyProperty HeightChangedCommandProperty = DependencyProperty.Register("HeightChangedCommand", typeof(ICommand), typeof(HeightChangedBehavior), new PropertyMetadata(null)); 


    protected override void OnAttached() 
    { 
     this.AssociatedObject.ScrollChanged += AssociatedObject_ScrollChanged; 
     base.OnAttached(); 
    } 

    /// <summary> 
    /// Calculates the desired height for the scrollviewer, as the sum of its content 
    /// desired height and, if visible, the horizontal scrollbar height. 
    /// </summary> 
    void AssociatedObject_ScrollChanged(object sender, ScrollChangedEventArgs e) 
    { 
     ScrollViewer sv = (ScrollViewer)sender; 

     // get content height 
     double height = ((FrameworkElement)sv.Content).DesiredSize.Height; 

     if (sv.ComputedHorizontalScrollBarVisibility == Visibility.Visible) 
     { 
      // add scrollbar height 
      height += (double)sv.FindResource(SystemParameters.HorizontalScrollBarHeightKey); // template of scrollbar should use this key 
     } 

     int intHeight = (int)Math.Ceiling(height); // whole pixels 

     // execute the command 
     ICommand cmd = this.HeightChangedCommand; 
     if (cmd != null && intHeight != sv.ActualHeight) 
      cmd.Execute(intHeight); 
    } 
} 
Смежные вопросы