Я создаю меню фильтра, которое динамически заполняется параметрами. Меню представляет собой сгруппированный ListView. Каждый параметр является классом со свойством OptionName
и IsFiltered
, и соответствующий Switch связан со свойством IsFiltered
. У меня есть три кнопки в этом меню фильтров: одна для очистки всех фильтров, одна для применения выбранных фильтров и одна для отмены, которая предназначена для отмены любых переключений, которые произошли с момента последнего открытия меню фильтров. Важно отметить, что меню фильтров «запоминает», какие фильтры переключаются после применения.
Кнопки «Очистить» и «Применить» работают отлично, но у меня возникают проблемы при реализации кнопки «Отмена». По сути, теперь он отслеживает все переключения, которые произошли с момента открытия меню, путем добавления этого параметра фильтра во внутреннюю коллекцию, когда даже срабатывает переключатель. Если пользователь выбирает Отмена, он перебирает все эти значения переключателя и возвращает их. Логика c прекрасно работает, когда я прохожу. У меня проблема в том, что если есть фильтры, которые были применены ранее, событие Toggle Handler вызывается для каждого из этих «уже выбранных» фильтров, когда появляется страница меню фильтров. Это приводит к тому, что эти «уже выбранные» фильтры добавляются в список «вновь выбранных». Я хотел бы найти способ подавить запуск обработчика Toggle в этом случае.
Я нашел несколько решений, но не смог заставить их работать. Самым многообещающим до сих пор был вариант 3 в этом ответе , который устанавливает событие обработчика Коммутатора после появления , но, поскольку Коммутатор живет в DataTemplate, я не могу получить к нему доступ по имени , поскольку число переключателей может быть бесконечным.
В сети есть и другие решения, которые кажутся успешными для других, но у меня недостаточно контекста, чтобы понять, как реализовать их в моем сценарии. , Для справки я включил содержащий xaml-код ListView, код для страницы xaml с любым соответствующим кодом, а также модель ViewModel с любым соответствующим кодом.
Соответствующий код приведен ниже:
ListView XAML
<ListView ItemsSource="{Binding FilterOptionList}"
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Name}"
HasUnevenRows="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="25">
<StackLayout Padding="3, 20, 3, 2">
<Label Text="{Binding Name}"
FontSize="Small"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="15, 0, 40, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding OptionName}"
FontSize="Micro"
Grid.Column="1"/>
<Switch x:Name="filterSwitch"
IsToggled="{Binding IsFiltered, Mode=TwoWay}"
Toggled="Switch_OnToggled"
Grid.Column="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Код сзади
namespace MyProject.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FilterMenu : ContentPage
{
public FilterMenu(ObservableRangeCollection<MyObject> myObjects, ObservableCollection<FilterOptionGroup> filterOptionList)
{
InitializeComponent();
BindingContext = new FilterMenuViewModel(Navigation, myObjects, filterOptionList);
}
private void CloseButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.Cancel();
}
private void ClearButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.ClearFilter();
}
private void ApplyFilterButton_OnClicked(object sender, EventArgs e)
{
(BindingContext as FilterMenuViewModel)?.ApplyFilter();
}
private void Switch_OnToggled(object sender, ToggledEventArgs e)
{
FilterOption filterOption = (sender as Switch).Parent.BindingContext as FilterOption;
(BindingContext as FilterMenuViewModel)?.ToggleFilter(sender, e, filterOption);
}
}
}
Фильтр Меню Вид Модель
public class FilterMenuViewModel : INotifyPropertyChanged
{
public ObservableCollection<MyObject> MyObjects { get; private set; }
private readonly INavigation _navigation;
public event PropertyChangedEventHandler PropertyChanged;
List<FilterOption> newlyCheckedFilters = new List<FilterOption>();
public ObservableCollection<FilterOptionGroup> FilterOptionList { get; set; } = new ObservableCollection<FilterOptionGroup>() ;
public FilterMenuViewModel(INavigation navigation, ObservableCollection<MyObject> myObjects, ObservableCollection<FilterOptionGroup> filterOptionList )
{
_navigation = navigation;
this.MyObjects = myObjects;
FilterOptionList = filterOptionList;
PopulateCategories();
}
private void PopulateFilter(string name, List<string> newOptions)
{
// Code to create the Filter Options list...
}
private void PopulateCategories()
{
// Code to create the Filter Options list...
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public async void Cancel()
{
foreach (var filterOption in newlyCheckedFilters)
{
filterOption.IsFiltered = !filterOption.IsFiltered;
}
await _navigation.PopModalAsync();
}
public void ClearFilter()
{
foreach (var group in FilterOptionList)
{
foreach (var option in group)
{
option.IsFiltered = false;
}
}
}
public async void ApplyFilter()
{
await _navigation.PopModalAsync();
}
public void ToggleFilter(object sender, ToggledEventArgs toggledEventArgs, FilterOption filterOption)
{
newlyCheckedFilters.Add(filterOption);
}
}
}