Обновление содержимого 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));
}
}