【问题标题】:TableView Cells Have Their Data Reset On ScrollingTableView 单元格在滚动时重置其数据
【发布时间】:2015-07-14 12:15:21
【问题描述】:

-----编辑-----

通过在 TableViewSource 中使用 DraggingStarted 方法,我找到了解决问题的方法。这不是最佳解决方案,我将继续寻找合适的方法来处理我的问题,但现在,我可以继续我的流程。

public override void DraggingStarted(UIScrollView scrollView)
{
    for (int i = 0; i < 12; i++)
    {
        try
        {
            GlobalSupport.NewClientData[i] = ((scrollView as UITableView).CellAt(NSIndexPath.FromItemSection(i, 0)).ContentView.Subviews[1] as UITextField).Text;
        }
        catch
        {
        }
    }

    Console.WriteLine("hoi");
}

然后在我的 GetCell 方法中搜索这个新的数据结构,以找到正确的值:

if (GlobalSupport.NewClientData[indexPath.Row] != "")
{
    cell.cellValue = GlobalSupport.NewClientData[indexPath.Row];
}

-----ENDEDIT-----

我正在实施一个以 TableView 为中心的应用程序。这意味着我的大部分屏幕都是 TableView,其中包含可重复使用的单元格。这些单元格是使用 Xcode Designer 定义的(这意味着我的资源中有一个 .cs、一个 .xib 和一个 .designer 用于每个不同的唯一单元格)。

使用预定义数据(自定义数据对象、字典、列表等)构建 TableView 时,我调用单元格 .cs 中的方法来修改 .xib 中定义的两个 UILabel(或 UILabel 和 UIImageView) .这一切都很顺利;提供的数据通过 TableViewSource 中的 GetCell 方法放入标签和其他控件中,并保留在那里,即使在滚动之后(因为数据是预定义的,并使用 IndexPath.Row 来确定放置位置)。

现在麻烦来了:

我有另一个单元格,其中有一个 UILabel 和 UITextField。 UILabel 将其文本修改为与我的可本地化字符串文件相对应。我的 GetCell 方法中有一个开关,在 TableViewSource 中,如下所示:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
    CTextInput cell = (CTextInput)tableView.DequeueReusableCell(CTextInput.Identifier);

    switch (indexPath.Row)
    {
        case 0:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtBSN", "", "");
            break;
        case 1:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtPrefix", "", "");
            break;
        case 2:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtInitials", "", "");
            break;
        case 3:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtFirstName", "", "");
            break;
        case 4:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtLastName", "", "");
            break;
        case 5:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtDateOfBirth", "", "");
            cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
            break;
        case 6:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtCity", "", "");
            break;
        case 7:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtStreet", "", "");
            break;
        case 8:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtHouseNumber", "", "");
            break;
        case 9:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtZipcode", "", "");
            break;
        case 10:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtCountry", "", "");
            break;
        case 11:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtPhonenumber", "", "");
            break;
        default:
            break;
    }

    return cell;
}

这很好用。

现在,当视图被加载时,用户可以在 UITextField 中输入他或她的数据,在这些 UILabel 旁边。提供数据,并且随着用户在 TableView 中前进,所有文本都保留在那里......直到用户到达屏幕底部,并且需要滚动以查看其他单元格。然后会发生什么,前几个单元格的 UITextField 中提供的数据被重置为在单元格的 .xib 文件中指定的值,即“”。这是因为我的 GetCell 方法开头的 DequeueReusableCell。每次新单元格进入用户视图时,都会调用 GetCell 方法。这意味着从用户视图中消失的所有单元格都将重置为默认值。

Supply the data

Scrolling down

Scrolling back up

我不希望此视图中的每个单元格都有一组单独的 .cs、.xib 和 .designer 文件,并且目前还没有找到保存单元格 UITextField 内容的方法。 更重要的是,我需要每个单元格内的 UITextField 的内容,以便创建一个新对象,我需要进一步推进这个过程。

非常感谢您对此主题的任何帮助。如果您需要更多信息,请随时与我联系!

亲爱的, 比约恩

