【发布时间】:2018-05-13 09:24:15
【问题描述】:
对于我的应用程序,我正在尝试完成以下操作:
- 当切换开关(true/false)时,将日期标签的内容设置为由 Switch 切换生成的新值,并刷新列表视图以立即显示该标签的新内容。
在调试器中,值会在后台正确更改,但标签不会更新。
代码的想法: 在 App.Xaml.CS 中,我们从 DbClub 类中填充每个 ObservableCollection,该类用作一种硬编码的数据库类。
在我的 TabbedPage 上,有根据相应 ObservableCollection 中保存的项目数动态创建的 ContentPages。
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
}
当切换开关时,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; }
}
因此,每当切换开关时,我们在确定是否已实现 Opdracht 后调用 SetBehaaldInfo 方法,如果为 true,则 DateTime 变为 > 2001,如果为 false,我们将 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 更改为空 Collection 或 null,然后将 ItemsSource 设置为其原始 ItemsSource 以强制刷新
- 我尝试使用 PropertyChanged(),但我不确定如何以正确的方式实现它,目前没有任何区别。
我知道 OC 只有在其集合被添加/删除或替换更改时才会更新。不是它的内容,所以这就是问题所在。
有什么想法吗?帮助将不胜感激。如果代码格式不正确,请原谅我对 SO 提出问题是很新的。但是不要更频繁地回复使用谷歌,检查解决方案,在那里做过,它们都不适用于我正在做的事情。
如果需要,我将发布源代码链接以供审核。
【问题讨论】:
-
这个例子远不及minimal。
-
请自行解释,不要参考不同的页面。
-
如果您希望对 Behaald 类中属性的更改反映在 UI 中,那么 Behaald 需要实现 INotifyPropertyChanged。
-
实现 INotifyPropertyChanged 时出现无法加载内存异常 我试过了,也许我做错了。可以举个例子吗?
-
在 SO 和网络上的其他地方已经有数千个 INPC 示例。如果您遇到错误,请更新您的问题以显示特定的错误/异常。
标签: c# listview xamarin observablecollection