您應該使用包含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