天天看點

分組視圖

當資料項數量較大的時候,為了讓使用者能夠快速找到要檢視的項,應該對資料進行分組。ItemsControl控件公開GroupStyle屬性,用來設定分組視圖的樣式,它是一個GroupStyle對象清單,清單中的每個GroupStyle對象代表一個層次的分組。如果清單中隻有一個GroupStyle對象,則表示分組視圖隻呈現頂層分組;如果清單中有兩個GroupStyle對象,則分組視圖将呈現兩個層次的分組。一般來說,隻需要一層分組就可以了,分組層次過多會導緻應用程式界面混亂,對使用者體驗造成負面影響。

GroupStyle所設定的分組樣式的目标類型為GroupItem,GroupItem是内容控件,派生自ContentControl,作用是在集合控件中顯示分組視圖,每個GroupItem執行個體将呈現一個組的資料。有關GroupStyle類的各個屬性的詳細資訊參考如下:

  • HeaderTemplate 定義用于顯示分組标頭内容的資料模闆,即如何顯示每個分組的組标題
  • HeaderContainerStyle 定義組标頭的容器控件的樣式
  • ContainerStyle 定義GroupItem控件的樣式
  • Panel 指定一個面闆,用于排列每個分組視圖

要實作分組視圖,還需用到ColelctionViewSource類,該類可以對資料集合進行管理,尤其是支援資料分組,通過Source屬性來引用原始資料清單。如果原始的資料清單已經進行過分組,應當将IsSourceGrouped屬性設定為true。通常,原始資料可以使用Linq技術進行分組,并把分組結果指派給Source屬性。

CollectionViewSource類的View屬性将傳回一個實作了ICollectionView接口的對象執行個體,但該實作類并沒有對外公開,開發者無法在代碼中通路它,不過可以使用ICollectionView接口來通路。當資料視圖分組後,IColelctionView的CollectionGroups将傳回一個對象清單,其中每個對象表示一個分組的視圖對象,該對象的類型實作了ICollectionViewGroup接口。同理,ICollectionViewGroup接口的實作類也沒有對外公開,開發者隻能通過ICollectionViewGroup接口來通路該對象。

ICollectionViewGroup接口的Group屬性就是資料的分組依據,假設資料是按首字母進行分組的,那麼Group屬性的值就是辨別該分組的單個字母。GroupItems屬性傳回的是屬于該分組的資料項清單。

接下來将通過一個示例來示範資料視圖分組功能。

本例假設有一個資料清單,表示一系列新聞紀錄,并将資料清單按新聞分類進行分組(如社會新聞、經濟新聞等),最終呈現資料的分組視圖。每一條新聞記錄将使用News類來分裝,News類定義如下:

class News
    {
        ///<summary>
        ///分類
        ///</summary>
        public string Category { get; set; }
        ///<summary>
        ///标題
        ///</summary>
        public string Title { get; set; }
        ///<summary>
        ///釋出日期
        ///</summary>
        public DateTime PublishDate { get; set; }
        ///<summary>
        ///内容
        ///</summary>
        public string Content { get; set; }
    }
           

随後在頁面的資源中聲明一個CollectionViewSource執行個體,稍後ListView控件将綁定到該CollectionViewSource執行個體。

<Page.Resources>
        <CollectionViewSource x:Key="cvs" x:Name="cvs" IsSourceGrouped="True"/>
    </Page.Resources>
           

為資源對象設定x:Key名稱是為了友善在XAML文檔的其他位置進行引用,而設定x:Name值是為了随後能夠在代碼中通路該CollectionViewSource執行個體。

在使用者界面上聲明ListView執行個體,并自定義它的子項目資料模闆,以及用于呈現分組視圖的GroupStyle。XAML代碼如下:

<Grid>
        <ListView SelectionMode="None" ItemsSource="{Binding Source={StaticResource cvs}}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,5">
                        <TextBlock FontWeight="Bold" FontSize="24" Text="{Binding Path=Title}"/>
                        <TextBlock Text="{Binding Path=Content}" FontSize="20"/>
                        <TextBlock Opacity="0.85">
                            釋出日期: 
                            <Run Text="{Binding Path=PublishDate}"/>
                        </TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock FontSize="32" FontWeight="Bold" Text="{Binding Path=Key}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.HeaderContainerStyle>
                        <Style TargetType="ListViewHeaderItem">
                            <Setter Property="Background" Value="Red"/>
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="Padding" Value="2,5"/>
                        </Style>
                    </GroupStyle.HeaderContainerStyle>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
    </Grid>
           

ListView控件的ItemsSource屬性引用資源中的CollectionViewSource執行個體,這樣就可以讓ListView控件以該CollectionViewSource執行個體為資料源。

GroupStyley用于設定分組視圖項的樣式,在本例中,通過HeadCotainerStyle屬性設定用于顯示分組标頭區域的控件的樣式,以及通過HeadTemplate屬性來定義分組标頭的内容模闆。

切換到代碼視圖,在頁面類的構造方法中,為CollectionViewSource對象提供一些示例資料:

public MainPage()
        {
            this.InitializeComponent();
            List<News> newsList = new List<News>();
            for (int i = 0; i <=4; i++)
            {
                newsList.Add(new News { 
                    Category="社會",
                    Title="示例新聞"+i.ToString(),
                    Content="測試新聞内容"+i.ToString(),
                    PublishDate=DateTime.Now.AddDays(i)
                    });
            }
            for (int i = 0; i <=4; i++)
            {
                newsList.Add(new News
                {
                    Category = "娛樂",
                    Title = "示例新聞" + i.ToString(),
                    Content = "測試新聞内容" + i.ToString(),
                    PublishDate = DateTime.Now.AddDays(i)
                });
            }
            for (int i = 0; i <= 4; i++)
            {
                newsList.Add(new News
                {
                    Category = "法則",
                    Title = "示例新聞" + i.ToString(),
                    Content = "測試新聞内容" + i.ToString(),
                    PublishDate = DateTime.Now.AddDays(i)
                });
            }
            //對資料進行分組
            var groups = from n in newsList
                         group n by n.Category;
            //設定資料源
            cvs.Source = groups;
        }
           

上面代碼中,使用以下Linq語句将示例資料進行分組:

var groups = from n in newsList
                         group n by n.Category;
           

分組的依據是News對象的Category屬性。在資料分組後,Linq語句的查詢結果為IGrouping<TKey,TElement>類型清單,表示已分組的一組資料清單,其中Key屬性表示該分組的依據項(即組标題)。是以前面在XAML中定義GroupStyle的組标頭資料模闆時,裡面的TextBlock控件的Text屬性所綁定的就是IGrouping<TKey,TElement>對象的Key屬性,以顯示分組的組标題。

<TextBlock FontSize="32" FontWeight="Bold" Text="{Binding Path=Key}"/>
           

運作應用程式,會看到如下圖所示的結果。

分組視圖