【问题标题】:Updating ListView Content on Switch Toggle event在 Switch Toggle 事件上更新 ListView 内容
【发布时间】:2018-05-13 09:24:15
【问题描述】:

对于我的应用程序,我正在尝试完成以下操作:

Image of desired result

  • 当切换开关(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


【解决方案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));

    }
}

【讨论】:

    猜你喜欢
    • 2021-08-22
    • 2013-04-25
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2011-03-17
    相关资源
    最近更新 更多