I'm an absolute beginner at iOS.
I want to provide swipe-left actions on a table but even though i am setting a proper delegate subclass the EditActionsForRow method is never called on it.
Here's my code:
using System;
using UIKit;
using Foundation;
using System.Linq;
using System.Diagnostics;
namespace Tasky {
public partial class TaskyViewController : UIViewController {
TasksRepository tasksRepository;
TaskItemViewSource tasksViewSource;
public TaskyViewController (IntPtr handle) : base (handle) {
tasksRepository = new TasksRepository ();
tasksViewSource = new TaskItemViewSource ();
tasksViewSource.Data = new TaskItem[0];
tasksViewSource.DeleteClicked += HandleTaskDeleteClicked;
}
public override void ViewDidLoad () {
base.ViewDidLoad ();
TasksTable.Delegate = tasksViewSource;
TasksTable.Source = tasksViewSource;
}
public async override void ViewDidAppear (bool animated) {
base.ViewDidAppear (animated);
var tasks = await tasksRepository.GetAllTasksAsync ();
tasksViewSource.Data = tasks.ToArray ();
TasksTable.ReloadData ();
}
async void HandleTaskDeleteClicked (object sender, NSIndexPath e) {
await tasksRepository.DeleteTaskAsync (tasksViewSource.Data [e.Row]);
TasksTable.ReloadData ();
}
}
public class TaskItemViewSource : UITableViewSource, IUITableViewDelegate {
public TaskItem[] Data { get; set; }
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) {
var task = Data [indexPath.Row];
UITableViewCellStyle cellStyle;
if (String.IsNullOrEmpty (task.Description)) {
cellStyle = UITableViewCellStyle.Default;
} else {
cellStyle = UITableViewCellStyle.Subtitle;
}
var taskCell = new UITableViewCell (cellStyle, "TaskCell");
taskCell.TextLabel.Text = Data [indexPath.Row].Title;
if (!String.IsNullOrEmpty (task.Description)) {
taskCell.DetailTextLabel.Text = Data [indexPath.Row].Description;
}
return taskCell;
}
public override nint RowsInSection (UITableView tableView, nint section) {
return Data.Length;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath) {
Debug.WriteLine ("Deselected row #" + indexPath.Row);
tableView.DeselectRow (indexPath, true);
}
public event EventHandler<NSIndexPath> DeleteClicked;
public override UITableViewRowAction[] EditActionsForRow (UITableView tableView, NSIndexPath indexPath) {
Debug.WriteLine ("Inflating edit actions...");
var deleteButton = UITableViewRowAction.Create (
UITableViewRowActionStyle.Destructive,
"Delete",
(action, index) => {
if (DeleteClicked != null) {
DeleteClicked (this, index);
}
});
return new [] { deleteButton };
}
}
}
EDIT:
I managed to fuse the delegate and the view source with Jason's remark, deselecting is now working fine.
Xamarin's TableSource combines two native iOS concepts, the DataSource and the Delegate. Xamarin also provides mappings to the DataSource and Delegate classes. However, you should not mix TableSource with DataSource and Delegate.
From Xamarin's TableView docs:
If you are looking at Objective-C code or documentation, be aware that
Xamarin.iOS aggregates the UITableViewDelegate protocol and
UITableViewDataSource class into this one class. There is no
comparable UITableViewSource class or protocol in Objective-C.
Related
I am getting "The object passed of type Class.TableViewDataSource does not derive from NSObject" error when I do the following I am trying to set the datasource of a UITableView.
viewdidload {
tableView.DataSource = new TableViewDataSource(al);
}
class TableViewDataSource : IUITableViewDataSource
{
public ArrayList listOfSellers
{
get;
set;
}
public TableViewDataSource(ArrayList al) {
listOfSellers = al;
}
public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = (SellerCell)tableView.DequeueReusableCell("cell", indexPath);
cell.seller.Text = (string)listOfSellers[indexPath.Row];
return cell;
}
public nint RowsInSection(UITableView tableView, nint section)
{
return listOfSellers.Count;
}
}
Any ideas why that might be.
If the class derives from interface, you have to implement all the method defined in its parent interface.
Here the method in INativeObject , IDisposable is also needed to implement.
public class TableViewDataSource : IUITableViewDataSource
{
public IntPtr Handle { get; }
public void Dispose()
{
}
}
However, in general we use UITableViewDataSource instead . It derives from IUITableViewDataSource , we just need to override the method inside it .
public class TableViewDataSource : UITableViewDataSource
{
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = (SellerCell)tableView.DequeueReusableCell("cell", indexPath);
cell.seller.Text = (string)listOfSellers[indexPath.Row];
return cell;
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return listOfSellers.Count;
}
}
I try to manage an UICollectionView inside an UIControllerView in Xamarin.iOS.
I tried many things, like this : https://developer.xamarin.com/guides/ios/tvos/user-interface/collection-views/ or this : https://www.youtube.com/watch?v=W4H9uLjoEjM
Finally, I followed this tutorial : https://forums.xamarin.com/discussion/11274/how-to-setup-uicollectionview-datasource
But I'm still blocked. My App crash when it tries to display the UIViewController with this error : [Gotago_iOS_CollectionViewSource_ViewSourceListProgram collectionView:cellForItemAtIndexPath:]: unrecognized selector sent to instance 0x7af49db0'
Here is my code... Any help please ?
public partial class ViewControllerListProgram : UIViewController
{
private ViewSourceListProgram m_viewSource;
public ViewControllerListProgram(IntPtr handle)
: base(handle)
{
}
public override async void ViewDidLoad()
{
base.ViewDidLoad();
AppDelegate.CurrentViewController = this;
ApiController_GetListConseilCircuit apiCtrl = new ApiController_GetListConseilCircuit();
m_collectionView.RegisterClassForCell(typeof(CellListProgram), CellListProgram.Id);
m_viewSource = new ViewSourceListProgram(await apiCtrl.OnlineGetListConseilCircuit());
m_collectionView.Source = m_viewSource;
}
}
public class ViewSourceListProgram : UICollectionViewSource
{
public List<ApiController_GetListConseilCircuit.ConseilCircuit> m_lsCircuits;
public ViewSourceListProgram(List<ApiController_GetListConseilCircuit.ConseilCircuit> lsCircuits)
{
m_lsCircuits = lsCircuits;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 1;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return m_lsCircuits.Count;
}
public override bool ShouldHighlightItem(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
return true;
}
public override void ItemHighlighted(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
CellListProgram cell = (CellListProgram)collectionView.CellForItem(indexPath);
Toast.MakeText("Cell highlighted", Toast.LENGTH_LONG).Show();
}
public override void ItemUnhighlighted(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
CellListProgram cell = (CellListProgram)collectionView.CellForItem(indexPath);
Toast.MakeText("Cell unhighlighted", Toast.LENGTH_LONG).Show();
}
public UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
CellListProgram cell = (CellListProgram)collectionView.DequeueReusableCell(CellListProgram.Id, indexPath);
ApiController_GetListConseilCircuit.ConseilCircuit circuitOrProgram = m_lsCircuits[indexPath.Row];
return cell;
}
}
public partial class CellListProgram : UICollectionViewCell
{
public static readonly NSString Id = new NSString("programCell");
public CellListProgram (IntPtr handle) : base (handle)
{
}
}
Ok... After a few hours of horrible search, I found my error.
I forgot the "override" keyword here :
public UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
Should be
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
argh
Now, everything is Ok ! No crash, and user's actions are well triggered
Good evening everybody.
Case Study:
Currently I'm working on an tvos application, that needs a Netflix like vertical scroll. I found the following article that explains the approach: https://www.thorntech.com/2015/08/want-your-swift-app-to-scroll-in-two-directions-like-netflix-heres-how/
Problem:
My constructor of the class ("DashboardCollectionView.cs") isn't called, so my cells aren't intialized. In result i receive a view without any collectionviewcells, like the photo below:
Information about code and the project:
I have attached the solution as a zip file. I hope someone can help me. I'm really new on .ios so maybe it can be something easy.
http://www35.zippyshare.com/v/cTJje8WL/file.html
EDIT:
Part of Code
public partial class DashboardCollectionView : UICollectionView
{
public DashboardCollectionView (IntPtr handle) : base (handle)
{
RegisterClassForCell(typeof(DashboardCollectionViewCell), "movieCell");
DataSource = new DashboardCollectionViewDataSource();
Delegate = new DashboardCollectionViewDelegateFlowLayout();
}
}
public partial class DashboardCollectionViewCell : UICollectionViewCell
{
public DashboardCollectionViewCell (IntPtr handle) : base (handle)
{
}
}
public class DashboardCollectionViewDataSource: UIKit.UICollectionViewDataSource
{
public DashboardCollectionViewDataSource()
{
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var movieCell = (DashboardCollectionViewCell)collectionView.DequeueReusableCell("movieCell", indexPath);
return movieCell;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return 12;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 1;
}
}
public class DashboardCollectionViewDelegateFlowLayout : UIKit.UICollectionViewDelegateFlowLayout
{
public DashboardCollectionViewDelegateFlowLayout()
{
}
public override CoreGraphics.CGSize GetSizeForItem(UIKit.UICollectionView collectionView, UIKit.UICollectionViewLayout layout, Foundation.NSIndexPath indexPath)
{
var itemsPerRow = 4;
var hardCodedPadding = 10;
var itemWidth = (collectionView.Bounds.Width / itemsPerRow) - hardCodedPadding;
var itemHeight = collectionView.Bounds.Height - (2 * hardCodedPadding);
return new CoreGraphics.CGSize(itemWidth, itemHeight);
}
}
public partial class DashboardTableViewController : UITableViewController
{
private String[] categories = new String[] { "Kürzlich hinzugefügt", "Beliebt" };
private String cardCellId = "cell";
public DashboardTableViewController(IntPtr handle) : base(handle)
{
}
public override nint NumberOfSections(UITableView tableView)
{
return categories.Length;
}
public override string TitleForHeader(UITableView tableView, nint section)
{
return categories[section];
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return 1;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(cardCellId, indexPath);
return cell;
}
}
The problem is this part
3. Now for the tricky part — wiring the Collection View’s DataSource and Delegate to the cell. It’s easier if you drag from the Collection View’s Connections Inspector to the Table View Cell within the view hierarchy.
I am not sure how to do that using VS story board, you probably need to use XCode. You kind of try to do it programmatically but that doesn't work.
So if working with XCode is not an option you can trick this part and give to your DashboardCollectionView a name to force its creation. But you cannot do that without creating custom class of your "Table View Cell".
You also need to comment out
//RegisterClassForCell(typeof(DashboardCollectionViewCell), "movieCell");
After those 3 steps you should be able to see your cells. I ran it on iOS 9 simulator but couldn't get any scrolling vertical or horizontal but this is a different question.
I want to use UITableView on XamarinApp.
I tried UITableView example Populating a Table with Data ,but it doesn't work.
When i used this.Add(table); cause crash. When I remove this.Add(table) it's shows empty table.
Please help me...
Here is my code
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace KUkyuko
{
partial class MyTableViewSource : UITableView
{
public MyTableViewSource(IntPtr handle) : base (handle)
{
var table = this;
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
table.Source = new TableSource(tableItems);
this.Add(table); //this code cause crash
}
}
public class TableSource : UITableViewSource {
string[] TableItems;
string CellIdentifier = "TableCell";
public TableSource (string[] items)
{
TableItems = items;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return TableItems.Length;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
string item = TableItems[indexPath.Row];
//---- if there are no cells to reuse, create a new one
if (cell == null)
{ cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier); }
cell.TextLabel.Text = item;
return cell;
}
}
}
Im abit unsure as to what you trying to achieve but
I would change the tableview to a tableViewController like so::
partial class TableViewController : UITableViewController
{
public TableViewController (IntPtr handle) : base (handle)
{
// Register the TableView's data source
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
this.TableView.Source = new TableSource(tableItems);
}
}
public class TableSource : UITableViewSource {
string[] TableItems;
string CellIdentifier = "TableCell";
public TableSource (string[] items)
{
TableItems = items;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return TableItems.Length;
}
public override nint NumberOfSections (UITableView tableView)
{
// TODO: return the actual number of sections
return 1;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
string item = TableItems[indexPath.Row];
//---- if there are no cells to reuse, create a new one
if (cell == null)
{ cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier); }
cell.TextLabel.Text = item;
return cell;
}
}
If you are using the table inside a viewController then you need to do this part in your viewController and set up a outlet for the table.
The reason this code crashes as you are adding this to this:
var table = this;
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
table.Source = new TableSource(tableItems);
this.Add(table); //this code cause crash as it is the same as this.Add(this)
Hope this helps!
I am very new to XCode and Monotouch development. I am trying to add multiple tabs in root view (Master-Detail application). I am using Mono for development and xCode 4 for UI design. For example, one tab shows list of employees and another tab shows list of departments.
I removed the default table view in the rootviewController.xib file and replaced with tabbedview but I cant get new table view for each tab working.
I would appreciate if anyone can show me the correct way of doing this.
UPDATED: I use the code below to add 2 tabs and 2 table view. One is to hold "Securities" and the other one to hold the "Indicators"
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Collections.Generic;
namespace ChartQ
{
public partial class RootViewController : UITabBarController
{
public DetailViewController DetailVC { get; set; }
private List<SecurityInfo> listSecInfo = new List<SecurityInfo>();
private List<Indicator> listIndicator = new List<Indicator>();
public RootViewController () : base ("RootViewController", null)
{
this.Title = NSBundle.MainBundle.LocalizedString ("Securities", "Securities");
//this.ClearsSelectionOnViewWillAppear = false;
this.ContentSizeForViewInPopover = new SizeF (100f, 200f);
//this.ContentSizeForViewInPopover = new SizeF (320f, 600f);
// Custom initialization
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//Read data from Database..
UITableViewController secController = new UITableViewController();
UITableViewController IndiController = new UITableViewController();
this.AddChildViewController(secController);
this.AddChildViewController(IndiController);
SQLLiteDatabase db = new SQLLiteDatabase();
listSecInfo = db.ReadSecurities();
listIndicator = db.ReadIndicator();
//TableView.Source = new SecuritiesDataSource (this);
secController.TableView.Source = new SecuritiesDataSource (this);
secController.TableView.SelectRow (NSIndexPath.FromRowSection (0, 0), false, UITableViewScrollPosition.Middle);
IndiController.TableView.Source = new IndicatorDataSource (this);
IndiController.TableView.SelectRow (NSIndexPath.FromRowSection (0, 0), false, UITableViewScrollPosition.Middle);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return true;
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
class SecuritiesDataSource : UITableViewSource
{
static NSString cellIdentifier = new NSString ("CellId");
RootViewController controller;
public SecuritiesDataSource (RootViewController controller)
{
this.controller = controller;
}
// Customize the number of sections in the table view.
public override int NumberOfSections (UITableView tableView)
{
return 1;
}
public override int RowsInSection (UITableView tableview, int section)
{
return controller.listSecInfo.Count;
}
public override string TitleForHeader (UITableView tableView, int section)
{
return "Securities";
}
// Customize the appearance of table view cells.
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
string cellIdentifier = "Cell";
var cell = tableView.DequeueReusableCell (cellIdentifier);
if (cell == null) {
cell = new UITableViewCell (UITableViewCellStyle.Subtitle, cellIdentifier);
//Add in a detail disclosure icon to each cell
cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
}
// Configure the cell.
var sInfo = controller.listSecInfo [indexPath.Row];
cell.TextLabel.Text = String.Format ("{0}",sInfo.SecCode);
cell.DetailTextLabel.Text = sInfo.SecName;
return cell;
}
private void InfoAlert (string msg)
{
using (UIAlertView av = new UIAlertView("Info", msg, null, "OK", null)) {
av.Show ();
}
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
var sInfo = controller.listSecInfo [indexPath.Row];
controller.DetailVC.DrawChart(sInfo.SecID, sInfo.SecCode);
}
}
class IndicatorDataSource : UITableViewSource
{
static NSString cellIdentifier = new NSString ("CellId");
RootViewController controller;
public IndicatorDataSource (RootViewController controller)
{
this.controller = controller;
}
// Customize the number of sections in the table view.
public override int NumberOfSections (UITableView tableView)
{
return 1;
}
public override int RowsInSection (UITableView tableview, int section)
{
return controller.listIndicator.Count;
}
public override string TitleForHeader (UITableView tableView, int section)
{
return "Indicators";
}
// Customize the appearance of table view cells.
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
string cellIdentifier = "Cell";
var cell = tableView.DequeueReusableCell (cellIdentifier);
if (cell == null) {
cell = new UITableViewCell (UITableViewCellStyle.Subtitle, cellIdentifier);
//Add in a detail disclosure icon to each cell
cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
}
// Configure the cell.
var sInfo = controller.listIndicator [indexPath.Row];
cell.TextLabel.Text = String.Format ("{0}",sInfo.DescriptiveName);
cell.DetailTextLabel.Text = sInfo.ShortName;
return cell;
}
private void InfoAlert (string msg)
{
using (UIAlertView av = new UIAlertView("Info", msg, null, "OK", null)) {
av.Show ();
}
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
var sInfo = controller.listIndicator [indexPath.Row];
//controller.DetailVC.DrawChart(sInfo.SecID, sInfo.SecCode);
}
}
}
However, it crashes when I click the second tab. I am getting the error as below
"Got a SIGSEGV while executing native code"
The first list populated ok.
I think the UITableViewController objects are getting collected and causing your abort. Make secController and secController member variables.
public partial class RootViewController : UITabBarController
{
UITableViewController secController;
UITableViewController IndiController;
public DetailViewController DetailVC { get; set; }
...
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//Read data from Database..
secController = new UITableViewController ();
IndiController = new UITableViewController ();