Обновление содержимого ListView при событии Switch Toggle

Для моего приложения я пытаюсь сделать следующее:

Изображение желаемого результата

  • Когда переключатель становится переключенным (true/false), установите для содержимого метки даты новое значение, которое генерируется переключателем Switch, и обновите представление списка для немедленного отображения нового содержимого этой метки.

Значения корректно изменяются негласно, когда в отладчике, но метка не будет обновляться.

Идея кода: в App.Xaml.CS мы заполняем каждый ObservableCollection из класса DbClub, который используется в качестве своего рода жестко закодированного класса Database.

На моей вкладке TabbedPage есть динамически созданные ContentPages, основанные на том, сколько элементов сохранено в соответствующей ObservableCollection.

foreach (var toets in dbClub.Toetsen)
 {
     MaakTabjeDynamischAan(toets); // GenerateTabs which takes toets as parameter
  }

На каждой ContentPage я динамически создаю новый ListView, который принимает сетку для отображения элементов. Сетка / список имеет 2 метки и переключатель на ViewCell как дочерние.

private void MaakTabjeDynamischAan(Toets toets)
 {        
    ListView listview = new ListView 
     {
        BindingContext = this,

        ItemTemplate = new DataTemplate(() =>
        {
          // Create views with bindings for displaying each property.
           Label nameLabel = new Label();
           Label birthdayLabel = new Label();                   
           Switch sSwitch = new Switch();

          // Set Bindings for each property
           nameLabel.SetBinding(Label.TextProperty, "opdrNaam");
           birthdayLabel.SetBinding(Label.TextProperty, new Binding("sBehaaldInfo"));
           sSwitch.SetBinding(Switch.IsToggledProperty, new Binding("YesNo"));

          nameLabel.TextColor = Color.White;
          birthdayLabel.TextColor = Color.White;


          // Attach toggle event to switch
           sSwitch.Toggled += mooieSwitch_Toggled;


          // Create Content Grid for layouting listview itemsource
            var grid = new Grid();

          // Define Background for listview grid

          grid.Padding = 5;
          grid.BackgroundColor = Color.FromRgb(34, 35, 38);

          // Add labels to their representative grid columns
          grid.Children.Add(nameLabel);
          grid.Children.Add(birthdayLabel, 1, 0);
          grid.Children.Add(sSwitch, 2, 0);


          ColumnDefinition gridCol1 = new ColumnDefinition();
          ColumnDefinition gridCol2 = new ColumnDefinition();
          ColumnDefinition gridCol3 = new ColumnDefinition();

          gridCol1.Width = new GridLength(60, GridUnitType.Star);
          gridCol2.Width = new GridLength(20, GridUnitType.Star);
          gridCol3.Width = new GridLength(20, GridUnitType.Star);

          grid.ColumnDefinitions.Add(gridCol1);
          grid.ColumnDefinitions.Add(gridCol2);
          grid.ColumnDefinitions.Add(gridCol3);

          // Return an assembled ViewCell.
         return new ViewCell {View = grid};
       }),

            ItemsSource = toets.Opdrachten
        };
        listview.SeparatorVisibility = SeparatorVisibility.None;

 // Code for creating the actual new ContentPage

        var page = new ContentPage
        {

            Title = toets.ToetsNaam,
            Content = new StackLayout
            {
                Children =
                {

                    listview
                }
            }

        };
        this.Children.Add(page);
    }

Содержимое меток и свойство IsToggled этих дочерних элементов связаны с отдельными классами. Первичный класс в этом случае 'DbClub', который содержит 3 ObservableCollections из их унаследованных классов, которые имеют свойства, с которыми связан ListView.

public class DbClub
{
    public string Clubnaam; // Don't bother with this property
    public ObservableCollection<Speler> Spelers;
    public ObservableCollection<Instelling> Instellingen;
    public ObservableCollection<Toets> Toetsen;

   // Each Toets takes 3 properties : int Id, string Name, OC<Opdracht> 
   // Where OC<Opdracht> takes Opdrachten to display
}

Когда Switch переключается, Opdracht становится истинным, и в этом случае генерируется DateTime, который мы хотим отобразить в ограниченной метке. Для этого мы создали класс ToetsCijfers.

