我在使用 ListView 分组获取要在标签中显示的列表内容时遇到问题。ListView 的 ItemsSource 和 GroupDisplayBinding 设置正确,但 ListView 中的标签不会显示任何内容(我什至尝试将其设置为文本字符串)。我的所有列表以及我的"列表列表"都正确填充。我已经倾注了文档,网站文章和教学视频,但我仍然卡住了。有人可以指出我正确的方向吗?总的来说,我在数据绑定和 MVVM 方面仍然遇到困难。谢谢。
视图:
<ListView ItemsSource="{Binding OAllLists}"
GroupDisplayBinding="{Binding Type}"
IsGroupingEnabled="true"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Items}">
</Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
视图模型:
class OrganizedViewModel
{
public ObservableCollection<Categories> OAllLists { get; set; }
public OrganizedViewModel()
{
OAllLists = new ObservableCollection<Categories>();
foreach(Categories value in Categories.AllLists)
{
OAllLists.Add(value);
}
}
}
型:
public class Categories
{
public static List<Categories> AllLists { get; set; } = new List<Categories>();
public static Categories FruitList { get; set; } = new Categories("Fruit");
public static Categories VegetableList { get; set; } = new Categories("Vegetables");
///Each type of item has its own static Categories object
public string Type { get; set; }
public List<string> Items { get; set; } = new List<string>();
}
组织项目的方法:
class OrganizeIt
{
public void OrganizeItems(List<string> groceries)
{
foreach (string value in groceries) ///Checks each value for keywords
{
if (Keywords.fruitKeys.Any(value.Contains))
{
Categories.FruitList.Items.Add(value);
}
else if (Keywords.vegetableKeys.Any(value.Contains))
{
Categories.VegetableList.Items.Add(value);
}
}
///Adds each type of list to "list of lists" if it contains values
if (Categories.FruitList.Items.Any())
{
Categories.AllLists.Add(FruitItem);
}
if (Categories.VegetableList.Items.Any())
{
Categories.AllLists.Add(Categories.VegetableList);
}
编辑
每个评论建议的新类。我还在由 GroupedList 填充的 ViewModel 中创建了另一个可观察集合(两者都正常工作)。名称更改是为了清楚起见。
public class Groceries : List<string>
{
public string Category { get; set; }
public static List<Groceries> GroupedList { get; set; } = new List<Groceries>();
public static Groceries Fruits { get; set; } = new Groceries("Fruit");
public static Groceries Vegetables { get; set; } = new Groceries("Vegetables");
public Groceries(string s)
{
Category = s;
}
}
新视图:
<ListView ItemsSource="{Binding OGroupedList}"
GroupDisplayBinding="{Binding Category}"
IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding .}"
VerticalOptions="FillAndExpand"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
编辑 2
这就是我现在在视图模型中填充可观察集合的方式:
class OrganizedViewModel
{
public ObservableCollection<Groceries> OGroupedList { get; set; }
public string Category { get; set; }
public OrganizedViewModel()
{
OGroupedList = new ObservableCollection<Groceries>();
foreach (Groceries value in Groceries.GroupedList)
{
OGroupedList.Add(value);
}
}
编辑 3
这是组织项目的方法。它接受一个字符串列表并检查每个列表项,以查看它是否包含与某个类别关联的任何关键字(例如,"苹果"包含在"2袋苹果"中)。如果是这样,则列表项将添加到相应的杂货对象中。
class OrganizeIt
{
public void OrganizeItems(List<string> groceries)
{
foreach (string value in groceries)
{
if (Keywords.fruitKeys.Any(value.Contains))
{
Groceries.Fruits.Add(value);
}
else if (Keywords.vegetableKeys.Any(value.Contains))
{
Groceries.Vegetables.Add(value);
}
}
if (Groceries.Fruits.Any())
{
Groceries.GroupedList.Add(Groceries.Fruits);
}
if (Groceries.Vegetables.Any())
{
Groceries.GroupedList.Add(Groceries.Vegetables);
}
}
这是在主页上调用该方法的地方。无组织列表是根据用户输入填充的。
private void SortItems()
{
OrganizeIt o = new OrganizeIt();
o.OrganizeItems(UnorganizedList);
}
溶液
所需要的只是将标签的绑定更改为仅{Binding}(没有句点),并删除"x:DataType"行。在下面的修订视图中,如果这对任何人有帮助:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:GroceryListMobile.ViewModels"
xmlns:mvvm="clr-namespace:MvvmHelpers;assembly=MvvmHelpers"
xmlns:model="clr-namespace:GroceryListMobile.Models"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:Class="GroceryListMobile.Views.OrganizedView"
x:Name="Organized">
<ContentPage.BindingContext>
<viewmodels:OrganizedViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<ListView ItemsSource="{Binding OGroupedList}"
GroupDisplayBinding="{Binding Category}"
IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding}"
VerticalOptions="FillAndExpand"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
你需要一个<ViewCell>
作为<DataTemplate>
的子节点:
<ListView ItemsSource="{Binding OAllLists}"
GroupDisplayBinding="{Binding Type}"
IsGroupingEnabled="true"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding .}">
</Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ListView.ItemTemplate 始终需要一个 DataTemplate,它是一个单元格。
编辑接下来要解决的是用作 ItemSource 的集合。使用分组时,这需要是集合的集合。我会尝试更改您的模型类:
public class Categories : List<string>
{
public static List<Categories> AllLists { get; set; } = new List<Categories>();
public static Categories FruitList { get; set; } = new Categories("Fruit");
public static Categories VegetableList { get; set; } = new Categories("Vegetables");
///Each type of item has its own static Categories object
public string Type { get; set; }
}
并查看上面 Xaml 中修订后的绑定。
考虑分组列表视图的一种方法是,它是一个列表列表。 "外部"列表元素具有绑定到 GroupDisplayBinding 的成员,"内部"列表元素具有绑定到 DataTemplate 中的元素的成员。
在您的情况下,"外部"集合是 ObservableCollection,因此 GroupDisplayBinding 将绑定到类别上的某些内容。 然后,每个类别本身都需要是一个集合。 在修订版中,这是一个列表,因此 DataTemplate 被赋予一个字符串作为 BindingContext。 所以标签只需要绑定到字符串(因此Binding .
.
代码的其余部分必须稍作调整,因为曾经是类别成员的 Items 集合现在是类别对象本身(通过继承)。
编辑 2
我创建了一个新应用程序,其中包含的页面与您拥有的 ListView 完全相同(第一次编辑下的"新建视图"),以及与第一次编辑下的完全相同的杂货类。
我稍微修改了一下OrganizedViewModel。它似乎没有使用类别,我想确保 OGroupedList 填充了类别:
class OrganizedViewModel
{
public ObservableCollection<Groceries> OGroupedList { get; set; }
public OrganizedViewModel()
{
OGroupedList = new ObservableCollection<Groceries>();
OGroupedList.Add(Groceries.Fruits);
OGroupedList.Add(Groceries.Vegetables);
}
}
最后,我在创建页面时向页面构造函数中的每个类别添加了一些项:
public Page1()
{
InitializeComponent();
var bc = new OrganizedViewModel();
var index = 1;
foreach (var g in bc.OGroupedList)
{
g.Add(g.Category + $" {index++}");
g.Add(g.Category + $" {index++}");
g.Add(g.Category + $" {index++}");
g.Add(g.Category + $" {index++}");
}
BindingContext = bc;
}
对我来说,这是正确显示带有项目名称和组标题的列表。 因此,无论您仍然看到的问题是什么,都在其他地方。 分组列表视图的基本类结构和 Xaml 定义现在是正确的。
我的两个猜测:
- 确保正确填充集合。
- 尝试更改为
public class Groceries : ObservableCollection<string>
。如果杂货列表在页面最初呈现后可以更改,这一点很重要。
编辑 3
弄到它的底部。以下是应该让您继续前进的评论:
{Binding .}
和{Binding}
之间存在细微差异。在您的情况下,{Binding}
有效,但{Binding .}
无效。更常见的情况是元素是对象,而不是字符串,所以这样的事情也可以解决它:
public class GroceryItem
{
public string Name { get; set; }
}
...
public class Groceries: ObservableCollection<GroceryItem>
{
...
当然,这将需要更改添加到杂货系列中,并且需要Text="{Binding Name}"
标签。
当我尝试#2时,Visual Studio在进行该更改后导致
x:DataType
出现问题。它在 IDE 中对绑定上下文的检测不是最好的,所以我不得不删除该行。在此处使用静态集合时要小心。如果添加项目、组织、返回并再次组织,应用将崩溃,因为它尝试重新添加水果和蔬菜集合。
根据您的代码,要显示 OAllLists,您可以创建如下所示的 OAllLists:
OAllLists = new ObservableCollection<Categories>
{
new Categories("FruitList"){"aaa","bbb","ccc},
new Categories("VegetableList"){"ddd","eee"}
};
其中,"FruitList"是Categories类中的类型,"aaa"是你在其中添加的字符串数组。您可以查看此链接以获取详细信息 (https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-list-appearance#grouping)