I'm figuring out the correct way to reuse cells in a UITableView and I would know if the mechanism I'm using is correct.
The scenario is the following.
I've a UITableView that displays a list of data obtained from a web service.
_listOfItems = e.Result as List<Item>;
where _listOfItems is an instance variable.
This list is passed to a class that extends UITableViewSource. Obviously this class override GetCell method to visualize data in this manner:
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell(_cID);
Item item = _listOfItems[indexPath.Row];
int id = item.Id;
if (cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Value1, _cID);
cell.Tag = id;
_cellControllers.Add(id, cell);
}
else
{
bool vb = _cellControllers.TryGetValue(id, out cell);
if(vb)
{
cell = _cellControllers[id];
}
else
{
cell = new UITableViewCell(UITableViewCellStyle.Value1, _cID);
cell.Tag = id;
_cellControllers.Add(id, cell);
}
}
cell.TextLabel.Text = item.Title;
return cell;
}
where
_cID is an instance variable identifier for the cell
string _cID = "MyCellId";
_cellControllers is a dictionary to store cell and the relative id for an Item instance
Dictionary<int, UITableViewCell> _cellControllers;
I'm using the dictionary to store cells bacause when a row is tapped, I have to retrieve the id for the cell tapped (through cell.Tag value), do some other operation - i.e.retrieve other some data from the service - and then update that cell again with new values. In this case each cell has to be unique.
So, my question is:
Is this the right manner to reuse cell or is it possible to figured out another solution to reuse cell and guaranteeing each tap for a cell is unique?
I hope it's all clear :) Thank you in advance. Regards.
I think what you are doing here is a bit too much. Especially the part where you are holding extra references to cells in a Dictionary.
I would do it differently. The DequeueReusableCell method is there so that you can retrieve any existing cell, but not necessarily the values it contains. So something like this will suffice:
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
int rowIndex = indexPath.Row;
Item item = _listOfItems[rowIndex];
UITableViewCell cell = tableView.DequeueReusableCell(_cID);
if (cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Value1, _cID);
}
// Store what you want your cell to display always, not only when you are creating it.
cell.Tag = item.ID;
cell.TextLabel.Text = item.Title;
return cell;
}
Then, in the RowSelected method, change your data source:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath){
// Do something here to change your data source _listOfItems[indexPath.Row] = new Item();
}
If I understand correctly what you want to do, this solution is better.
You will save yourself a lot of trouble if you use my MonoTouch.Dialog library that takes care of all of these details for you and does exactly what you want and more. It will let you focus on your app instead of focusing on the administrivia, and I believe will let you move faster, you can get it from:
http://github.com/migueldeicaza/MonoTouch.Dialog
The first problem with this code is that this hardcodes the cells to a single type. In general, you would have to first check the section/row and based on this information determine the kind of cell that you want.
Once you determine the kind of cell you want, then you use this information to call DequeueReusableCell with the token associated with this cell ID. This is different for example for a cell that contains an entry line vs a cell that contains an image. You need to dequeue the right kind of cell.
You do not need to make every cell unique, all the information that you need is in the section/row, so what you need is something that maps a section/row to your unique cell. A simple approach is that there is a single section, and the row is the index into your data array that you want to fetch more information from.
A small tutorial on best practices when creating these cells can be found here:
http://tirania.org/monomac/archive/2011/Jan-18.html
If you were using MonoTouch.Dialog, your whole code could be:
var elements = "foo, bar, baz";
var dvc = new DialogViewController ();
dvc.Root = new RootElement ("My results") {
from x in elements.Split (',')
select (Element) new StringElement (x);
};
dvc.Root.Add ("Final one");
current.PresentModalViewController (dvc, true);
The above creates a UITableView with 4 rows, one for "foo", "bar" and "baz" using Linq, and adds an extra node at the end just to show how to use the Add API.
There are also many assorted elements you can use, you are not limited to String elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With