adding a header to a listbox's scrollviewer an

2019-07-07 03:41发布

问题:

I want to add a header to my ListBoxes and I do this by using a template. The problem is that if I extend the ListBox's template it seems that the listbox's virtualizingstackpanel doesn't work anymore as expected: it loads all content before I can scroll it.

I found some relevant questions in stackoverflow like this (VirtualizingStackPanel stops working when overriding the default control template for ScrollViewer) but the solution given there cannot be applied to WP7: I can't find the property named "CanContentScroll" of the scrollviewer.

my code

<Style x:Key="ListBoxStyle1" TargetType="ListBox">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <ScrollViewer x:Name="ScrollViewer" 
                     BorderBrush="{TemplateBinding BorderBrush}" 
                     BorderThickness="{TemplateBinding BorderThickness}" 
                     Background="{TemplateBinding Background}" 
                     Foreground="{TemplateBinding Foreground}" 
                     Padding="{TemplateBinding Padding}">
                    <StackPanel>
                        <TextBlock Text="..."/>
                        <ItemsPresenter/>
                    </StackPanel>
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

回答1:

To be honest, I'm really not sure what the actual problem is here; the VirtualizingStackPanel is still in the visual tree, but it seems that none of the items actually added. Enough of the bad news, the good news is I've found a way to work round it, by changing the default style of the ScrollViewer to place the header there instead, which results in two styles that look like this:

<Style x:Key="ScrollViewerStyle1" TargetType="ScrollViewer">
    <Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ScrollViewer">
                <Border BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="ScrollStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="00:00:00.5" />
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Scrolling">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="VerticalScrollBar"
                                                        Storyboard.TargetProperty="Opacity"
                                                        To="1"
                                                        Duration="0" />
                                    <DoubleAnimation Storyboard.TargetName="HorizontalScrollBar"
                                                        Storyboard.TargetProperty="Opacity"
                                                        To="1"
                                                        Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="NotScrolling">
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid Margin="{TemplateBinding Padding}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Text="Header" Style="{StaticResource PhoneTextLargeStyle}"/>
                        <ScrollContentPresenter x:Name="ScrollContentPresenter"
                                                Grid.Row="1"
                                                Content="{TemplateBinding Content}"
                                                ContentTemplate="{TemplateBinding ContentTemplate}" />
                        <ScrollBar x:Name="VerticalScrollBar"
                                    Grid.RowSpan="2"
                                    IsHitTestVisible="False"
                                    Opacity="0"
                                    Height="Auto"
                                    Width="5"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Stretch"
                                    Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                    IsTabStop="False"
                                    Maximum="{TemplateBinding ScrollableHeight}"
                                    Minimum="0"
                                    Value="{TemplateBinding VerticalOffset}"
                                    Orientation="Vertical"
                                    ViewportSize="{TemplateBinding ViewportHeight}" />
                        <ScrollBar x:Name="HorizontalScrollBar"
                                    Grid.RowSpan="2"
                                    IsHitTestVisible="False"
                                    Opacity="0"
                                    Width="Auto"
                                    Height="5"
                                    HorizontalAlignment="Stretch"
                                    VerticalAlignment="Bottom"
                                    Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                    IsTabStop="False"
                                    Maximum="{TemplateBinding ScrollableWidth}"
                                    Minimum="0"
                                    Value="{TemplateBinding HorizontalOffset}"
                                    Orientation="Horizontal"
                                    ViewportSize="{TemplateBinding ViewportWidth}" />
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="ListBoxStyle2" TargetType="ListBox">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <ScrollViewer x:Name="ScrollViewer"
                                Grid.Row="1"
                                Style="{StaticResource ScrollViewerStyle1}"
                                Foreground="{TemplateBinding Foreground}"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Padding="{TemplateBinding Padding}">
                    <ItemsPresenter />
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>