我正在使用Xamarin.iOS.In TableView。我用Button绑定了Cell。
For Button Click我正在通过以下代码进行订阅和取消订阅Cell活动
cell.btn_Click.Tag = indexPath.Row;
cell.btn_Click.TouchUpInside -= BtnClickEvent;
cell.btn_Click.TouchUpInside += BtnClickEvent;
当我再次调用数据api并设置为TableView时,这不能正常工作。
说明: 当我打开ViewController第一次单元格按钮时单击事件触发1次。然后我第二次打开它会激活单元格按钮点击事件2次。我使用高级代码进行订阅和取消订阅按钮事件,然后为什么会多次调用。
我在iOS 11.2中面临的这个问题
第一种方式:
源类完整代码
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);
}
}
在ViewController内部,我使用
StockListSourceClass.BtnClickEvented += (sender, e) =>
{
if (!(serialNoList.Contains(stockLists[RowNo].SerialNo)))
serialNoList.Add(stockLists[RowNo].SerialNo);
else
serialNoList.Remove(stockLists[RowNo].SerialNo);
SetUpperPanelData();
};
第二种方式
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);
}
};
但如果我第二次打开ViewController,则会多次调用此方法。
答案 0 :(得分:4)
最后通过以下方式获得解决方案
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 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);
}
}
最后我们可以在ViewController中获取Cell按钮的单个事件
定义这种方式
stockListSourceClass.SelectButtonTapped -= OnSelectButtonTapped;
stockListSourceClass.SelectButtonTapped += OnSelectButtonTapped;
并实施它。
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();
}
答案 1 :(得分:2)
您可以尝试将该代码放在自定义单元格中,取消订阅方法PrepareForReuse
中的事件,并在将数据填充到单元格时订阅它。
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);
详情请参阅here。