保持 UWP 中 ListView.HeaderTemplate 的可见性/静态/粘性

7
我需要始终保持ListView的HeaderTemplate可见,但我不知道要设置什么或更改ListView模板的哪个部分才能实现这一点。目前的设置导致ListView的标题随着向下滚动项目而从顶部滚动出去。如何在滚动ListView的项目时保持Header "row"可见?以下是我的XAML代码:
<ListView x:Name="permitResults"
          Grid.Row="1"
          AutomationProperties.AutomationId="PermitResults"
          AutomationProperties.Name="Permit Search Results"
          ItemsSource="{Binding Source={StaticResource ResultsSource}}" 
          ItemClick="permitResults_ItemClick"
          SelectionMode="None"
          TabIndex="1"
          Padding="0"
          Margin="0"
          BorderThickness="0"
          IsSwipeEnabled="True"
          IsItemClickEnabled="True"
          ScrollViewer.VerticalScrollBarVisibility="Auto" >
    <ListView.HeaderTemplate>
        <DataTemplate>
            <Grid Margin="0,0,0,0" Width="1366" Height="Auto" HorizontalAlignment="Left">
                <Grid.Resources>
                        <Style TargetType="TextBlock" BasedOn="{StaticResource SearchGridResultsHeaderTextBlock}">
                            <Setter Property="HorizontalAlignment" Value="Left"></Setter>
                        </Style>
                    </Grid.Resources>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="2*"/>
                        <ColumnDefinition Width="2*"/>
                        <ColumnDefinition Width="3*"/>
                        <ColumnDefinition Width="2*"/>
                        <ColumnDefinition Width="6*"/>
                        <ColumnDefinition Width="2*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="Permit #" MaxLines="2" TextWrapping="WrapWholeWords"/>
                    <TextBlock Grid.Column="1" Text="County" TextWrapping="WrapWholeWords" />
                    <TextBlock Grid.Column="2" Text="Business Name" TextWrapping="WrapWholeWords" />
                    <TextBlock Grid.Column="3" Text="Status" TextWrapping="WrapWholeWords" />
                    <TextBlock Grid.Column="4" Text="Type" TextWrapping="WrapWholeWords" />
                    <TextBlock Grid.Column="5" Text="FY" TextWrapping="WrapWholeWords" />
                </Grid>
        </DataTemplate>
    </ListView.HeaderTemplate>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Margin="-11,0,0,0" Width="1366" Height="Auto">
                <Grid.Resources>
                    <Style TargetType="TextBlock" BasedOn="{StaticResource SearchGridResultsTextBlock}">
                        <Setter Property="HorizontalAlignment" Value="Left"></Setter>
                    </Style>
                </Grid.Resources>
                <Grid.RowDefinitions>
                    <RowDefinition Height="44"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="3*"/>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="6*"/>
                    <ColumnDefinition Width="2*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding PermitNumber}" TextWrapping="WrapWholeWords" />
                <TextBlock Grid.Column="1" Text="{Binding County}" TextWrapping="NoWrap" />
                <TextBlock Grid.Column="2" Text="{Binding BusinessName}" TextWrapping="NoWrap" />
                <TextBlock Grid.Column="3" Text="{Binding Status}" TextWrapping="NoWrap" />
                <TextBlock Grid.Column="4" Text="{Binding PermitType}" TextWrapping="NoWrap" />
                <TextBlock Grid.Column="5" Text="{Binding EffFiscalYear}" TextWrapping="NoWrap" />
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

看起来你的标题是静态的。那么为什么不将标题从ListView中拉出来,放在外面呢?还有,为什么要将宽度设置为1366?小屏幕怎么办?如果你认为这不是一个好主意,请告诉我,我会以另一种方式回答你的问题。 - AVK
@AVKNaidu 我可以这样做,但是在我的应用程序中有大约10个这样的元素,如果有一种方法可以应用一个样式来完成这个任务,那就更好了。设置宽度仅是为了在设计模式下查看整个元素,我忘记删除了。 - BlackICE
将您的列表视图包装在滚动查看器中。 滚动查看器具有顶部标题模板。 在那里加载您的标题模板。 内容将仅为您的列表视图。 确保ListView的水平对齐方式为左侧,垂直对齐方式为顶部。 看看是否有帮助。否则请告诉我。 - AVK
好的,我会尝试一下并看看结果,谢谢。 - BlackICE
请尝试我的答案 @BlackICE - Andrii Krupka
3个回答

11

