I'm trying to make an app for people of my student dancing association to find a dance partner. It's been a fun project during corona. Everything is done in ASP Core 5 and Xamarin Forms, and it's almost ready for testing. However, I'm having some trouble with the chat UI. When I use a CollectionView in Forms, it loads very slowly, due to rendering performance (at least on Android, iOS is generally much faster). To solve that I tried creating it as a view and use native renderers for iOS and Android. With Android, I simply used a NuGet package (XamarinLibrary.Xamarin.AndroidX.ChatKit), but for iOS I could find no such package. There's a native SwiftUI package (MessageKit), though I don't know how to wrap that (and the documentation is a lot). So I started to instead write it in Xamarin iOS. My test loads really quickly, although I'm now struggling with the layout of the Collection and the ViewCell. Could someone show me how to create message cells that fill the horizontal space?
Thanks in advance! :)
This is what it looks like right now:
Screenshot
[UPDATE] I partially solved the issue by adding this (though it does not work in the constructor):
Screenshot 2
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds) {
MinimumLineSpacing = 10;
MinimumInteritemSpacing = 10;
SectionInset = new UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10);
ItemSize = new CGSize(width: (newBounds.Width - 20), height: 100);
return true;
}
My code currently (the data source isn't correct yet):
public class MessageListLayout : UICollectionViewFlowLayout {
public MessageListLayout() {
ItemSize = new CGSize(UIScreen.MainScreen.Bounds.Size.Width, 50);
EstimatedItemSize = AutomaticSize;
}
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds) {
return true;
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath path) {
return base.LayoutAttributesForItem(path);
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect) {
return base.LayoutAttributesForElementsInRect(rect);
}
}
public class MessageListDataSource : UICollectionViewDataSource {
private string CellId { get; set; }
#region Computed Properties
public UICollectionView CollectionView { get; set; }
public List<int> Numbers { get; set; } = new List<int>();
#endregion
#region Constructors
public MessageListDataSource(UICollectionView collectionView, string cellId) {
// Initialize
CollectionView = collectionView;
CellId = cellId;
// Init numbers collection
for (int n = 0; n < 100; ++n) {
Numbers.Add(n);
}
}
#endregion
#region Override Methods
public override nint NumberOfSections(UICollectionView collectionView) {
// We only have one section
return 1;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section) {
// Return the number of items
return Numbers.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) {
// Get a reusable cell and set {~~it's~>its~~} title from the item
var cell = collectionView.DequeueReusableCell(CellId, indexPath) as MessageListViewCell;
cell.Text = Numbers[(int)indexPath.Item].ToString();
return cell;
}
public override bool CanMoveItem(UICollectionView collectionView, NSIndexPath indexPath) {
// We can always move items
return true;
}
public override void MoveItem(UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath) {
// Reorder our list of items
var item = Numbers[(int)sourceIndexPath.Item];
Numbers.RemoveAt((int)sourceIndexPath.Item);
Numbers.Insert((int)destinationIndexPath.Item, item);
}
#endregion
}
So this should be the base message bubble.
public class MessageListViewCell : UICollectionViewCell {
UIImageView imageView;
public string Text { get; set; }
[Export("initWithFrame:")]
public MessageListViewCell(CGRect frame) : base(frame) {
BackgroundView = new UIView { BackgroundColor = UIColor.Orange };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
//ContentView.Transform = CGAffineTransform.MakeScale(1, 1);
ContentView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
imageView = new UIImageView(UIImage.FromBundle("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f);
ContentView.AddSubview(imageView);
}
public UIImage Image {
set {
imageView.Image = value;
}
}
[Export("custom")]
public void Custom() {
// Put all your custom menu behavior code here
Console.WriteLine("custom in the cell");
}
public override bool CanPerform(Selector action, NSObject withSender) {
if (action == new Selector("custom"))
return true;
else
return false;
}
}
[assembly: ExportRenderer(typeof(MessagesListControl), typeof(MessagesListControlRenderer))]
namespace Vinder.iOS.UI.Renderers {
public class MessagesListControlRenderer : ViewRenderer<MessagesListControl, UICollectionView> {
static readonly NSString messageListViewCell = new("MessageListViewCell");
private UICollectionView collectionView { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<MessagesListControl> e) {
base.OnElementChanged(e);
if (e.OldElement != null) {
// Unsubscribe to events
}
if (e.NewElement != null) {
if (Control == null) {
collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new MessageListLayout());
collectionView.RegisterClassForCell(typeof(MessageListViewCell), messageListViewCell);
collectionView.BackgroundColor = UIColor.Blue; // blue is easy for seeing the correct bounds
collectionView.DataSource = new MessageListDataSource(collectionView, messageListViewCell);
SetNativeControl(collectionView);
}
// Subscribe to events
}
}
}
}
Related
I'm trying to implement a pickview object instead of the keyboard on xamarin.ios, I found something on the net but they are not for me. I have to enter a numeric value, required on a TextField which when clicked instead of the standard keyboard will show my pickview. And it will insert it in the field to forward it afterwards to the php script for an insertion on a data base. I developed this code but I'm stuck, I humbly ask you for help :(
Please only c# code, if you would help me.
I display the Picker with my list but when I have to go to retrieve the data and insert it somewhere for example in the Textfield or in a variable to save it and send it to the PHP script I can't get the selected value!
public override void ViewDidLoad()
{
base.ViewDidLoad();
//gesture torna indietro
var BackGesture = new UISwipeGestureRecognizer(swipe);
BackGesture.Direction = UISwipeGestureRecognizerDirection.Right;
BackGesture.NumberOfTouchesRequired = 1;
View.AddGestureRecognizer(BackGesture);
//evento torna indietro
void swipe(UISwipeGestureRecognizer sw1)
{
//torno indietro
apriStoryBoard("Home");
}
var list = new List<string> { "1", "2" };
ConfigurePicker(list);
// picker.Model = colorsViewModel;
}
void ConfigurePicker(List<string> list)
{
var pickerTextField = new UITextField();
var picker = new UIPickerView();
picker.Model = new ColorsViewModel(list);
var screenWidth = UIScreen.MainScreen.Bounds.Width;
var pickerToolBar = new UIToolbar(new RectangleF(0, 0, (float)screenWidth, 44)) { BarStyle = UIBarStyle.Default, Translucent = true };
var flexibleSpaceButton = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
var doneButton = new UIBarButtonItem(UIBarButtonSystemItem.Done, (sender, e) => Rips1.ResignFirstResponder());
pickerToolBar.SetItems(new[] { flexibleSpaceButton, doneButton }, false);
var colorsViewModel = new ColorsViewModel(list);
colorsViewModel.ColorChange += (sender, e) =>
{
Rips1.Text = colorsViewModel.SelectedColor;
};
Rips1.InputView = picker;
Rips1.InputAccessoryView = pickerToolBar;
}
PickviewModel class:
class ColorsViewModel : UIPickerViewModel
{
List<string> list;
public event EventHandler ColorChange;
public string SelectedColor { get; private set; }
public override System.nint GetRowsInComponent(UIPickerView pickerView, nint component) //non e uguale
{
return list.Count;
}
public ColorsViewModel(List<string> list)
{
this.list = list;
}
public override System.nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
public override string GetTitle(UIPickerView pickerView, nint row, nint component)
{
return list[(int)row];
}
//controla la selezione attuale
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
var color = list[(int)row];
SelectedColor = color;
ColorChange?.Invoke(null, null);
}
public string getValore(nint row)
{
return list[(int)row];
}
}
I am making an app for iOS using Xamarin I had some trouble with UITableViews and found this tutorial: https://learn.microsoft.com/en-us/xamarin/ios/user-interface/controls/tables/populating-a-table-with-data
I created a new project and followed what they did, but it doesn't work for me. I must be doing something wrong, but I can't figure out what.
Could someone take a look and see why the TableView doesn't show up?
BasicViewController:
public class BasicTableViewController : UIViewController
{
private UIView view;
public override void ViewDidLoad()
{
base.ViewDidLoad();
var table = new UITableView(View.Bounds);
table.Source = new BasicTableSource("aaaaaaaaa", "bbbbb", "cccccccc", "ddddddddddddd", "eeeee");
Add(table);
}
public override void LoadView()
{
view = new UIView()
{
BackgroundColor = UIColor.White,
};
View = view;
}
}
BasicTableViewSource:
public class BasicTableSource : UITableViewSource
{
private readonly string[] items;
public BasicTableSource(params string[] items)
{
this.items = items;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("cell");
if (cell == null)
cell = new UITableViewCell(UITableViewCellStyle.Default, "cell");
cell.TextLabel.Text = items[indexPath.Row];
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return items.Length;
}
}
AppDelegate:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
Window.RootViewController = new BasicTableViewController();
Window.MakeKeyAndVisible();
return true;
}
}
What the simulator looks like when running this project:
What the simulator looks like
Cause:
When you override the method LoadView.It seems that you forgot to set the Frame of view.So the size of view will with Height as 0 and Width as 0.
Solution:
Set the frame of view as the size of screen.
public override void LoadView()
{
view = new UIView()
{
Frame = UIScreen.MainScreen.Bounds,
BackgroundColor = UIColor.White,
};
View = view;
}
I have a custom Listview, each row contains one textviewand one checkbox. I am saving the value (or the text) of the selected row's textview in a public list named usercoin. Each time the user opens the app, the list usercoin will contain the text of the his textview selected items, and I am doing that using SQLite. The problem is I want to re-check the items which the usaer have previously selected which are available in the usercoin list. I am not able to do so.
MyActivity.cs
ListView mListView;
MyAdapter adapter;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
mListView = FindViewById<ListView>(Resource.Id.listview);
List<TableList> list = new List<TableList>();
list.Add(new TableList("Germany",false));
list.Add(new TableList("France", false));
list.Add(new TableList("Finland", false));
list.Add(new TableList("Germany", false));
list.Add(new TableList("France", false));
list.Add(new TableList("Germany", false));
list.Add(new TableList("France", false));
list.Add(new TableList("Finland", false));
adapter = new MyAdapter(this, list);
mListView.Adapter = adapter;
mListView.ItemClick += MListView_ItemClick;
}
private void MListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
var t = list[e.Position];
string selected = t.name;
var ll = e.View as LinearLayout;
var cb = ll.GetChildAt(2) as CheckBox;
if (cb.Checked)
{
cb.Checked = false;
adapter.changeState((int)cb.Tag, false);
}
else
{
cb.Checked = true;
adapter.changeState((int)cb.Tag, true);
}
}
class MyAdapter : BaseAdapter
{
Context mContext;
List<TableList> mitems;
public MyAdapter(Context context, List<TableList> list)
{
this.mContext = context;
this.mitems = list;
}
public override int Count
{
get
{
return mitems.Count;
}
}
public override Java.Lang.Object GetItem(int position)
{
return mitems[position];
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
DataViewHolder holder = null;
if (convertView == null)
{
convertView = LayoutInflater.From(mContext).Inflate(Resource.Layout.CoinList, null, false);
holder = new DataViewHolder();
holder.tv = convertView.FindViewById<TextView>(Resource.Id.CoinName);
holder.iv = convertView.FindViewById<ImageView>(Resource.Id.imageView1);
holder.cb = convertView.FindViewById<CheckBox>(Resource.Id.checkBox1);
convertView.Tag = holder;
}
else
{
holder = convertView.Tag as DataViewHolder;
}
holder.cb.Tag = position;
holder.tv.Text = mitems[position].Name;
holder.cb.Focusable = false;
holder.cb.Checked = mitems[position].bl;
holder.iv.SetImageResource(Resource.Drawable.dapao);
holder.cb.CheckedChange += Cb_CheckedChange;
return convertView;
}
private void Cb_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
{
var cb = sender as CheckBox;
if (e.IsChecked && !mitems[(int)cb.Tag].bl)
{
mitems[(int)cb.Tag].bl = true;
this.NotifyDataSetChanged();
}
else if (!e.IsChecked && mitems[(int)cb.Tag].bl)
{
mitems[(int)cb.Tag].bl = false;
this.NotifyDataSetChanged();
}
}
internal void changeState(int tag, bool v)
{
mitems[tag].bl = v;
this.NotifyDataSetChanged();
}
}
public class DataViewHolder : Java.Lang.Object
{
public ImageView iv { get; set; }
public TextView tv { get; set; }
public CheckBox cb { get; set; }
}
public class TableList : Java.Lang.Object
{
private string v;
public TableList(string name, bool b)
{
this.Name = name;
this.bl = b;
}
public string Name { get; set; }
public bool bl { get; set; }
}
}
}
For example, when the user run the app and select France and Germany from the listview, next time he opens the app, the usercoin list will contain France and Germany. Now the question is how can I check the checkboxes corresponding to those values in the listview. I have tried to do so by including this code in MyAdapter : BaseAdapter class:
if (Class1.usercoin.Contains(item.CoinAbr))
{
Class1.adapter[(int)holder.cb.Tag].bl = true;
this.NotifyDataSetChanged();
}
But when this code get executed, the previously checked items are checked plus some other items which the user haven't checked previously are also checked. So how can I check the previously checked items in the Listview on the app start ? Please help me to find a solution.
I have stored the data(useritems) in both DataBase and memory.
If your app is killed by system or user, you can restore the data from DataBase.
If your app isn't killed by system or user, but user jump to other activity, when he back to this activity, you can use memory to restore the data.
About DataBase, I am use SQLite.Net. I am using DBHelper to operation the DataBase.
And I have add Application class in the app.
I have update the demo. Here is gif.
When we enter value in row 1 the value entered in row 1 is appearing back in row 6 when we scroll to the row 6. Please see the below code and advice.
namespace Kites
{
public class Marks
{
// add any if you need more
public string StudentName { get; set; }
public string MarksScored { get; set; }
}
public class TEXTCHECK
{
public int POS { get; set; }
public string Value { get; set; }
}
public class MarksListViewAdapter : BaseAdapter<Marks>
{
private List<Marks> mstuduentmarks;
private List<TEXTCHECK> abc = new List<TEXTCHECK>();
private Context mcontext;
public MarksListViewAdapter (Context context, List<Marks> stud)
{
mstuduentmarks = stud;
mcontext = context;
}
public override int Count
{
get
{
return mstuduentmarks.Count;
// return mattendence.Count;
}
}
public override long GetItemId (int position)
{
return position;
}
public override Marks this[int position]
{
get
{
return mstuduentmarks [position];
// return mattendence [position];
}
}
class ViewHolder : Java.Lang.Object
{
public EditText comsevin;
public TextView namenmn;
}
public override View GetView (int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
View view = convertView;
if (view == null) // otherwise create a new one
{
view = LayoutInflater.From(mcontext).Inflate(Resource.Layout.listview_Marks, null, false);
holder = new ViewHolder();
holder.comsevin = view.FindViewById<EditText>(Resource.Id.editTextTeacherMarks);
holder.namenmn = view.FindViewById<TextView>(Resource.Id.textStudentNameTeacherMarks);
holder.namenmn.Tag = position;
view.Tag = holder;
}
else
{
holder = (ViewHolder)view.Tag;
}
holder.namenmn.Text = mstuduentmarks[position].StudentName;
int pos = (int)holder.namenmn.Tag;
holder.comsevin.TextChanged += (sender, e) =>
{
abc[pos].Value = holder.comsevin.Text;
};
//TextView txtStudent =
//txtStudent.Text = mstuduentmarks[position].StudentName;
//txtMarks.FocusChange += (object sender, View.FocusChangeEventArgs e) =>
//{
// //txtMarks.RequestFocusFromTouch ();
// mstuduentmarks[position].MarksScored = txtMarks.Text;
//};
holder.comsevin.BeforeTextChanged += (sender, e) =>
{
abc.Add(new TEXTCHECK { POS = position, Value = mstuduentmarks[position].MarksScored });
};
holder.comsevin.AfterTextChanged += (sender, e) =>
{
int a = abc[pos].POS;
mstuduentmarks[pos].MarksScored = abc[pos].Value;
};
//txtMarks.Tag = position;
//txtMarks.TextChanged += TxtMarks_TextChanged;
return view;
}
//void TxtMarks_TextChanged (object sender, Android.Text.TextChangedEventArgs e)
//{
// EditText txtMarks = (EditText)sender;
// //var position = (int)txtMarks.Tag;
//}
}
}
When we enter value in row 1 the value entered in row 1 is appearing back in row 6 when we scroll to the row 6. Please see the below code and advice.
As a rule of thumb, when experiencing lists that don't reflect the dataset (experiencing item repetition for example) in listview / recyclerview it means that you're either using dirty views which were previously used and then uncorrectly Re-Bound, or simply using wrong positions during bind
I see where you are getting it wrong:
if (view == null) // otherwise create a new one
{
view = LayoutInflater.From(mcontext).Inflate(Resource.Layout.listview_Marks, null, false);
holder = new ViewHolder();
holder.comsevin = view.FindViewById<EditText>(Resource.Id.editTextTeacherMarks);
holder.namenmn = view.FindViewById<TextView>(Resource.Id.textStudentNameTeacherMarks);
holder.namenmn.Tag = position;//<------------here!!!
view.Tag = holder;
}
TLDR Don't save positions this way.
Whats happening: this instance of your view is being reused by listView, meaning that sometimes (many times) if (view == null) will be false and this means Tag property will not be updated for row 6 (or any other calls that will use recycled Views) and you are in fact using a dirty value.
You are then trying to use the Tag property as position, but forgetting this tag is already dirty if the view was recycled
int pos = (int)holder.namenmn.Tag;
holder.comsevin.TextChanged += (sender, e) =>
{
abc[pos].Value = holder.comsevin.Text;
};
Since you have access to the position in this method call you should use it directly
take a look at this guide from Java Code geeks even though it's in Java you will be able to see a good implementation of the old ViewHolder/ListView pattern.
Hope this helps
I have subclassed UITableView with the required methods overridden in the subclass to populate the table view. However while NumberOfSections is called, NumberOfRowsInSection is not called.
The code below is from a Xamarin project but this is no different to its equivalent native version with slight differences in method names.
partial class ShootsTable : UITableView, IUISearchResultsUpdating, IUISearchBarDelegate
{
public bool History { get; set; }
public UIViewController Parent { get; set; }
private Bootleg.API.Event[] Events { get; set; }
private List<nint> ExpandedSections { get; }
public ShootsTable (IntPtr handle) : base (handle)
{
ExpandedSections = new List<nint> ();
SetEvents();
}
private void SetEvents()
{
if (History) {
Events = AppDelegate.Api.GetShootHistory ().ToArray();
} else {
Events = AppDelegate.Api.MyEvents.ToArray();
}
}
private void AddRefreshControl()
{
var refreshControl = new UIRefreshControl ();
refreshControl.AttributedTitle = new NSAttributedString ("Pull to refresh");
refreshControl.AddTarget (async delegate(object sender, EventArgs e) {
await AppDelegate.Api.RefreshEvents();
SetEvents();
ReloadData();
refreshControl.EndRefreshing();
}, UIControlEvent.ValueChanged);
AddSubview (refreshControl);
}
private void AddSearchControl()
{
var searchControl = new UISearchController (Parent);
searchControl.SearchResultsUpdater = this;
searchControl.SearchBar.Delegate = this;
TableHeaderView = searchControl.SearchBar;
}
public void UpdateSearchResultsForSearchController (UISearchController searchController)
{
SetEvents ();
Events = Events.Where (e => e.name.Contains (searchController.SearchBar.Text)).ToArray ();
ReloadData ();
}
public override nint NumberOfSections ()
{
if (Events != null && Events.Length > 0)
{
SeparatorStyle = UITableViewCellSeparatorStyle.SingleLine;
return Events.Length;
}
var label = new UILabel (new CGRect (Bounds.X, Bounds.Y, Bounds.Size.Width, Bounds.Size.Height));
label.Text = History ? "You have not contributed to any shoots yet." : "No shoots available.";
label.Lines = 2;
label.TextAlignment = UITextAlignment.Center;
BackgroundView = label;
SeparatorStyle = UITableViewCellSeparatorStyle.None;
return 0;
}
public override nint NumberOfRowsInSection (nint section)
{
var e = Events[section];
if (e.group == null)
{
return 1;
}
return ExpandedSections.Contains (section) ? e.events.Count : 0;
}
[Export ("tableView:heightForHeaderInSection:")]
public System.nfloat GetHeightForHeader (UIKit.UITableView tableView, System.nint section)
{
return Events [section].group == null ? 0 : tableView.SectionHeaderHeight;
}
[Export ("tableView:viewForHeaderInSection:")]
public UIKit.UIView GetViewForHeader (UIKit.UITableView tableView, System.nint section)
{
var e = Events [section];
if (e.group == null)
{
return null;
}
var cell = (ShootGroupCell) tableView.DequeueReusableCell (ShootGroupCell.Key);
cell.Event = e;
cell.AddGestureRecognizer (new UITapGestureRecognizer(() => {
if (ExpandedSections.Contains(section))
{
ExpandedSections.Remove(section);
tableView.ReloadSections(new NSIndexSet((nuint) section), UITableViewRowAnimation.Automatic);
} else {
ExpandedSections.Add(section);
tableView.ReloadSections(new NSIndexSet((nuint) section), UITableViewRowAnimation.Automatic);
}
}));
return cell.ContentView;
}
public override UITableViewCell CellAt (NSIndexPath ns)
{
var e = Events[ns.Section];
e = e.group == null ? e : e.events[ns.Row];
if (History) {
var cell = (ShootCell)DequeueReusableCell (ShootCell.Key);
cell.Event = e;
cell.Parent = Parent;
return cell;
} else {
var cell = (ShootJoinCell) DequeueReusableCell (ShootJoinCell.Key);
cell.Event = e;
return cell;
}
}
[Export ("tableView:heightForRowAtIndexPath:")]
public System.nfloat GetHeightForRow (UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
return Events [indexPath.Section].group == null || ExpandedSections.Contains (indexPath.Section) ? tableView.RowHeight : 0;
}
[Export ("tableView:didSelectRowAtIndexPath:")]
public async void RowSelected (UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
if (!History)
{
var e = Events [indexPath.Section];
if (e.group != null) {
e = e.events [indexPath.Row];
}
MBHUDView.HudWithBody ("Connecting Event...", MBAlertViewHUDType.ActivityIndicator, 0, true);
await AppDelegate.Api.ConnectToEvent (e, false);
MBHUDView.DismissCurrentHUD ();
if (AppDelegate.Api.CurrentEvent.id != e.id)
{
var alert = UIAlertController.Create ("Confirm", "This event requires you to confirm you wish to join.", UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("Join", UIAlertActionStyle.Default, async delegate {
MBHUDView.HudWithBody ("Connecting Event...", MBAlertViewHUDType.ActivityIndicator, 0, true);
await AppDelegate.Api.ConnectToEvent (e, true);
MBHUDView.DismissCurrentHUD ();
e = AppDelegate.Api.CurrentEvent;
DialogHelper.PermissionsDialog (e, delegate {
Parent.PerformSegue("phasesSegue", tableView);
}, null, Parent);
}));
alert.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, null));
Parent.PresentViewController (alert, true, null);
}
else
{
e = AppDelegate.Api.CurrentEvent;
DialogHelper.PermissionsDialog (e, delegate {
Parent.PerformSegue("phasesSegue", tableView);
}, null, Parent);
}
}
}
Now I have been looking at several possible solutions however it seems quite uncommon to sub-class UITableView with the majority of solutions simply being not setting the delegate or data source properly. I have also seen a SO solution to this issue simply being the TableView not being in view and therefore the delegate methods do not need to be called however this is not the case.
I do not need to set delegate methods as I am subclassing UITableView itself and it is sufficient to just override the built in methods. In the storyboard I set the class to my custom class ShootsTable.
Does anyone have any ideas?
Thanks in advance.
This appears to be a bug. Not sure what level (Xamarin or iOS) it is at but as soon as this is changed back to a IUITableViewDataSource implementation it works.
I will report this to Xamarin and see what comes back.