For my application I am trying to accomplish the following:
- When a switch gets Toggled (either true/false) set the content of the date label to a new value that gets generated by the Switch toggle and refresh the listview to immediate display the new content of that label.
The values get changed correctly behind the scenes when in the debugger but the label's won't update.
The idea of the code : In the App.Xaml.CS we fill each ObservableCollection from the DbClub class which is used as a sort of hardcoded Database class.
On my TabbedPage there are dynamic created ContentPages based on how many items are saved in the corresponding ObservableCollection.
foreach (var toets in dbClub.Toetsen)
{
MaakTabjeDynamischAan(toets); // GenerateTabs which takes toets as parameter
}
On each ContentPage I dynamicly create a new ListView which takes a grid to display the items. The grid/listview has 2 labels and a switch per ViewCell as children.
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);
}
The content of the labels and the IsToggled property of those children are bound to seperate classes. The primary class is in this case 'DbClub' which holds 3 ObservableCollections from their inherited classes which have the properties that the ListView gets bound to.
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
}
When a Switch gets toggled the Opdracht becomes true and in this case a DateTime is generated which we want to display in the bounded Label. In order to accomplish this we have made a class called '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; }
}
So whenever a switch is Toggled we call the SetBehaaldInfo method after we decided whether the Opdracht has been achieved, if its true the DateTime becomes > 2001 and if it is false we set the DateTime to 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() method :
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";
}
}
}
Methods I've tried:
- I've tried to change the ItemsSource to an empty Collection or to null and afterwards set the ItemsSource to its original ItemsSource to force a refresh
- I've tried to use PropertyChanged() but I am not certain on how to implement this the correct way, and makes no difference at the moment.
I am aware that OC's only update when its collection is changed by Add/Remove or Replace. Not its content, so that's the problem here.
Any ideas? Help would be appreciated. Excuse me if the code is not formatted properly, quite new to asking questions on SO. But don't reply with use Google more often, check SO for solutions, been there done that, none of them apply to what I am doing.
If requested I will post a link to the SourceCode to review.