I am Working on Xamarin.iOS.In the TableView. I am bind the Cell with Button.
For Button Click I am doing Subscribe and Unsubscribe Cell event by below code
cell.btn_Click.Tag = indexPath.Row; cell.btn_Click.TouchUpInside -= BtnClickEvent; cell.btn_Click.TouchUpInside += BtnClickEvent;
this is not working fine when I call data api again and set to the TableView.
Explanation : When I open ViewController first time cell button click event fire 1 time. And I open it second time it will fire cell button click event 2 time. I am using upper code for subscribe and unsubscribe button event then why it will called multiple time.
this issue i am facing in iOS 11.2
First Way :
Source Class full code
class StockListSourceClass : UITableViewSource { private List<PacketAndPacketDetailItem> stockLists; private List<string> serialNoList; private UINavigationController navigationController; public static event EventHandler BtnClickEvented; public StockListSourceClass(List<PacketAndPacketDetailItem> stockLists, List<string> serialNolist, UINavigationController navigationController) { this.stockLists = stockLists; this.serialNoList = serialNolist; this.navigationController = navigationController; } public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { StockTableViewCell cell = tableView.DequeueReusableCell(StockTableViewCell.Key) as StockTableViewCell ?? StockTableViewCell.Create(); var item = stockLists[indexPath.Row]; if (serialNoList.Contains(item.SerialNo)) cell.BindData(item, true); else cell.BindData(item, false); cell.SelectionStyle = UITableViewCellSelectionStyle.None; cell.PreservesSuperviewLayoutMargins = false; cell.SeparatorInset = UIEdgeInsets.Zero; cell.LayoutMargins = UIEdgeInsets.Zero; cell.SetNeedsLayout(); cell.LayoutIfNeeded(); cell.btn_Click.Tag = indexPath.Row; cell.btn_Click.TouchUpInside -= BtnClickEvent; cell.btn_Click.TouchUpInside += BtnClickEvent; cell.btn_Click.TouchUpInside += (sender, e) => { var imageName = ((UIButton)sender).TitleLabel.Text; if (imageName.Equals("unchecked")) { ((UIButton)sender).SetBackgroundImage(UIImage.FromBundle("checked"), UIControlState.Normal); ((UIButton)sender).TitleLabel.Text = "checked"; } else { ((UIButton)sender).SetBackgroundImage(UIImage.FromBundle("unchecked"), UIControlState.Normal); ((UIButton)sender).TitleLabel.Text = "unchecked"; } }; return cell; } public void BtnClickEvent(object sender, EventArgs e) { var row = ((UIButton)sender).Tag; MarketSheetViewController.RowNo = (int)row; if (BtnClickEvented != null) { BtnClickEvented(stockLists[(int)row].SerialNo, EventArgs.Empty); } } public override nint RowsInSection(UITableView tableview, nint section) { return stockLists.Count; } public override void RowSelected(UITableView tableView, NSIndexPath indexPath) { var storyboard = UIStoryboard.FromName("Main", null); var webController = storyboard.InstantiateViewController("PacketDetailViewController") as PacketDetailViewController; webController.item = stockLists[indexPath.Row]; this.navigationController.PushViewController(webController, true); } }
Inside ViewController I use that
StockListSourceClass.BtnClickEvented += (sender, e) => { if (!(serialNoList.Contains(stockLists[RowNo].SerialNo))) serialNoList.Add(stockLists[RowNo].SerialNo); else serialNoList.Remove(stockLists[RowNo].SerialNo); SetUpperPanelData(); };
Second Way
//cell.btn_Click.TouchUpInside -= BtnClickEvent; //cell.btn_Click.TouchUpInside += BtnClickEvent; cell.btn_Click.TouchUpInside += (sender, e) => { var imageName = ((UIButton)sender).TitleLabel.Text; if (imageName.Equals("unchecked")) { ((UIButton)sender).SetBackgroundImage(UIImage.FromBundle("checked"), UIControlState.Normal); ((UIButton)sender).TitleLabel.Text = "checked"; } else { ((UIButton)sender).SetBackgroundImage(UIImage.FromBundle("unchecked"), UIControlState.Normal); ((UIButton)sender).TitleLabel.Text = "unchecked"; } var row = ((UIButton)sender).Tag; MarketSheetViewController.RowNo = (int)row; if (BtnClickEvented != null) { BtnClickEvented(stockLists[(int)row].SerialNo, EventArgs.Empty); } };
But this method is called multiple times if I open the ViewController a second time.
2 Answers
Answers 1
Finally got the solution by doing below way
StockTableViewCell.cs
public partial class StockTableViewCell : UITableViewCell { public int Row; public event EventHandler<int> SelectButtonTapped; public void BindData(PacketAndPacketDetailItem item, bool flag, int row) { this.Row = row; btn_click.TouchUpInside -= OnSelectButtonTapped; btn_click.TouchUpInside += OnSelectButtonTapped; } private void OnSelectButtonTapped(object sender, EventArgs e) { if (SelectButtonTapped != null) SelectButtonTapped(sender, Row); } }
TableSource Class
class StockListSourceClass : UITableViewSource { public event EventHandler<int> SelectButtonTapped; public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { StockTableViewCell cell = tableView.DequeueReusableCell(StockTableViewCell.Key) as StockTableViewCell ?? StockTableViewCell.Create(); var item = stockLists[indexPath.Row]; if (serialNoList.Contains(item.SerialNo)) cell.BindData(item, true, indexPath.Row); else cell.BindData(item, false, indexPath.Row); cell.SelectButtonTapped -= OnCellSpeakButtonTapped; cell.SelectButtonTapped += OnCellSpeakButtonTapped; cell.SelectionStyle = UITableViewCellSelectionStyle.None; cell.PreservesSuperviewLayoutMargins = false; cell.SeparatorInset = UIEdgeInsets.Zero; cell.LayoutMargins = UIEdgeInsets.Zero; cell.SetNeedsLayout(); cell.LayoutIfNeeded(); return cell; } void OnCellSpeakButtonTapped(object sender, int e) { var row = e; MarketSheetViewController.RowNo = (int)row; if (SelectButtonTapped != null) SelectButtonTapped(sender, e); } }
and finally we can do in the ViewController to get the single event of Cell button
define this way
stockListSourceClass.SelectButtonTapped -= OnSelectButtonTapped; stockListSourceClass.SelectButtonTapped += OnSelectButtonTapped;
and Implement it.
private void OnSelectButtonTapped(object sender, int e) { if (!(serialNoList.Contains(stockLists[RowNo].SerialNo))) serialNoList.Add(stockLists[RowNo].SerialNo); else serialNoList.Remove(stockLists[RowNo].SerialNo); SetUpperPanelData(); }
Answers 2
You can try to place that code inside your custom cell, unsubscribe event inside method PrepareForReuse
and subscribe it when populating the data to cell.
Code
public class DetailCell : UICollectionViewCell { CustomEventHandler HandlerForButton; public override void PrepareForReuse () { base.PrepareForReuse (); if (HandlerForButton != null) { EditButton.TouchUpInside -= ButtonPressed; } HandlerForButton = null; } private void ButtonPressed (object sender, EventArgs args) { if (HandlerForButton != null) { HandlerForButton (this, args); } } internal void GetCell (int position, CustomEventHandler handler) { HandlerForButton = handler; EditButton.TouchUpInside += ButtonPressed; } } public class CollectionViewSource : UICollectionViewSource { public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath) { var cell = collectionView.DequeueReusableCell ("DetailCell", null) as DetailCell; cell.GetCell (indexPath.Row, ClickHandler); return cell; } private void ClickHandler (UICollectionViewCell sender, CustomEventArgs args) { var cell = sender as UICollectionViewCell; if (cell != null) { // do stuff } var yourArgs = args as CustomEventArgs; if (yourArgs != null) { // do stuff } } } internal delegate void CustomEventHandler (DetailCell sender, CustomEventArgs args);
Details refer to here.
0 comments:
Post a Comment