UITableViewDelegate中的问题 - RowSelected给出了错误的NSIndexPath

时间:2011-02-01 10:05:22

标签: c# iphone ios xamarin.ios

我有一个UITableViewSource,我已经将其子类化了。我正在重写GetCell并使用我自己的子类化单元格,如下所示:

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中获取事件时,索引路径会让我得到错误的单元格(如AccessoryButtonTapped,WillSelectRow等事件)。

截面和行数看起来正确但是当我做

 tableView.CellAt(indexPath)

我得错了。 (行和节号再次看起来是正确的。)

注意事项:

  • 该表不断更新 - 项目到达另一个线程,然后是InvokeOnMainThread'd
  • 虽然表格不断更新,但只添加了行和部分 - 没有重新排序或删除
  • 如果我在收到'WillSelectRow'时暂停更新,则无效
  • 最有趣的是(但不是一个可交付的解决方案)如果我每次都创建一个新单元而不是DequeueReusableCell,它可以正常工作。

我不禁想到这是我自己制作的一个愚蠢的错误,却无法找到它。非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

您可以尝试使用不同的方法,如http://simon.nureality.ca/?p=91

所示

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

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

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

快速举例:

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参数(无论如何都会被覆盖)并创建一个公共属性(或setter)。用于在获取单元格后分配正确的项目(无论它是否已出列或新创建)。应该这样做:

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方法也是如此。无论一个单元格是否已经出列或是新单元格,您都应该重置单元格中可能与其他单元格不同的所有内容。

BTW:如果您将单元格硬编码为UITableViewCellStyle.Subtitle,您也可以从构造函数中省略它并将其硬编码到MarketCell类中。

至于cellController方法的价值:您可以将UITableViewCell与自定义数据和行为分离,从而获得一个很好的分离层。您的单元控制器不必像表格单元格那样;)

答案 1 :(得分:0)

看来这仍然是Xamarin的一个问题。不幸的是,@ vlad259发布的链接很久就消失了 - 这个'bug'今天就让我感到厌烦。我不知道它为什么会发生 - 为了追查原因,我已经将我的UITableViewSource实现一直向下切换到返回固定数量的行,并简单地将行号分配给单元格标签。 ..

该bug特别表现为,加载视图,滚动到第一个屏幕外单元格(即,如果您的表格可以渲染10个单元格,滚动以便第11个刚出现在屏幕上),然后点击该单元格 - 您将获得RowSelected事件中几乎随机的Row索引。

我找到了几个解决方案。

解决方案A

如果我覆盖了GetHeightForRow以返回自定义行高,即使它返回常量,这个错误也只会显示出来。如果不需要......不要覆盖它。

解决方案B

该错误似乎是DequeueReusableCell(s)内的NSIndexPath参数。

使用

UITableView.DequeueReusableCell(NSString)

而不是

UITableView.DequeueReusableCell(NSString, NSIndexPath)