【发布时间】:2020-03-15 01:26:12
【问题描述】:
我正在尝试使用启用分组的 ListView 创建一个简单的过滤器菜单。目前我正在通过从父页面生成一个模式页面来做到这一点,该页面传递了一个我需要填充菜单的对象,其中包含一些按钮和列表页面。然而,我什至无法让最简单的分组 ListView 出现。我已经按照教程here 到达了我所在的位置。
我将包含 XAML、代码隐藏和过滤器页面的 ViewModel,以及教程中描述的过滤器组和过滤器选项的模型。请注意,虽然页面在我的代码中传递了一个对象,但我还没有以任何方式使用它来发布我在这里发布的内容。
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="MyProject.Views.FilterMenu">
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Text="Close"
Grid.Column="0"
Grid.Row="0"
HorizontalOptions="FillAndExpand"
Clicked="CloseButton_OnClicked"/>
<Button Text="Clear Filter"
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="FillAndExpand"
Clicked="ClearButton_OnClicked"/>
<Label Text="Filter By"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
HorizontalTextAlignment="Start"/>
<StackLayout Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2">
<ListView ItemsSource="{Binding FilterOptionList}"
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Name}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}"></TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
<Button
Text="Apply Filter"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="3"
Clicked="ApplyFilterButton_OnClicked"/>
</Grid>
</ContentPage.Content>
</ContentPage>
代码背后
using System;
using MyProject.Models;
using MyProject.ViewModels;
using MvvmHelpers;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyProject.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FilterMenu : ContentPage
{
public FilterMenu(ObservableRangeCollection<Unit> units)
{
InitializeComponent();
BindingContext = new FilterMenuViewModel(Navigation, units);
}
private void CloseButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.Close();
}
private void ClearButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.ClearFilter();
}
private void ApplyFilterButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.ApplyFilter();
}
}
}
视图模型
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using MyProject.Annotations;
using MyProject.Models;
using Microsoft.Extensions.Options;
using Xamarin.Forms;
namespace MyProject.ViewModels
{
public class FilterMenuViewModel : INotifyPropertyChanged
{
public ObservableCollection<Unit> Units { get; private set; }
public ObservableCollection<FilterOptionGroup> FilterOptionList = new ObservableCollection<FilterOptionGroup>();
private readonly INavigation _navigation;
public event PropertyChangedEventHandler PropertyChanged;
public FilterMenuViewModel(INavigation navigation, ObservableCollection<Unit> units )
{
_navigation = navigation;
this.Units = units;
PopulateCategories();
FilterOptionList.Add(new FilterOptionGroup("Group One", new []
{
new FilterOption
{
Name = "Option One", IsFiltered = false
},
new FilterOption
{
Name = "Option One", IsFiltered = false
}
}));
FilterOptionList.Add(new FilterOptionGroup("Group Two", new[]
{
new FilterOption
{
Name = "Option One", IsFiltered = false
},
new FilterOption
{
Name = "Option Two", IsFiltered = false
},
new FilterOption
{
Name = "Option Three", IsFiltered = false
}
}));
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public async void Close()
{
await _navigation.PopModalAsync();
}
public void ClearFilter()
{
Debug.WriteLine("Clear Filter Clicked.");
}
public void ApplyFilter()
{
Debug.WriteLine("Apply Filter Clicked.");
}
}
}
过滤选项 GROUP 集合
using System.Collections.ObjectModel;
using System.Text;
namespace MyProject.Models
{
public class FilterOptionGroup : ObservableCollection<FilterOption>
{
public string Name { get; private set; }
public FilterOptionGroup(string name)
: base()
{
Name = name;
}
public FilterOptionGroup(string name, IEnumerable<FilterOption> source)
: base(source)
{
Name = name;
}
}
}
过滤选项类
using System;
using System.Collections.Generic;
using System.Text;
namespace DormRemote.Models
{
public class FilterOption
{
private string _name;
private bool _isFiltered;
public string Name
{
get { return _name; }
set { _name = value; }
}
public bool IsFiltered
{
get => _isFiltered;
set => _isFiltered = value;
}
}
}
据我所知,我的绑定设置正确,因为我的按钮打印了相应的调试文本,如果我用一个简单的 ListView 替换当前的 ListView 而没有启用分组,并将它绑定到一个简单的 List 它会正确显示。
此外,我已经测试了 FilterOptionList 的填充是否正确,因为我已使用调试代码打印出每个组的内容。
我不确定我是否只是遗漏了一些东西,或者本教程中的实现是否不起作用。任何帮助将不胜感激。
【问题讨论】:
-
首先,您将绑定到
FilterOptionList,这不是您的 VM 的公共属性。您只能绑定到公共属性 -
我很困惑。 FilterOptionList 在顶部声明为公共 ObservableCollection
。我误会你了吗? -
您能否澄清您所指的本文档中的内容?据我所知,我的 ItemsSource 列表是公开的,并且它们的所有内部属性都是公开的
-
在他的教程
PhonesList有一个get;并设置;
标签: c# listview xamarin xamarin.forms