Xamarin Listview 分组
Xamarin Listview grouping
我正在处理 xamarin.froms 中的列表视图。我可以轻松地为每条记录用一个列表项填充列表视图:
[
{"cat":1, "name":"alpha"},
{"cat":1, "name":"beta"},
{"cat":1, "name":"gamma"},
{"cat":2, "name":"john"},
{"cat":2, "name":"william"},
{"cat":2, "name":"smith"},
{"cat":2, "name":"steve"},
{"cat":3, "name":"abc"},
{"cat":3, "name":"xyz"}
]
//来自此 json 来源的列表视图中的 9 个项目
但我想要的是根据某个键值对所有项目进行分组,在这里说 "cat"
并实现如下目标:
如有任何建议或方法,我们将不胜感激。
Xamarin.Forms ListView 支持分组。请查看他们的文档 http://developer.xamarin.com/guides/cross-platform/xamarin-forms/user-interface/listview/customizing-list-appearance/#Grouping 了解如何使用它。
将您的数据分组到 collections 并将这些 collections 添加到您的 ListView 中。 collections 需要是你自己的 class 和 属性 用于绑定组。
这是一个演练:
在您的 ListView 上设置分组,包括 属性 以将每个组绑定到,在本例中为 "GroupKey"
myListView.IsGroupingEnabled = true;
myListView.GroupDisplayBinding = new Binding("GroupKey"); // See below
然后将您的数据分组(例如列表列表)。这通常意味着您需要创建自己的 class 来显示您的分组,例如:
public class Grouping<K, T> : ObservableCollection<T>
{
// NB: This is the GroupDisplayBinding above for displaying the header
public K GroupKey { get; private set; }
public Grouping(K key, IEnumerable<T> items)ac
{
GroupKey = key;
foreach (var item in items)
this.Items.Add(item);
}
}
最后,分组添加您的数据:
var groups = new ObservableCollection<Grouping<string, MyDataClass>>();
// You can just pass a set of data in (where "GroupA" is an enumerable set)
groups.Add(new Grouping<string, MyDataClass>("GroupA", GroupA));
// Or filter down a set of data
groups.Add(new Grouping<string, MyDataClass>("GroupB",
MyItems.Where(a => a.SomeFilter())));
myListView.ItemSource = groups;
像以前一样将单元格绑定到 MyDataClass:
var cell = new DataTemplate(typeof(TextCell));
cell.SetBinding(TextCell.TextProperty, "SomePropertyFromMyDataClass");
cell.SetBinding(TextCell.DetailProperty, "OtherPropertyFromMyDataClass");
myListView.ItemTemplate = cell;
查看它以了解为什么在 Grouping
class 中使用模板 K
而不是字符串,如何自定义 header 外观等等更多:
http://motzcod.es/post/94643411707/enhancing-xamarinforms-listview-with-grouping
(归功于@pnavk 回答中的 link)
在我的环境中,代码在此 url http://motzcod.es/post/94643411707/enhancing-xamarinforms-listview-with-grouping 中不起作用。
无效的代码在这里
var partnersSorted = from item in Partners
orderby item.UserName
group item by item.UserNameSort into PartnersGroup
select new Grouping<string, Monkey>(PartnersGroup.Key, PartnersGroup);
MonkeysGrouped = new ObservableCollection<Grouping<string, Monkey>>(partnersSorted);
所以我更改了代码。
var sortedPartners = Partners.OrderBy(x => x.UserName).GroupBy(y => y.UserNameSort);
foreach (var item in sortedPartners)
{
PartnersGrouped.Add(new PartnersGrouping<string, Item>(item.Key, Partners.Where(x=>x.UserNameSort == item.Key)));
}
你可以这样看。
[https://i.stack.imgur.com/BswPq.png][1]
这是我所有的脚本
项目是合作伙伴
Item.cs
using System;
namespace NewHeats.Models
{
public class Item
{
public string Id
{
get;
set;
}
public string UserName
{
get;
set;
}
public DateTime RegisterDate
{
get;
set;
}
public string Field
{
get;
set;
}
public string Password
{
get;
set;
}
public int Heats
{
get;
set;
}
public string UserNameSort
{
get
{
if (string.IsNullOrWhiteSpace(UserName) || UserName.Length == 0)
return "?";
return UserName[0].ToString().ToUpper();
}
}
}
}
PartnersGrouping.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace NewHeats.Models
{
public class PartnersGrouping<K,T> : ObservableCollection<T>
{
public K Key { get; private set; }
public PartnersGrouping(K key,IEnumerable<T> items)
{
Key = key;
foreach (var item in items)
{
this.Items.Add(item);
}
}
}
}
PartnersViewModel.cs
using System;
using System.Windows.Input;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using NewHeats.Models;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Linq;
using System.Diagnostics.Contracts;
namespace NewHeats.ViewModels
{
public class PartnersViewModel : BaseViewModel
{
public Item Me
{
get;
set;
}
public ObservableCollection<Item> Partners { get; set; }
public ObservableCollection<PartnersGrouping<string, Item>> PartnersGrouped { get; set; }
public Item SelectedPartner { get; set; }
public Command LoadPartnersCommand { get; set; }
public PartnersViewModel()
{
Title = "Partners";
Partners = new ObservableCollection<Item>();
PartnersGrouped = new ObservableCollection<PartnersGrouping<string, Item>>();
LoadPartnersCommand = new Command(async() =>await ExecuteLoadPartnersCommand());
}
async Task ExecuteLoadPartnersCommand()
{
Contract.Ensures(Contract.Result<Task>() != null);
if (IsBusy)
return;
IsBusy = true;
try
{
Me = await MockUsrDataStore.GetItemAsync("naoto");
Partners.Clear();
var allfriends = await MockFriDataStore.GetItemsAsync(true);
var myFriends = allfriends.Where(x => x.MyId == Me.Id);
var allUsers = await MockUsrDataStore.GetItemsAsync(true);
foreach (var item in myFriends)
{
var partner = allUsers.FirstOrDefault(x => x.Id == item.FriendId);
if (partner!=null)
{
Partners.Add(partner);
}
}
var sortedpartners = Partners.OrderBy(x => x.UserName).GroupBy(y => y.UserNameSort);
foreach (var item in sortedpartners)
{
PartnersGrouped.Add(new PartnersGrouping<string, Item>(item.Key, Partners.Where(x=>x.UserNameSort == item.Key)));
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}
PartnerPage.xaml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="NewHeats.Views.PartnersPage" xmlns:vm="clr-namespace:NewHeats.ViewModels" xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin" Title="{Binding Title}">
<ContentPage.Resources>
<ResourceDictionary>
<!--Page Level Resources: Compatibile with Xamarin Live Player -->
<Color x:Key="Primary">#2196F3</Color>
<Color x:Key="Accent">#96d1ff</Color>
<Color x:Key="LightTextColor">#999999</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollView Grid.Row="0">
<StackLayout Orientation="Vertical" Padding="16,40,16,40" Spacing="10">
<ListView ItemsSource="{Binding PartnersGrouped}"
HasUnevenRows="true"
VerticalOptions="FillAndExpand"
IsPullToRefreshEnabled="true"
CachingStrategy="RecycleElement"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
RefreshCommand="{Binding LoadPartnersCommand}"
ItemSelected="Handle_ItemSelected"
SelectedItem="{Binding SelectedPartner}"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="true"
GroupShortNameBinding="{Binding Key}">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="25">
<StackLayout VerticalOptions="FillAndExpand"
Padding="5"
BackgroundColor="#3498DB">
<Label Text="{Binding Key}" TextColor="White" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<controls:CircleImage Source="husky.jpg"
Aspect="AspectFill"
Grid.Column="0"
Grid.Row="0"
WidthRequest="60"
HeightRequest="60">
</controls:CircleImage>
<StackLayout Orientation="Vertical" Grid.Column="1">
<Label Text="{Binding UserName}" VerticalTextAlignment="Center"/>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ScrollView>
</Grid>
</ContentPage>
谢谢!!
我正在处理 xamarin.froms 中的列表视图。我可以轻松地为每条记录用一个列表项填充列表视图:
[
{"cat":1, "name":"alpha"},
{"cat":1, "name":"beta"},
{"cat":1, "name":"gamma"},
{"cat":2, "name":"john"},
{"cat":2, "name":"william"},
{"cat":2, "name":"smith"},
{"cat":2, "name":"steve"},
{"cat":3, "name":"abc"},
{"cat":3, "name":"xyz"}
]
//来自此 json 来源的列表视图中的 9 个项目
但我想要的是根据某个键值对所有项目进行分组,在这里说 "cat"
并实现如下目标:
如有任何建议或方法,我们将不胜感激。
Xamarin.Forms ListView 支持分组。请查看他们的文档 http://developer.xamarin.com/guides/cross-platform/xamarin-forms/user-interface/listview/customizing-list-appearance/#Grouping 了解如何使用它。
将您的数据分组到 collections 并将这些 collections 添加到您的 ListView 中。 collections 需要是你自己的 class 和 属性 用于绑定组。
这是一个演练:
在您的 ListView 上设置分组,包括 属性 以将每个组绑定到,在本例中为 "GroupKey"
myListView.IsGroupingEnabled = true;
myListView.GroupDisplayBinding = new Binding("GroupKey"); // See below
然后将您的数据分组(例如列表列表)。这通常意味着您需要创建自己的 class 来显示您的分组,例如:
public class Grouping<K, T> : ObservableCollection<T>
{
// NB: This is the GroupDisplayBinding above for displaying the header
public K GroupKey { get; private set; }
public Grouping(K key, IEnumerable<T> items)ac
{
GroupKey = key;
foreach (var item in items)
this.Items.Add(item);
}
}
最后,分组添加您的数据:
var groups = new ObservableCollection<Grouping<string, MyDataClass>>();
// You can just pass a set of data in (where "GroupA" is an enumerable set)
groups.Add(new Grouping<string, MyDataClass>("GroupA", GroupA));
// Or filter down a set of data
groups.Add(new Grouping<string, MyDataClass>("GroupB",
MyItems.Where(a => a.SomeFilter())));
myListView.ItemSource = groups;
像以前一样将单元格绑定到 MyDataClass:
var cell = new DataTemplate(typeof(TextCell));
cell.SetBinding(TextCell.TextProperty, "SomePropertyFromMyDataClass");
cell.SetBinding(TextCell.DetailProperty, "OtherPropertyFromMyDataClass");
myListView.ItemTemplate = cell;
查看它以了解为什么在 Grouping
class 中使用模板 K
而不是字符串,如何自定义 header 外观等等更多:
http://motzcod.es/post/94643411707/enhancing-xamarinforms-listview-with-grouping
(归功于@pnavk 回答中的 link)
在我的环境中,代码在此 url http://motzcod.es/post/94643411707/enhancing-xamarinforms-listview-with-grouping 中不起作用。
无效的代码在这里
var partnersSorted = from item in Partners
orderby item.UserName
group item by item.UserNameSort into PartnersGroup
select new Grouping<string, Monkey>(PartnersGroup.Key, PartnersGroup);
MonkeysGrouped = new ObservableCollection<Grouping<string, Monkey>>(partnersSorted);
所以我更改了代码。
var sortedPartners = Partners.OrderBy(x => x.UserName).GroupBy(y => y.UserNameSort);
foreach (var item in sortedPartners)
{
PartnersGrouped.Add(new PartnersGrouping<string, Item>(item.Key, Partners.Where(x=>x.UserNameSort == item.Key)));
}
你可以这样看。
[https://i.stack.imgur.com/BswPq.png][1]
这是我所有的脚本
项目是合作伙伴
Item.cs
using System;
namespace NewHeats.Models
{
public class Item
{
public string Id
{
get;
set;
}
public string UserName
{
get;
set;
}
public DateTime RegisterDate
{
get;
set;
}
public string Field
{
get;
set;
}
public string Password
{
get;
set;
}
public int Heats
{
get;
set;
}
public string UserNameSort
{
get
{
if (string.IsNullOrWhiteSpace(UserName) || UserName.Length == 0)
return "?";
return UserName[0].ToString().ToUpper();
}
}
}
}
PartnersGrouping.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace NewHeats.Models
{
public class PartnersGrouping<K,T> : ObservableCollection<T>
{
public K Key { get; private set; }
public PartnersGrouping(K key,IEnumerable<T> items)
{
Key = key;
foreach (var item in items)
{
this.Items.Add(item);
}
}
}
}
PartnersViewModel.cs
using System;
using System.Windows.Input;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using NewHeats.Models;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Linq;
using System.Diagnostics.Contracts;
namespace NewHeats.ViewModels
{
public class PartnersViewModel : BaseViewModel
{
public Item Me
{
get;
set;
}
public ObservableCollection<Item> Partners { get; set; }
public ObservableCollection<PartnersGrouping<string, Item>> PartnersGrouped { get; set; }
public Item SelectedPartner { get; set; }
public Command LoadPartnersCommand { get; set; }
public PartnersViewModel()
{
Title = "Partners";
Partners = new ObservableCollection<Item>();
PartnersGrouped = new ObservableCollection<PartnersGrouping<string, Item>>();
LoadPartnersCommand = new Command(async() =>await ExecuteLoadPartnersCommand());
}
async Task ExecuteLoadPartnersCommand()
{
Contract.Ensures(Contract.Result<Task>() != null);
if (IsBusy)
return;
IsBusy = true;
try
{
Me = await MockUsrDataStore.GetItemAsync("naoto");
Partners.Clear();
var allfriends = await MockFriDataStore.GetItemsAsync(true);
var myFriends = allfriends.Where(x => x.MyId == Me.Id);
var allUsers = await MockUsrDataStore.GetItemsAsync(true);
foreach (var item in myFriends)
{
var partner = allUsers.FirstOrDefault(x => x.Id == item.FriendId);
if (partner!=null)
{
Partners.Add(partner);
}
}
var sortedpartners = Partners.OrderBy(x => x.UserName).GroupBy(y => y.UserNameSort);
foreach (var item in sortedpartners)
{
PartnersGrouped.Add(new PartnersGrouping<string, Item>(item.Key, Partners.Where(x=>x.UserNameSort == item.Key)));
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}
PartnerPage.xaml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="NewHeats.Views.PartnersPage" xmlns:vm="clr-namespace:NewHeats.ViewModels" xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin" Title="{Binding Title}">
<ContentPage.Resources>
<ResourceDictionary>
<!--Page Level Resources: Compatibile with Xamarin Live Player -->
<Color x:Key="Primary">#2196F3</Color>
<Color x:Key="Accent">#96d1ff</Color>
<Color x:Key="LightTextColor">#999999</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollView Grid.Row="0">
<StackLayout Orientation="Vertical" Padding="16,40,16,40" Spacing="10">
<ListView ItemsSource="{Binding PartnersGrouped}"
HasUnevenRows="true"
VerticalOptions="FillAndExpand"
IsPullToRefreshEnabled="true"
CachingStrategy="RecycleElement"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
RefreshCommand="{Binding LoadPartnersCommand}"
ItemSelected="Handle_ItemSelected"
SelectedItem="{Binding SelectedPartner}"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="true"
GroupShortNameBinding="{Binding Key}">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="25">
<StackLayout VerticalOptions="FillAndExpand"
Padding="5"
BackgroundColor="#3498DB">
<Label Text="{Binding Key}" TextColor="White" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<controls:CircleImage Source="husky.jpg"
Aspect="AspectFill"
Grid.Column="0"
Grid.Row="0"
WidthRequest="60"
HeightRequest="60">
</controls:CircleImage>
<StackLayout Orientation="Vertical" Grid.Column="1">
<Label Text="{Binding UserName}" VerticalTextAlignment="Center"/>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ScrollView>
</Grid>
</ContentPage>
谢谢!!