Sunday, May 6, 2018

Subscribe and Unsubscribe cell button Click event is not Working in iOS 11

Leave a Comment

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment