Я пытаюсь создать простое меню фильтра, используя ListView с включенной группировкой. В настоящее время я делаю это, генерируя модальную страницу из родительской страницы, которой передается объект, который мне нужен для заполнения меню, и который содержит несколько кнопок плюс страницу списка. Я не могу получить даже простейшую группировку ListView. Я следовал учебнику здесь , чтобы добраться туда, где я нахожусь.
Я включу XAML, codebehind и 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();
}
}
}
ViewModel
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
заполняется правильно, так как я распечатал содержимое каждого из его групп, использующих код отладки.
Я не уверен, что я что-то упускаю или реализация из этого урока просто не работает. Любая помощь будет оценена.