Как предотвратить запуск обработчика OnToggled в ячейке представления? - PullRequest
0 голосов
/ 25 марта 2020

Я создаю меню фильтра, которое динамически заполняется параметрами. Меню представляет собой сгруппированный 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);
        }
    }
}

1 Ответ

0 голосов
/ 25 марта 2020

используйте bool для управления переключаемым обработчиком. Установите значение true после завершения инициализации (например, в OnAppearing)

    bool init = false;

    private void Switch_OnToggled(object sender, ToggledEventArgs e)
    {
        if (!bool) return;

        FilterOption filterOption = (sender as Switch).Parent.BindingContext as FilterOption;
        (BindingContext as FilterMenuViewModel)?.ToggleFilter(sender, e, filterOption);
    }
...