【问题讨论】:

  • 您的单元格不是您的数据模型。当数据输入到单元格中时,您需要更新数据模型并在单元格显示在 cellForRowAtIndexPath 时从数据模型中提取数据
  • 抱歉,您能否详细说明“更新您的数据模型”?我不确定单元格的数据模型是什么。
  • 您需要将数据存储在其他数据结构中(例如数组或字典)。您的表格单元格只是数据视图。在 Google 上搜索“模型-视图-控制器”架构。
  • 我找到了一个临时解决方案来解决我的问题,正如您在我的原始帖子中看到的那样。但是,这似乎是一个非常草率的解决方案。回复您的评论:我现在找到了一种获取用户输入的方法,但似乎无法修改单元格的模型以永久应用这些新值。我现在每次都更新单元格。在另一个具有两个 UILabel 的视图中,我通过 ViewController 修改 UILabel 文本。我在 Cell 的类中调用一个方法并修改 label.Text。但是,如果我有一个 TableView 有 12 个相同的单元格(在结构上,而不是内容上),我怎么能做到这一点。
  • 您需要在文本字段更改时从单元格中取回数据并将其存储在某个变量中。使用委托模式执行此操作。在您的表格视图单元子类中,您可以实现 UITextFieldDelegate 方法,以便您可以在文本字段更改时运行代码。为您的视图控制器创建一个协议以实现并将视图控制器设置为单元格的委托。当文本改变时,单元格调用视图控制器中的委托方法来更新变量。然后可以在下次显示该单元格时使用此变量

标签: c# ios uitableview xamarin


【解决方案1】:

您的 UITableView 的 DataSource 需要为单元格提供完全正确渲染所需的任何数据。由于单元格被重用,它们可以被认为是“愚蠢的”并且完全依赖数据源来知道要显示什么。

记住这一点,您需要做的是更新您的 DataSource 以包含输入到单元格的 UITextField 中的任何内容。

以下是您如何实现此目的的示例:

1.) 将 UITableView 的数据源实现为键/值对:

DataSource = new Dictionary<string, string> () {
    { "Label 1", string.Empty },
    { "Label 2", string.Empty },
    ...
    ...
};

对于您的场景,“标签 1”将是 NSBundle.MainBundle.LocalizedString("txtBSN", "", "")

2.) 像这样实现 CTextInput 单元格:

public partial class CTextInput : UITableViewCell
{
    Action<string, string> OnTextFieldTextChanged;

    public CustomCell ()
    {
    }

    public CustomCell (IntPtr handle) : base (handle)
    {
    }

    public void SetupCell (string labelText, string value, Action<string, string> onTextFieldTextChanged)
    {
        CellLabel.Text = labelText;
        CellTextField.Text = value;
        OnTextFieldTextChanged = onTextFieldTextChanged;

        CellTextField.EditingDidEnd += HandleEditingDidEnd;
    }

    void HandleEditingDidEnd (object sender, EventArgs e)
    {
        var textField = sender as UITextField;
        OnTextFieldTextChanged (CellLabel.Text, textField.Text);
    }

    // clean up
    public override void PrepareForReuse ()
    {
        base.PrepareForReuse ();

        OnTextFieldTextChanged = null;
        CellTextField.EditingDidEnd -= HandleEditingDidEnd;
    }

    protected override void Dispose (bool disposing)
    {
        if (disposing) {
            OnTextFieldTextChanged = null;
        }

        base.Dispose (disposing);

    }

}

这里重要的是SetupCell 方法和HandleEditingDidEnd 事件处理程序。您挂钩到 UITextField 的 EditingDidEnd 以便您可以调用传入的 onTextFieldTextChanged 操作。

3.) 添加OnTextFieldTextChange 处理程序并在您的视图控制器中实现GetCell 方法,如下所示:

public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
    var cell = tableView.DequeueReusableCell ("CellIdentifier")  as CTextInput ?? new CTextInput ();

    var labelText = DataSource.Keys.ElementAt (indexPath.Row);
    var textFieldText = DataSource.Values.ElementAt (indexPath.Row);

    cell.SetupCell (labelText, textFieldText, OnTextFieldTextChange);

    return cell;
}


public void OnTextFieldTextChange (string key, string value)
{
    if (DataSource.ContainsKey (key)) {
        DataSource [key] = value;
    }
}

在这里,您定义了一个OnTextFieldTextChange 方法,该方法可以传入SetupCell 方法中的Action&lt;string, string&gt; onTextFieldTextChanged 参数,该方法之前在CTextInput 类中定义。

OnTextFieldTextChange 方法中,您所做的只是更新数据源中给定键的值。

现在,当 UITextField 发出 EditingDidEnd 事件时,数据源会更新以包含用户输入的值。

希望这会有所帮助!

【讨论】:

  • 我做了一些类似的事情,是的。我创建了一个自定义 Eventargs,我在引发事件时使用它。我使用 GetCell 中的 Indexpath.Row 来绑定作为文本字段的 cell.ContentView.Subviews[1].ValueChanged,并抛出我的自定义 Eventargs,通过它我将 UITextField 传递回我的控制器,然后能够复制数据,然后在我的数据源中重新使用它,方法是调用 parent-viewcontroller 的属性,我在其中存储数据。
猜你喜欢
  • 2023-03-14
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多