UITableViewDelegate问题 – RowSelected给出了错误的NSIndexPath

我有我已经分类的UITableViewSource。 我重写GetCell和使用我自己的subclassed单元格,如下所示:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { MarketItem item=_tableItems[indexPath.Section].Items[indexPath.Row]; MarketCell cell=tableView.DequeueReusableCell(_cellIdentifier) as MarketCell; if (cell==null) { cell=new MarketCell(UITableViewCellStyle.Subtitle,_cellIdentifier,item); } // decorate the cell // ... return cell; } 

这工作,但是当我得到我的UITableViewDelegate事件,索引path得到我错误的单元格(像AccessoryButtonTapped,WillSelectRow等事件)。

部分和行号看起来是正确的,但是当我做一个

  tableView.CellAt(indexPath) 

我得到错误的单元格。 (行和段号再次看起来是正确的。)

注意事项:

  • 表不断更新 – 项目到达不同的线程然后InvokeOnMainThread'd
  • 虽然表格不断更新,但只添加了行和部分 – 没有重新sorting或删除
  • 如果我在获取“WillSelectRow”的时候暂停更新,这并没有帮助
  • 最有趣的是(但不是一个可交付的解决scheme),如果我每次做一个新的单元而不是做DequeueReusableCell,它能正常工作。

我不禁认为这是我自己制造的一个愚蠢的错误,但无法find它。 任何帮助将非常感激地收到!

你可以尝试一种不同的方法,如http://simon.nureality.ca/?p=91所示

基本上,不要inheritanceUITableViewCell,而是将UIViewController作为“MarketCellController”的子类。 这个自定义控制器维护一个标准的UITableViewCell以及你的自定义的东西,并简单地通过AddSubview()添加你的自定义的东西。

您为每个必需的单元格创build一个新的控制器并将其存储到字典中。

诀窍:通过为单元分配唯一标记,您可以从字典中检索关联的控制器。

快速示例:

 Dictionary<int,MarketCellController> controllers = new Dictionary<int,MarketCellController>(); // ... public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { UITableViewCell cell = tableView.DequeueReusableCell(_cellIdentifier); MarketCellController cellController; if (cell == null) { cellController = new MarketCellController(); cell = cellController.Cell; controllers.Add(cell.Tag, cellController); } else { cellController = controllers[cell.Tag]; } // Decorate the cell (using Methods of your cellController) // ... return cell; } 

这可能最终会绕过UITableViewCells和出队的问题。

编辑:

我只是有一些其他的想法:你似乎只在你的MarketCell构造函数上分配你的项目。 但是,出列单元格的旧项目已设置,您需要在出列之后将其重置为新项目。

删除构造函数的item参数(它将被覆盖),并创build一个公共属性(或setter)。 在获取单元格之后使用它来分配正确的项目(不pipe它是否已经出队或新创build)。 应该这样做:

 MarketCell cell = tableView.DequeueReusableCell(_cellIdentifier) as MarketCell; if (cell == null) { cell = new MarketCell(UITableViewCellStyle.Subtitle, _cellIdentifier); } // Assign the correct item cell.Item = item; // or (whatever you like more): // cell.SetItem(item); // Decorate the cell // ... return cell; 

我的cellController方法也是如此。 无论细胞出院还是新出现,都应该重置细胞上可能与其他细胞不同的所有细胞。

顺便说一句:如果你硬编码你的单元格到UITableViewCellStyle.Subtitle,你可以从构造函数中忽略它,并将其硬编码到你的MarketCell类中。

至于cellController的方法是值得的:你从你的自定义数据和行为中解耦UITableViewCell,从而得到一个很好的分离层。 您的单元格控制器不必像表格单元格一样工作;)

看来这在Xamarin中还是个问题。 @ vlad259发布的链接不幸已经消失了很久了,而这个“bug”就是今天的一点点。 我不知道为什么会发生这种情况 – 为了追踪原因,我使用了裁减我的UITableViewSource实现,直到返回固定数量的行,并简单地将行号分配给单元格标签。 ..

这个bug具体performance为:加载视图,滚动到第一个屏幕外的单元格(例如,如果你的表格可以渲染10个单元格,滚动到第11个单元格出现在屏幕上),然后点击该单元格 – 你会得到一个几乎是随机的RowSelected事件中的行索引。

我find了一些解决scheme。

答案A

如果我重写了GetHeightForRow来返回自定义行高,这个bug只会出现,即使它返回一个常量。 如果不需要…不要覆盖它。

解决schemeB

看来,该错误是专门在DequeueReusableCell (s)接受NSIndexPath参数。

使用

UITableView.DequeueReusableCell(NSString)

代替

UITableView.DequeueReusableCell(NSString, NSIndexPath)