2011-02-01 4 views
1

私はサブクラス化したUITableViewSourceを持っています。私はそうのように、getcellををオーバーライドし、私自身のサブクラス化細胞を使用しています:UITableViewDelegateの問題 - RowSelectedが間違ったNSIndexPathを与える

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を行うよりも、正しく動作します。

私はそれが自分の作ったばかげたバグだとは思っていませんが、見つけられません。どんな援助も最も感謝して受け取ります! http://simon.nureality.ca/?p=91

基本的には、UITableViewCellのをサブクラス化していないが、代わりに「MarketCellController」としてのUIViewControllerのサブクラス:

+0

のあなたはtable.ReloadData()テーブルのデータが更新されるたびに呼び出していますか? – Luke

+0

新しい行が追加されたときのみ - 既存のセルへの更新のために、ReloadRows()を実行しています – vlad259

+0

これはセルのキューイングに関連している可能性があります。あなたのMarketCellコンストラクタは、新しく作成されたセルに_cellIdentifierをどのように割り当てますか? – riha

答えて

1

あなたは上実証されたように異なるアプローチを試みることができます。このカスタムコントローラーは、標準のUITableViewCellとカスタムのものを保持し、AddSubview()を使用してカスタムのものを追加します。

必要なセルごとに新しいコントローラを1つ作成し、辞書に格納します。

トリック:セルに一意のタグを割り当てることによって、関連するコントローラを辞書から取得できます。

クイック例:

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およびデキューの問題を回避することができます。

EDIT:

私は心の中で何かを持っていた:あなたは、あなたのMarketCellコンストラクタにあなたの商品をassingingているように見えます。ただし、デキューされたセルには古いアイテムが設定されており、デキュー後に新しいアイテムにリセットする必要があります。

コンストラクタのitemパラメータを削除します(とにかく上書きされます)代わりにpublicプロパティ(または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をカスタムデータとビヘイビアから切り離し、分離レイヤを作成します。あなたのセルコントローラはテーブルセルのように動作する必要はありません;

+0

本当に面白そうです。ありがとう! – vlad259

+0

私はそれが好きですが、自分の細胞を追跡するだけの利点はどこにあるのでしょうか? (それは私がやっていることで、うまくいきます。) – vlad259

+0

私はそれについてもっと学ぶので、私はあなたのソリューションがますます好きです。ありがとう! – vlad259

0

これはXamarinではまだ問題があるようです。 @ vlad259によって投稿されたリンクは、残念ながら長く残っていません - そして、この「バグ」は今日私にちょっと痛感します。私はなぜそれが起こっているのかわかりません - 原因を突き止めるために、私は自分のUITableViewSource実装を固定数の行を返すように切り捨て、セルのラベルに行番号を割り当てるだけです。 ..

バグは、ビューを読み込んで最初のオフスクリーンセルにスクロールします(つまり、テーブルが10個のセルをレンダリングできる場合はスクロールして11番目のセルのみが画面に表示されます) RowSelectedイベントでほとんどランダムな行インデックスを取得します。

私はこれに対するいくつかの解決策を見つけました。

ソリューション

このバグは、私だけがカスタム行の高さを返すようにGetHeightForRowを上書きした場合、マニフェストに表示されます - それは定数を返すいたとしても。それが必要でないなら...それを上書きしないでください。

溶液B

バグが、具体的NSIndexPath引数を取るDequeueReusableCell(秒)以内であることが表示されます。

使用

UITableView.DequeueReusableCell(NSString)

代わり

UITableView.DequeueReusableCell(NSString, NSIndexPath)