将此样式应用于您的ListView,您将拥有静态标题。

    <Style TargetType="ListView" x:Key="FixedHeaderListViewStyle">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="TabNavigation" Value="Once" />
        <Setter Property="IsSwipeEnabled" Value="True" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
        <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
        <Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False" />
        <Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled" />
        <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
        <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
        <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
        <Setter Property="UseSystemFocusVisuals" Value="True" />
        <Setter Property="ItemContainerTransitions">
            <Setter.Value>
                <TransitionCollection>
                    <AddDeleteThemeTransition />
                    <ContentThemeTransition />
                    <ReorderThemeTransition />
                    <EntranceThemeTransition IsStaggeringEnabled="False" />
                </TransitionCollection>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <ItemsStackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListView">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" 
                            Background="{TemplateBinding Background}" 
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>

                            <ContentControl Content="{TemplateBinding Header}"
                                                ContentTemplate="{TemplateBinding HeaderTemplate}"
                                                ContentTransitions="{TemplateBinding HeaderTransitions}"/>

                            <ScrollViewer x:Name="ScrollViewer"
                                          Grid.Row="1"
                                        TabNavigation="{TemplateBinding TabNavigation}"
                                        HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                                        HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                        IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
                                        VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                                        VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                                        IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
                                        IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                                        IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                                        ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
                                        IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                                        BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                                        AutomationProperties.AccessibilityView="Raw">
                                <ItemsPresenter 
                                                Footer="{TemplateBinding Footer}"
                                                FooterTemplate="{TemplateBinding FooterTemplate}"
                                                FooterTransitions="{TemplateBinding FooterTransitions}"
                                                Padding="{TemplateBinding Padding}" />
                            </ScrollViewer>

                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

谢谢,我会尝试一下,并且如果有不同的话也会发布我的版本。 - BlackICE
尝试了这个。感谢 @Andrii。非常有效,完全实现了它所说的功能。然而,对于我目前的情况,我还需要水平滚动。不幸的是,这个解决方案并没有提供头部与项目一起水平滚动(同时跟踪它们)。但如果你不需要水平滚动,这仍然是一个很好的答案 :) - Geoff James
1
帮了我很大的忙 - 只需提取setter的模板部分,listview就能像标准一样运行和显示,但带有静态标题。 - Lindsay
哇,好多代码才能完成小任务。感谢你的帮助! - Borzh
@Borzh - 乍一看,我同意你的观点,但是经过更深入的思考,我没有看到其他选择。设计师可能选择让一个属性折叠一个可视树并使另一个可见,如果您有“FixedHeader”== true,或者反之亦然,但那将非常丑陋,并且可能性能不佳。 - Quark Soup
好的。我已经找到了实现这个功能的最佳方法,使用水平滚动条和虚拟化,而无需限制列表视图的高度,就是通过对Id进行分组查询,并使用CollectionViewSource与分组头模板。 - 27k1

2

Andrii提供的样式绝对是正确的答案,但你不需要包含所有其他内容。当覆盖内置样式时,你只需要为实际覆盖的内容提供setter即可。最少的代码如下:

Original Answer翻译成"最初的回答"

<Style x:Key="FixedHeaderListViewStyle"
       TargetType="ListView">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListView">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <ContentControl Content="{TemplateBinding Header}"
                                        ContentTemplate="{TemplateBinding HeaderTemplate}"
                                        ContentTransitions="{TemplateBinding HeaderTransitions}"/>
                        <ScrollViewer AutomationProperties.AccessibilityView="Raw"
                                      BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                                      Grid.Row="1"
                                      HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                      HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                                      IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                                      IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                                      IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
                                      IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                                      IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
                                      x:Name="ScrollViewer"
                                      TabNavigation="{TemplateBinding TabNavigation}"
                                      VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                                      VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                                      ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
                            <ItemsPresenter Footer="{TemplateBinding Footer}"
                                            FooterTemplate="{TemplateBinding FooterTemplate}"
                                            FooterTransitions="{TemplateBinding FooterTransitions}"
                                            Padding="{TemplateBinding Padding}"/>
                        </ScrollViewer>

                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这看起来是一个不错的替代方案,代码量少得多,但我已经有一段时间没有使用WPF了,所以我不能确定它是否有效,希望有人能试一下! - BlackICE

2
根据最初的回答(如果不需要水平滚动,则完美运作),以下是实现“水平滚动+粘性标题”的解决方法(FixedHeaderListViewStyle与上面相同):
<ScrollViewer
   HorizontalScrollBarVisibility="Auto"
   HorizontalScrollMode="Auto"
   VerticalScrollBarVisibility="Disabled"
   VerticalScrollMode="Disabled">
   <ListView Style="{StaticResource FixedHeaderListViewStyle}">
      <!-- your list here -->
   </ListView>
</ScrollViewer>

问题在于您已禁用了 ScrollViewer 的虚拟化。 - 27k1
@peterincumbria 你是什么意思?我在scrollViewer中禁用了垂直滚动,是因为ListView已经启用了垂直滚动。 - Wendee Hsu
嗨,你可能是正确的,请检查一下。我在虚拟化方面遇到了一些问题,如果你有时间测试,请让我知道结果 - 可能会很有趣。https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/listview-and-gridview-data-optimization - 27k1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接