【发布时间】:2020-03-26 02:15:19
【问题描述】:
我正在创建一个动态填充选项的过滤器菜单。菜单是一个分组的 ListView。每个选项都是一个具有OptionName 和IsFiltered 属性的类,并且对应的Switch 绑定到IsFiltered 属性。我在此过滤器菜单上有三个按钮:一个用于清除所有过滤器,一个用于应用选定的过滤器,一个用于取消,用于丢弃自上次打开过滤器菜单以来发生的任何切换。请务必注意,过滤器菜单会“记住”您应用后切换的过滤器。
“清除”和“应用”按钮效果很好,但我无法实现“取消”按钮。本质上,它现在所做的是通过在触发切换时将该过滤器选项添加到内部集合来跟踪自打开菜单以来发生的所有切换。如果用户选择取消,它将遍历所有这些切换值并恢复它们。当我逐步完成时,逻辑效果很好。我遇到的问题是,如果之前已经应用了过滤器,那么当出现“过滤器菜单”页面时,会为每个“已选择”过滤器触发切换处理程序事件。这会导致将那些“已选择”过滤器添加到“新选择”列表中。在这种情况下,我想找到一种方法来抑制 Toggle 处理程序的触发。
我找到了几个解决方案,但没有一个能够工作。到目前为止最有希望的是option 3 in this answer,它设置了 Switch 的处理程序事件在出现之后,但是由于 Switch 存在于 DataTemplate 中,我无法通过名称访问它,因为可能存在无限开关数量。
还有其他在线提供的解决方案似乎对其他人来说是成功的,但没有足够的上下文让我弄清楚如何在我的场景中实施它。作为参考,我已经包含了包含 ListView 的 xaml 代码、带有任何相关代码的 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);
}
}
}
【问题讨论】:
-
您能否与我们分享一个基本演示来重现此问题,因为通过您的描述我无法完全理解该问题?另外,我同意复制过滤器列表,然后您可以通过此列表重置它。
标签: xaml xamarin xamarin.forms event-handling toggle