UWP - ItemsStackPanel 中 HeaderTemplate 的拉伸高度,GroupHeaderPlacement=Left

UWP - Stretch height of HeaderTemplate in ItemsStackPanel with GroupHeaderPlacement=Left

在 ItemsControl 或 ListView 中,是否可以使 GroupStyle.HeaderTemplate 的高度拉伸以匹配分组项目的高度?

无论我将 VerticalAlignment/VerticalContentAlignment 设置为什么,组 header 都会出现在组中第一项的左侧。

Regardless of what I set VerticalAlignment/VerticalContentAlignment to, the group header appears to the left of the first item from the group.

一组header实际上是一个ListViewHeaderItem object. By looking through theViewTree我们不会看到每个组都有一个parent容器(一个组包含一个ListViewHeaderItem和几个ListViewItems。)。所以似乎没有 parent 控制 ListViewHeaderItem 来简单地加强。但是我们可以通过精确计算设置ListViewHeaderItem的高度来进行分组项。

这里可以先用ViewTreeHelperclass获取ListViewItemAcualHeight,然后从你的群资源中获取当前群的item数绑定到XAML,现在可以计算组header的高度了。代码如下:

XAML代码

<Page.Resources>
    <CollectionViewSource x:Name="cvsActivities" IsSourceGrouped="True" />
    <CollectionViewSource
        x:Name="cvsProjects"
        IsSourceGrouped="True"
        ItemsPath="Activities" />
    <local:ListGroupStyleSelector x:Key="listGroupStyleSelector" />
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="30">
    <ListView
        x:Name="CListView"
        GroupStyleSelector="{StaticResource listGroupStyleSelector}"
        ItemContainerStyle="{StaticResource ListViewItemExpanded}"
        ItemTemplate="{StaticResource listViewItemTemplate}"
        ItemsSource="{Binding Source={StaticResource cvsActivities}}">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsStackPanel GroupHeaderPlacement="Left" Orientation="Vertical"/>
       </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</Grid>

代码隐藏

public sealed partial class MainPage : Page
{
    DateTime startDate;
    IOrderedEnumerable<IGrouping<string, Activity>> result;
    public MainPage()
    {
        this.InitializeComponent();
    }
   //Calculate the group height.
    public void calculate()
    {
        IEnumerable<ListViewHeaderItem> headeritems = FindVisualChildren<ListViewHeaderItem>(CListView);
        IEnumerable<ListViewItem> listviewitems = FindVisualChildren<ListViewItem>(CListView);
        var listviewitemheight = listviewitems.FirstOrDefault().ActualHeight;

        for (int i = 0; i < headeritems.Count(); i++)
        {
            ListViewHeaderItem headeritem = headeritems.ElementAt<ListViewHeaderItem>(i); 
            var currentgroup = result.ElementAt<IGrouping<string, Activity>>(i);
            var groupcount = currentgroup.Count();
            headeritem.Height = listviewitemheight * groupcount;
            System.Diagnostics.Debug.WriteLine(headeritem.ActualHeight);
        }  
    }
    private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        DateTime.TryParse("1/1/2014", out startDate);             
        PopulateActivities();
    }

    private void PopulateActivities()
    {
        List<Activity> Activities = new List<Activity>();

        Activities.Add(new Activity()
        {
            Name = "Activity 1",
            Complete = true,
            DueDate = startDate.AddDays(4),
            Project = "Project 1"
        });
       ...

        Activities.Add(new Activity()
        {
            Name = "Activity A",
            Complete = true,
            DueDate = startDate.AddDays(2),
            Project = "Project 2"
        });
        ...
        result = from act in Activities group act by act.Project into grp orderby grp.Key select grp;
        cvsActivities.Source = result;
    }
    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        calculate();
    }         
}

public class ListGroupStyleSelector : GroupStyleSelector
{
    protected override GroupStyle SelectGroupStyleCore(object group, uint level)
    {
        return (GroupStyle)App.Current.Resources["listViewGroupStyle"];
    }
}

public class Activity
{
    public string Name { get; set; }
    public DateTime DueDate { get; set; }
    public bool Complete { get; set; }
    public string Project { get; set; }
}

更新 HeaderContainerStyle 组样式,使布局看起来整洁。

<GroupStyle x:Key="listViewGroupStyle">
    <GroupStyle.HeaderTemplate>
        <DataTemplate>                       
                <TextBlock
                    VerticalAlignment="Center"
                    Foreground="Black"
                    Text="{Binding Key}" />                   
        </DataTemplate>
    </GroupStyle.HeaderTemplate> 
    <GroupStyle.HeaderContainerStyle>
        <Style TargetType="ListViewHeaderItem">
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
            <Setter Property="FontSize" Value="{ThemeResource ListViewHeaderItemThemeFontSize}" />
            <Setter Property="Background" Value="Azure" />
            <Setter Property="Margin" Value="0,0,0,0" />
            <Setter Property="Padding" Value="0,0,0,0" />
            <Setter Property="HorizontalContentAlignment" Value="Left" />
            <Setter Property="VerticalContentAlignment" Value="Stretch" />
            <Setter Property="MinHeight" Value="{ThemeResource ListViewHeaderItemMinHeight}" />
            <Setter Property="UseSystemFocusVisuals" Value="True" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewHeaderItem">
                        <Grid
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                            <ContentPresenter
                                x:Name="ContentPresenter"
                                Margin="0"
                                HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalContentAlignment="Stretch"
                                Content="{TemplateBinding Content}"
                                ContentTemplate="{TemplateBinding ContentTemplate}"
                                ContentTransitions="{TemplateBinding ContentTransitions}" />
                            <Rectangle
                                Height="1"
                                Margin="0,0,0,0"
                                HorizontalAlignment="Stretch"
                                VerticalAlignment="Bottom"
                                Stroke="{ThemeResource SystemControlForegroundBaseLowBrush}"
                                StrokeThickness="0.5" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </GroupStyle.HeaderContainerStyle>
</GroupStyle>

结果。