您应该使用包含UITableView和您自定义的UITableSource对象来处理删除事件的ViewController。
然后你就可以得到正确的行通过从UITableView的方法是这样点击:
Foundation.NSIndexPath indexPath = tableView.IndexPathForCell(cell);
从你的数据列表,并在同一时间你的UI删除该行的数据。
这是一个示例代码,我给你们写,我们来看一看:
这是视图控制器:
public override void ViewDidLoad()
{
//Create a custom table source
MyTableSource mySource = new MyTableSource();
//Create a UITableView
UITableView tableView = new UITableView();
CGRect tbFrame = this.View.Bounds;
tbFrame.Y += 20;
tbFrame.Height -= 20;
tableView.Frame = tbFrame;
tableView.Source = mySource;
tableView.RowHeight = 50;
this.Add (tableView);
//Handle delete event
mySource.DeleteCell += (cell) => {
//Get the correct row
Foundation.NSIndexPath indexPath = tableView.IndexPathForCell(cell);
//Remove data from source list
mySource.RemoveAt(indexPath.Row);
//Remove selected row from UI
tableView.BeginUpdates();
tableView.DeleteRows(new Foundation.NSIndexPath[]{indexPath},UITableViewRowAnimation.Fade);
tableView.EndUpdates();
};
}
这MyTableSource.cs:
public delegate void DeleteCellHandler(UITableViewCell cell);
public event DeleteCellHandler DeleteCell;
private string CellID = "MyTableCell";
private List<string> tableItems;
public MyTableSource()
{
tableItems = new List<string>();
for (int i = 0; i < 10; i++) {
tableItems.Add ("Test Cell " + i.ToString());
}
}
public void RemoveAt(int row)
{
tableItems.RemoveAt (row);
}
#region implement from UITableViewSource
public override nint RowsInSection (UITableView tableview, nint section)
{
return tableItems.Count;
}
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
MyTableCell cell = tableView.DequeueReusableCell (CellID) as MyTableCell;
if (null == cell) {
//Init custom cell
cell = new MyTableCell (UITableViewCellStyle.Default, CellID);
//Bind delete event
cell.DeleteCell += delegate {
if(null != DeleteCell)
DeleteCell(cell);
};
}
cell.Title = tableItems [indexPath.Row];
return cell;
}
#endregion
这是MyTableCell。cs:
public class MyTableCell : UITableViewCell
{
public delegate void DeleteCellHandler();
public event DeleteCellHandler DeleteCell;
UILabel lbTitle = new UILabel();
UIButton btnDelete = new UIButton (UIButtonType.System);
public string Title{
get{
return lbTitle.Text;
}
set{
lbTitle.Text = value;
}
}
public MyTableCell (UITableViewCellStyle style, string reuseID) : base(style,reuseID)
{
lbTitle.Text = "";
lbTitle.Frame = new CoreGraphics.CGRect (0, 0, 100, 50);
this.AddSubview (lbTitle);
btnDelete.SetTitle ("Delete", UIControlState.Normal);
btnDelete.Frame = new CoreGraphics.CGRect (120, 0, 50, 50);
this.AddSubview (btnDelete);
btnDelete.TouchUpInside += delegate {
if(null != DeleteCell)
DeleteCell();
};
}
}
希望它能帮助你。
如果您仍然需要一些建议,请在此给我留言。
------------------------------ New --------------- ---------------------
我只是建议你将所有的逻辑代码移入ViewController,因为根据MVC模型,它应该在Controller层。
如果你想通过调用一些API或从本地数据库加载数据来管理你的数据,它会更方便。
原因,你可以把你删除事件在TableSource,只需要从控制器TableSource删除事件,并把它,如:
ViewController.cs:
public override void ViewDidLoad()
{
//Create a custom table source
MyTableSource mySource = new MyTableSource();
//Create a UITableView
UITableView tableView = new UITableView();
CGRect tbFrame = this.View.Bounds;
tbFrame.Y += 20;
tbFrame.Height -= 20;
tableView.Frame = tbFrame;
tableView.Source = mySource;
tableView.RowHeight = 50;
this.Add (tableView);
// //Handle delete event
// mySource.DeleteCell += (cell) => {
// //Get the correct row
// Foundation.NSIndexPath indexPath = tableView.IndexPathForCell(cell);
// //Remove data from source list
// mySource.RemoveAt(indexPath.Row);
// //Remove selected row from UI
// tableView.BeginUpdates();
// tableView.DeleteRows(new Foundation.NSIndexPath[]{indexPath},UITableViewRowAnimation.Fade);
// tableView.EndUpdates();
// };
}
在TableSource。 CS,改变GetCell方法像这样的:
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
MyTableCell cell = tableView.DequeueReusableCell (CellID) as MyTableCell;
if (null == cell) {
//Init custom cell
cell = new MyTableCell (UITableViewCellStyle.Default, CellID);
//Bind delete event
cell.DeleteCell += delegate {
// if(null != DeleteCell)
// DeleteCell(cell);
//Get the correct row
Foundation.NSIndexPath dIndexPath = tableView.IndexPathForCell(cell);
int deleteRowIndex = dIndexPath.Row;
Console.WriteLine("deleteRowIndex = "+deleteRowIndex);
//Remove data from source list
RemoveAt(deleteRowIndex);
//Remove selected row from UI
tableView.BeginUpdates();
tableView.DeleteRows(new Foundation.NSIndexPath[]{dIndexPath},UITableViewRowAnimation.Fade);
tableView.EndUpdates();
};
}
cell.Title = tableItems [indexPath.Row];
return cell;
}
你做的唯一的错误是你不应该在你的自定义单元格的删除事件句柄添加任何参数。
因为当你从表格中删除一个单元格时,其他单元格永远不会更新他们自己的IndexPath。
例如,如果您有3行,并且您删除了第二行,它就会起作用。 但是当你尝试删除第三行(这是现在的第二行,因为你只是删除了第二行),你会得到一个关于你没有3行或索引超出范围的异常,因为这个单元格的IndexPath仍然是2(正确的是1)。
因此,您需要使用UITableView的方法“IndexPathForCell”在您的删除事件处理程序中计算索引,就像我上面提到的那样。它将始终得到正确的索引。
-------------------关于您的问题--------------------
你发的关于删除事件的init的错误,你必须初始化它的细胞构造的时候,像我一样:
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
MyTableCell cell = tableView.DequeueReusableCell (CellID) as MyTableCell;
if (null == cell) {
cell = new MyTableCell (UITableViewCellStyle.Default, CellID);
//Bind delete event
cell.DeleteCell += delegate {
//Delete stuff
};
}
cell.Title = tableItems [indexPath.Row];
return cell;
}
如果你只是用它喜欢你:
if (null == cell) {
cell = new MyTableCell (UITableViewCellStyle.Default, CellID);
}
//Bind delete event
cell.DeleteCell += delegate {
//Delete stuff
};
cell.Title = tableItems [indexPath.Row];
就会造成重复绑定问题,因为您的表格单元格被重用,所以当您尝试刷新/插入/删除甚至sc时滚动您的UITableView,将触发“GetCell”方法,因此当您尝试调用单元格的删除事件时,会调用多个代理,第一个代理正在工作,并且如果您至少有两个代理,则会导致问题你遇到了。
的效果是这样的屏幕截图: 重现步骤: 1添加新的项目对的tableview; 2删除刚刚添加的项目; 3再次添加一个新项目; 4删除刚刚添加的项目;
因为有2个代表,所以它抛出一个异常。
最后,我已经将完整的示例代码上传到我的GitHub,如果需要,请下载它。
UITalbViewManagement Sample code
嗨,所有的 首先,感谢你的答案。我从来没有看到过这个角度的问题,现在看来确实更合乎逻辑。 但是,即使我肯定会进入TableSource中的DeleteCell(由Console.WriteLine确认),但我绝对不会通过控制器的ViewDidLoad函数中的DeleteCell。 你知道为什么吗? – Pictar
我修改了我的答案,它应该可以解决您的问题。@ Pictar –
删除工作正常,感谢您的帮助:)唯一剩下的问题是添加了Todo。我为ViewDidLoad中的添加创建了视图,并正确捕获了添加的事件。当我启动应用程序并添加一个Todo时,单元格显示正确,但是当我尝试删除它之后,我得到** ** NullException ** ** dIndexPath ** .. – Pictar