Как мы можем выполнить действие, когда изменение в списке TableView изменилось?

Наше приложение отображает список групп категорий:

List<CategoryGroupWordCountVM> categoryGroups;

На экране это выглядит примерно так:

Спорт 23 [Включить]

Увлечения 5 [Включить]

Страны 55 [Включить]

Занятия 0 [Выключить]

Строки такие как:

public class CategoryGroupWordCountVM : ObservableProperty {
   public int Id { get; set; }
   public string Name { get; set; }
   public bool IsToggled { get; set; }
}

Страница XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Japanese;assembly=Japanese"        x:Class="Japanese.CategoryGroupPage" x:Name="CategoryGroupPage">
   <ContentPage.Content>
      <TableView x:Name="tableView" Intent="Settings">
      </TableView>
   </ContentPage.Content>
</ContentPage>

Строка XAML:

<ViewCell 
   xmlns="http://xamarin.com/schemas/2014/forms" 
   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
   x:Class="Japanese.MyViewCell">
   <Grid>
      <Label Text = "{Binding Name}" />
      <Label Text = "{Binding TotalWordCount}" />
      <Switch IsToggled = "{Binding IsToggled}" />
   </Grid>
</ViewCell>

Поддержка С#

protected void RefreshPage() {
   categoryGroups = App.DB.GetCategoryGroupWithWordCount();
   var section = new TableSection("Available Categories");
   foreach (var category in categoryGroups) {
      var cell = new MyViewCell { BindingContext = category };
  section.Add(cell);
   }
   tableView.Root.Add(section);
}

protected override void OnAppearing() {
   base.OnAppearing();
   RefreshPage();
}

Что мы хотим сделать, так это то, что когда пользователь переключает переключатель, вызывается метод, подобный приведенному ниже, и значение TotalWordCount для строки, в которую был изменен переключатель, обновляется.

void selectCategoryGroup(object sender, SelectedItemChangedEventArgs e) {
   if (e.SelectedItem == null) {
      return;
   }
   var categoryGroup = (CategoryGroupWordCountVM)e.SelectedItem;
   App.DB.UpdateCategoryGroupIsToggled(categoryGroup.IsToggled, categoryGroup.Id);
   // The row that follows needs to update the value so that 
   // the screen shows a new value for on the left side of 
   // the switch. When the switch is off this will always be
   // 0. When on it will be the list of words in the category
   TotalWordCount = GetWordCountForCategory(categoryGroup.Id);
}

Это было ранее реализовано добавлением этого кода `

<ListView ItemSelected="selectCategoryGroup" >

Но теперь мы используем TableView, который у нас нет.

Поэтому мы будем очень благодарны, если кто-нибудь сможет дать некоторые советы о том, как вызвать метод, например selectCategoryGroup, при изменении ключей.

Обратите внимание, что обычно в списке категорий категорий будет около 20-30 разных записей. Кроме того, если бы это было проще, я был бы счастлив, если MyViewCell был закодирован на С#.

Ответ 1

Обновлено 08/21: Реструктурированный ответ на бит и добавленный код очистки; Добавлено другое решение, основанное на событии с измененным свойством

Вариант 1 - Использовать настраиваемое событие

Чтобы обработать событие switch Toggled на родительском уровне TableView; вам нужно будет развернуть событие до родительского вида. Один из способов сделать это - разоблачить событие в пользовательском MyViewCell.

Шаги:

  • Объявить событие в вашей пользовательской ячейке просмотра (позади кода).

    public event EventHandler<SelectedItemChangedEventArgs> SelectedOrToggled;
    
  • Назначить Toggled обработчик событий для переключателя, определенного в viewcell XAML

    <ViewCell 
        xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
        x:Class="Japanese.MyViewCell">
        <Grid>
            <Label Text = "{Binding Name}" />
            <Label Text = "{Binding TotalWordCount}" />
            <Switch IsToggled = "{Binding IsToggled}" Toggled="Handle_Toggled" />
        </Grid>   
    
  • И вызовите свое настраиваемое событие в нем (в коде управления)

    void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
    {
        var view = sender as BindableObject;
        SelectedOrToggled?.Invoke(this, new 
        SelectedItemChangedEventArgs(view.BindingContext));
    }
    
  • Использование. Теперь вы можете подписаться на настраиваемое событие на родительской странице, где вы используете/создаете экземпляр своего пользовательского вида.

    //XAML usage
    //<local:MyViewCell SelectedOrToggled="selectCategoryGroup" />
    
    protected void RefreshPage()
    {
        categoryGroups = App.DB.GetCategoryGroupWithWordCount();
        var section = new TableSection("Available Categories");
        foreach (var category in categoryGroups)
        {
            var cell = new MyViewCell { BindingContext = category };
            // assign method as event-handler
            cell.SelectedOrToggled += selectCategoryGroup;
            section.Add(cell);
        }
        tableView.Root.Add(section);
    }
    
  • Очистка: Чтобы избежать утечек памяти, рекомендуется отказаться от подписки во время разгрузки.

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
    
        foreach (var section in tableView.Root)
        {
            foreach(var cell in section)
            {
                cell.Tapped -= openCategoriesPage;
            }
        }
    }
    

Поведение выбора. Вы также можете настроить его, обработав событие Tapped в ViewCell и поднимите событие SelectedOrToggled (похожее на Handle_Toggled), чтобы имитировать поведение выбора ListView.

Вариант 2 - использовать PropertyChanged событие в виде-модели

Вы можете прослушать изменение свойства IsToggled в CategoryGroupWordCountVM и соответственно отреагировать.

Шаги:

  • Использование. Вы можете подписаться на событие PropertyChanged в viewmodel.

    protected void RefreshPage()
    {
        categoryGroups = App.DB.GetCategoryGroupWithWordCount();
        var section = new TableSection("Available Categories");
        foreach (var category in categoryGroups)
        {
            var cell = new MyViewCell { BindingContext = category };
            // assign method as event-handler
            cat.PropertyChanged += CategoryVM_PropertyChanged;
            section.Add(cell);
        }
        tableView.Root.Add(section);
    }
    
    async void CategoryVM_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == nameof(CategoryGroupWordCountVM.IsToggled))
        {
            var categoryGroup = (CategoryGroupWordCountVM)sender;
            ...//call update code here
            ...
        }
    }
    
  • Очистка: Чтобы избежать утечек памяти, рекомендуется отказаться от подписки во время разгрузки.

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
    
        foreach (var section in tableView.Root)
        {
            foreach(var cell in section)
            {
                (cell as ObservableProperty)?.PropertyChanged -= CategoryVM_PropertyChanged;
            }
        }
    }
    

Ответ 2

Вы можете подписаться на Toggled событие Switch, которое возникает при переключении Switch.