public class ToetsCijfers
{
    public int toetsNr;
    public ObservableCollection<Behaald> opdrachten;
}

public class Behaald
{
    public int opdrNr;
    public DateTime datumBehaald;
    public string dtString; 

}

public class Opdracht
{
    public int opdrNr { get; set; }
    public string opdrNaam { get; set; }
    public bool YesNo { get; set; }
    public string sBehaaldInfo { get; set; }

}

Таким образом, всякий раз, когда переключатель переключается, мы вызываем метод SetBehaaldInfo после того, как мы решили, был ли достигнут Opdracht, если его значение DateTime становится> 2001, а если оно ложно, мы устанавливаем DateTime в 1999, 1, 1.

private void mooieSwitch_Toggled(object sender, ToggledEventArgs e)
{

   if (curOpdracht == null)
   {
      curOpdracht = new Behaald {opdrNr = tabbedopdrNr};
      curToetsSpeler.opdrachten.Add(curOpdracht);


  }

    curOpdracht.datumBehaald = e.Value ? DateTime.Now.Date : new DateTime(1999, 1, 1);
SetBehaaldInfo(toets.ToetsId, curOpdracht);

Метод SetBehaaldInfo():

    private void SetBehaaldInfo(int curToetsNr, Behaald curBehaald)
    {


        var currentToets = dbClub.Toetsen.FirstOrDefault(t => t.ToetsId == curToetsNr);
        if (currentToets != null)
        {
            // var curOpdr = currentToets.Opdrachten.FirstOrDefault(o => o.opdrNr == curBehaald.opdrNr);
            var curOpdracht = currentToets.Opdrachten.FirstOrDefault(o => o.opdrNr == curBehaald.opdrNr);
            if (curOpdracht != null && curBehaald.datumBehaald >= new DateTime(2000, 1, 1))
            {
                curOpdracht.YesNo = true;

                curOpdracht.sBehaaldInfo = curBehaald.datumBehaald.ToString("dd-MM-yy");


            }
            else
            {
                if (curOpdracht != null)
                    curOpdracht.sBehaaldInfo = "n.n.b";
        }
    }
}

Методы, которые я пробовал:

  • Я пытался изменить ItemsSource на пустую коллекцию или на ноль, а затем установить ItemsSource на свой исходный ItemsSource, чтобы принудительно обновить
  • Я пытался использовать PropertyChanged(), но я не уверен, как правильно реализовать это, и в настоящее время не имеет значения.

Мне известно, что OC обновляется только в том случае, если его коллекция изменяется путем добавления / удаления или замены. Не его содержание, вот в чем проблема.

Есть идеи? Помощь будет оценена. Извините, если код не отформатирован должным образом, совершенно новый вопрос к SO. Но не отвечайте с помощью Google чаще, проверяйте SO на наличие решений, если это было сделано, ни одно из них не относится к тому, что я делаю.

Если потребуется, я опубликую ссылку на SourceCode для проверки.

1 ответ

Решение

Хорошо. После недели исследований я понял, как решить мою проблему. Я реализовывал INotifypropertyChanged на неправильных классах, которые вызывали нулевую ссылку, потому что никакие свойства не были изменены, и это не было обработано должным образом.

Вместо того, чтобы применять его к моему классу Opdrachten, я применил его к классу Behaald. Я применил его к свойствам YesNo & sBehaaldInfo, таким образом, где фактические свойства меняются, и затем это работает.

public class Opdracht : INotifyPropertyChanged
{
    private bool _yesNo;
    private string _sBehaaldInfo;


    public int OpdrNr { get; set; }
    public string OpdrNaam { get; set; }

    public bool YesNo
    {
        get { return _yesNo; }
        set
        {
            _yesNo = value;
            OnPropertyChanged(nameof(YesNo));
        }
    }

    public string SBehaaldInfo
    {
        get { return _sBehaaldInfo; }
        set
        {
            _sBehaaldInfo = value;
            OnPropertyChanged(nameof(SBehaaldInfo));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    }
}
Другие вопросы по тегам