Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 += (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.

like image 546
Harshad Pansuriya Avatar asked Apr 27 '18 12:04

Harshad Pansuriya


People also ask

How do I subscribe to an event in a form?

For example, you might subscribe to a button's click event in order to make your application do something useful when the user clicks the button. If you cannot see the Properties window, in Design view, right-click the form or control for which you want to create an event handler, and select Properties.

How do I unsubscribe from an event?

You cannot easily unsubscribe from an event if you used an anonymous function to subscribe to it. To unsubscribe in this scenario, go back to the code where you subscribe to the event, store the anonymous function in a delegate variable, and then add the delegate to the event.

How to add button onClick event process in Xcode?

Create an Xcode project with the name ButtonLabelExample. Open the Main.storyboard file, then click Library icon in the top right corner to open the UI views library panel. In the library panel, search the keyword button and drag the button into Main.storyboard. Do the same to add a Label view. 2. Add Button onClick Event Process Method.

What happens when you unsubscribe from a multicast event?

Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds that reference, garbage collection will not delete your subscriber object.


1 Answers

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();
    }
like image 62
Harshad Pansuriya Avatar answered Oct 02 '22 03:10

Harshad Pansuriya