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.
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.
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.
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.
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.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With