0

を含むWPF UserControl(の内部ElementHostScrollViewerがありItemsControlます。はHorizontalScrollbarVisibilityに設定されてAutoいるため、スクロールが不要な場合は、ScrollBarが非表示になります。

私の要件は、ScrollBarが表示/非表示になった場合、ElementHostそれに応じて高さを調整することです。それを達成するために、私はSizeChangedイベントを聞いています。私はのを取得しDesiredSizeScrollViewer次にEventHandlerに渡しDesiredSize.HeightますElementHost

  1. 見える 2.3 隠れた正しくない、オーバーレイ

1つの方法として、これは機能します。ScrollBar表示されている場合(状況1)、ウィンドウを拡大して、すべてのアイテムItemsControlが表示され、ScrollBar消え、ElementHost高さが低くなるように調整します(状況2)。隠されDesiredSizeた瞬間に実際に小さくなりました。ScrollBar

ただし、逆の場合は機能しません。表示されない場合(状況2)、aが必要になりScrollBar、表示されるまでウィンドウサイズを縮小します。同じままで、調整されません(状況3)。ScrollBarDesiredSizeElementHost

何か案は?

これは、ScrollviewerいくつかのMVVMのものを含むのxamlですが、これにこだわる必要はありません。要点は、実際には、表示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>
4

1 に答える 1

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);
    }
}
于 2013-03-03T14:40:34.417 に答える