Xamarin 窗体列表视图分组内容不绑定



我在使用 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 定义现在是正确的。

我的两个猜测:

  1. 确保正确填充集合。
  2. 尝试更改为public class Groceries : ObservableCollection<string>。如果杂货列表在页面最初呈现后可以更改,这一点很重要。

编辑 3

弄到它的底部。以下是应该让您继续前进的评论:

  1. {Binding .}{Binding}之间存在细微差异。在您的情况下,{Binding}有效,但{Binding .}无效。

  2. 更常见的情况是元素是对象,而不是字符串,所以这样的事情也可以解决它:

public class GroceryItem
{
public string Name { get; set; }
}
...
public class Groceries: ObservableCollection<GroceryItem>
{
...

当然,这将需要更改添加到杂货系列中,并且需要Text="{Binding Name}"标签。

  1. 当我尝试#2时,Visual Studio在进行该更改后导致x:DataType出现问题。它在 IDE 中对绑定上下文的检测不是最好的,所以我不得不删除该行。

  2. 在此处使用静态集合时要小心。如果添加项目、组织、返回并再次组织,应用将崩溃,因为它尝试重新添加水果和蔬菜集合。

根据您的代码,要显示 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)

最新更新