UICollectionView - Curious flow layout - xamarin.ios

I'm experiencing with the UICollectionView(Controller) for the first time. Actually it should be as simple as working with TableViews, it's not though.
Rather than showing all images in a flow (several rows) just the top row is displayed. All the other images are somewhere... scrolling is enabled but nothing happens, no bouncing, no scrolling, ...
And after an orientation change (and back) some more images are visible but they appear randomly. After every orientation change they appear at an other location.
My example should have 7 images.
My properties in IB:
First time:
After rotating (and back):
And my source code to implement the photo gallery.
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Collections.Generic;
using Xamarin.Media;
using MonoTouch.AssetsLibrary;
using MonoTouch.CoreGraphics;
using System.Diagnostics;
using System.Linq;
using System.Drawing;
namespace B2.Device.iOS
{
public partial class TagesRapportDetailRegieBilderCollectionViewController : UICollectionViewController
{
private const string Album = "Rapport";
public TagesRapportDetailRegieBilderSource Source { get; private set; }
private TagesRapportDetailRegieBilderDelegate _delegate;
public TagesRapportDetailRegieBilderCollectionViewController (IntPtr handle) : base (handle)
{
Source = new TagesRapportDetailRegieBilderSource(this);
_delegate = new TagesRapportDetailRegieBilderDelegate(this);
// Delegate - Muss im konstruktor sein. ViewDidLoad geht nicht!
CollectionView.Delegate = _delegate;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Cell Klasse registrieren
CollectionView.RegisterClassForCell (typeof(ImageCell), new NSString("imageCell"));
// DataSource
CollectionView.Source = Source;
// Bilder laden
LoadImages();
}
private void LoadImages()
{
Source.Images.Clear();
var assetsLibrary = new ALAssetsLibrary();
assetsLibrary.Enumerate(ALAssetsGroupType.Album, GroupsEnumeration, GroupsEnumerationFailure);
}
private void GroupsEnumeration(ALAssetsGroup group, ref bool stop)
{
if (group != null && group.Name == Album)
{
//notifies the library to keep retrieving groups
stop = false;
//set here what types of assets we want,
//photos, videos or both
group.SetAssetsFilter(ALAssetsFilter.AllPhotos);
//start the asset enumeration
//with ALAssetsGroup's Enumerate method
group.Enumerate(AssetsEnumeration);
CollectionView.ReloadData();
}
}
private void AssetsEnumeration(ALAsset asset, int index, ref bool stop)
{
if (asset != null)
{
//notifies the group to keep retrieving assets
stop = false;
//use the asset here
var image = new UIImage(asset.AspectRatioThumbnail());
Source.Images.Add(image);
}
}
private void GroupsEnumerationFailure(NSError error)
{
if (error != null)
{
new UIAlertView("Zugriff verweigert", error.LocalizedDescription, null, "Schliessen", null).Show();
}
}
}
public class TagesRapportDetailRegieBilderDelegate : UICollectionViewDelegateFlowLayout
{
private TagesRapportDetailRegieBilderCollectionViewController _controller;
public TagesRapportDetailRegieBilderDelegate(TagesRapportDetailRegieBilderCollectionViewController controller)
{
_controller = controller;
}
public override System.Drawing.SizeF GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
{
var size = _controller.Source.Images[indexPath.Row].Size.Width > 0
? _controller.Source.Images[indexPath.Row].Size : new SizeF(100, 100);
size.Width /= 3;
size.Height /= 3;
return size;
}
public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout, int section)
{
return new UIEdgeInsets(50, 20, 50, 20);
}
}
public class TagesRapportDetailRegieBilderSource : UICollectionViewSource
{
private TagesRapportDetailRegieBilderCollectionViewController _controller;
public List<UIImage> Images { get; set; }
public TagesRapportDetailRegieBilderSource(TagesRapportDetailRegieBilderCollectionViewController controller)
{
_controller = controller;
Images = new List<UIImage>();
}
public override int NumberOfSections(UICollectionView collectionView)
{
return 1;
}
public override int GetItemsCount(UICollectionView collectionView, int section)
{
return Images.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = collectionView.DequeueReusableCell(new NSString("imageCell"), indexPath) as ImageCell;
cell.Image = Images[indexPath.Row];
return cell;
}
}
public class ImageCell : UICollectionViewCell
{
UIImageView imageView;
[Export ("initWithFrame:")]
public ImageCell (System.Drawing.RectangleF frame) : base (frame)
{
imageView = new UIImageView(frame);
imageView.AutoresizingMask = ~UIViewAutoresizing.None;
ContentView.AddSubview (imageView);
}
public UIImage Image
{
set
{
imageView.Image = value;
}
}
}
}

If all you want to do is displaying the cells in an uniform grid, overriding GetSizeForItem shouldn't be necessary in the first place. Just configure the cellsize property of your flow layout either in IB or programatically during ViewDidLoad and be done with it.
There's another problem with your code:
group.Enumerate(AssetsEnumeration)
This will run asynchronously. That means:
CollectionView.ReloadData();
Will only cover a small subset of your images. It would be better to issue a ReloadData() when group == null, which indicates that the enumeration is complete.
You could also avoid ReloadData alltogether and call CollectionView.InsertItem() everytime you've added an image. This has the benefit of your items become immediately visible instead of all of them at once after everything has been enumerated - which may take some time (on the device). The downside is that you've got to be careful to not run into this.

Related

How to implement UICollectionView - XAMARIN.IOS

I'm trying to use UICollectionView but I can't find any samples that I can take advantage of. I needed the UICollectionView by code (without using swift/storyboard/forms). Could you give me a really simple example? For example 2 lines with 2 columns please? Basic stuff just to try to understand how I can implement it.
Thank you
You can refer to Collection Views in Xamarin.iOS doc to check how to use Collection View with Code .And here I will show a sample code to explain how to implement it .
Could you give me a really simple example? For example 2 lines with 2 columns please?
First , need to create a GridLayout :
public class GridLayout : UICollectionViewFlowLayout
{
public GridLayout ()
{
}
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);
}
}
Then you can init the Collection View in ViewDidLoad :
static NSString animalCellId = new NSString("AnimalCell");
List<IAnimal> animals;
animals = new List<IAnimal>();
for (int i = 0; i < 2; i++)
{
animals.Add(new Monkey());
}
// Perform any additional setup after loading the view, typically from a nib.
UICollectionView collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new GridLayout());
collectionView.RegisterClassForCell(typeof(AnimalCell), animalCellId);
collectionView.BackgroundColor = UIColor.Blue;
collectionView.DataSource = new MyCollectionViewDataDelegate(animals);
View.AddSubview(collectionView);
Here you also need to creat a Custom Cell for your needs , this can be modified by yourself :
public class AnimalCell : UICollectionViewCell
{
UIImageView imageView;
[Export("initWithFrame:")]
public AnimalCell(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(0.8f, 0.8f);
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")]
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;
}
}
The MyCollectionViewDataDelegate also need to be created:
public class MyCollectionViewDataDelegate : UICollectionViewDataSource
{
private List animals;
public MyCollectionViewDataDelegate(List<IAnimal> animals)
{
this.animals = animals;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 2;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return animals.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell(animalCellId, indexPath);
var animal = animals[indexPath.Row];
animalCell.Image = animal.Image;
return animalCell;
}
}
You can find that animalCell should be registed when init Collection View .
Then effect :
This is the sample link for reference .

Why is my view controller showing blank screen after a push and its very slow on simulator?

View Controller blank when pushing using this method if you look at the rowslected method im pushing the chat view controller but for some reason the view is being very slow in the simulator and coming through just blank none of the controls are loaded on it.
Any ideas what is up??? I just dunno why the view would act slow also what is the best way of dealing with this if I was to be loading a parse object in ordinary .net I would normally pass the entity as parameter of form is it the same here ?
using System;
using MonoTouch.UIKit;
using System.Drawing;
using Xamarin.Contacts;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using MonoTouch.Foundation;
using System.Globalization;
using System.Threading.Tasks;
namespace ExampleProject3
{
partial class mychatcontroller : UITableViewController
{
List<Contact> list;
private UIAlertView alert;
UIDetailsChatView chatController;
public mychatcontroller (IntPtr handle) : base (handle)
{
list = new List<Contact>();
//
// get the address book, which gives us access to the
// the contacts store
//
var book = new AddressBook ();
book.RequestPermission().ContinueWith (t =>
{
if (!t.Result)
{
alert = new UIAlertView ("Permission denied", "User has denied this app access to their contacts", null, "Close");
alert.Show();
}
else
{
foreach (Contact contact in book.Take(10))
{
list.Add(contact);
}
mychat.DataSource = new TableViewDataSource (list);
mychat.ReloadData();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//
// simple table view data source using the List<Contact> as the datasource
//
private class TableViewDataSource : UITableViewDataSource
{
static NSString cellIdentifier = new NSString ("contactIdentifier");
private List<Contact> list;
public TableViewDataSource (List<Contact> list)
{
this.list = list;
}
public override int RowsInSection (
UITableView tableview, int section)
{
return list.Count;
}
public override UITableViewCell GetCell (
UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (
UITableViewCellStyle.Default,
cellIdentifier);
}
cell.TextLabel.Text = list[indexPath.Row].DisplayName;
cell.ImageView.Image =list [indexPath.Row].GetThumbnail () ;
Email firstEmail = list[indexPath.Row].Emails.FirstOrDefault();
if(firstEmail != null)
{
cell.DetailTextLabel.Text = String.Format("{0}: {1}", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(firstEmail.Label), firstEmail.Address);
}
return cell;
}
}
public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
//WHAT TO DO HERE
UIDetailsChatView myDetail = new UIDetailsChatView();
NavigationController.PushViewController (myDetail, true);
tableView.DeselectRow (indexPath, true); // normal iOS behaviour is to remove the blue highlight
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
}
}
}
chat view controller
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.CodeDom.Compiler;
namespace ExampleProject3
{
partial class UIDetailsChatView : UIViewController
{
public UIDetailsChatView (IntPtr handle) : base (handle)
{
}
public UIDetailsChatView ()
{
}
}
}

How to reflect changes in viewmodel to tableviewcell view with binding in MVVMcross

Am a little stuck with getting changes reflected from the ViewModel to the View when used in a MvxBindableTableViewCell. I am using the vNext branch of MvvmCross on iOS.
Everything is set up properly and the initial values are visible when loading/showing the list for the first time. The list is a ObservableCollection<T> and the ViewModels inherit from MvxViewModel (thus implements INotifyPropertyChanged).
The main ViewModel looks like this:
public abstract class BaseViewModel : MvxViewModel, IMvxServiceConsumer
{
//... just regular implementation
}
public class UploadListViewModel: BaseViewModel
{
private readonly IUploadItemTasks uploadItemTasks;
private readonly IPhotoPickerService photoPickerService;
public IObservableCollection<UploadItemViewModel> Uploads { get { return this.LoadUploadItems(); } }
public UploadListViewModel()
{
this.uploadItemTasks = this.GetService<IUploadItemTasks>();
this.photoPickerService = this.GetService<IPhotoPickerService>();
}
private IObservableCollection<UploadItemViewModel> LoadUploadItems()
{
using (var unitOfWork = UnitOfWork.Start ())
{
return new SimpleObservableCollection<UploadItemViewModel>(uploadItemTasks.GetAll());
}
}
public void StartUpload ()
{
if (this.Uploads == null || this.Uploads.Count == 0) {
ReportError("Error", "No images to upload");
return;
}
this.Uploads.ForEach (uploadItem => PostCallback (uploadItem));
}
private void PostCallback (UploadItemViewModel uploadAsset)
{
IProgressReporter progressReporter = uploadAsset;
this.photoPickerService.GetAssetFullImage(uploadAsset.ImageUrl,
(image) => {
UIImage fullImage = image;
NSData jpeg = fullImage.AsJPEG();
byte[] jpegBytes = new byte[jpeg.Length];
System.Runtime.InteropServices.Marshal.Copy(jpeg.Bytes, jpegBytes, 0, Convert.ToInt32(jpeg.Length));
MemoryStream stream = new MemoryStream(jpegBytes);
Uri destinationUrl = new Uri(uploadAsset.DestinationUrl + "&name=" + uploadAsset.Name + "&contentType=image%2FJPEG");
//TO DO: Move this to plugin
var uploader = new Uploader().UploadPicture (destinationUrl, stream, UploadComplete, progressReporter);
uploader.Host = uploadAsset.Host;
ThreadPool.QueueUserWorkItem (delegate {
uploader.Upload ();
jpeg = null;
});
});
}
private void UploadComplete (string name)
{
if (name == null){
ReportError("Error","There was an error uploading the media.");
} else
{
//ReportError("Succes", name);
}
}
The item ViewModel looks like:
public interface IProgressReporter
{
float Progress { get; set;}
}
public abstract class BaseAssetViewModel: BaseViewModel, IBaseAssetViewModel
{
//... just regular properties
}
public class UploadItemViewModel: BaseAssetViewModel, IProgressReporter
{
public UploadItemViewModel(): base()
{
}
private float progress;
public float Progress {
get {
return this.progress;
}
set {
this.progress = value;
this.RaisePropertyChanged(() => Progress);
}
}
}
The View for the items inherits from MvxBindableTableViewCell and has the property:
private float progress;
public float ProgressMarker {
get {
return progress;
}
set {
progress = value;
// change progressbar or textfield here
}
}
The tableviewcell is bounded to the UploadItemViewModel via the BindingText:
public const string BindingText = #"ProgressMarker Progress, Converter=Float;";
The Uploader class mentioned in the snippet of UploadListViewModel implements a private method which tries to set the progress on the IProgressReporter.
float progressValue;
void SetProgress (float newvalue)
{
progressValue = newvalue;
this.dispatcher.InvokeOnMainThread (delegate {
if (ProgressReporter != null)
ProgressReporter.Progress = progressValue;
});
}
During the first viewing of the list I can see that the properties in both the ViewModel and View are being hit but when I update the ViewModel via the interface IProgressReporter with a new value in Progress the View in the tableviewcell is not updated nor the property is being called.
What am I doing wrong or what am I missing here?
UPDATE: Check the answer to this question.
I found why the binding didn't work. I was replacing the ObservableCollection over and over again.. I changed that piece of code as stated below and now it reflects the changes made to the UploadItemViewModel in the View of the cell.
private IObservableCollection<UploadItemViewModel> uploads;
private IObservableCollection<UploadItemViewModel> LoadUploadItems()
{
if (uploads == null)
{
using (var unitOfWork = UnitOfWork.Start ())
{
uploads = new SimpleObservableCollection<UploadItemViewModel>(uploadItemTasks.FindAll());
}
}
return uploads;
}

Monotouch UITableView image "flashing" while background requests are fetched

I am in need of some help from you guys. I have a Monotouch UITableView which contains some web images. I have implemented a Task to fetch them asynchronously so the UI is responsive, an even added some animations to fade them in when they are fetched from the web.
My problems start when the user scrolls down very fast down the UITableView, so since the cells are resusable, several background tasks are queued for images. When he is at the bottom of the list, he might see the thumbnail displaying an image for another cell, then another, then another, then another, as the tasks are completed and each image replaces the other one. I am in need of some sort of checking whether the currently displayed cell corresponds to the correct image url, but not sure how to do that.
Here is the code for my TableSource class.
using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
{
public class ListDelegate:UITableViewDelegate
{
private UINavigationController nav;
public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
return 128;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
DealViewController c = new DealViewController(((ListDataSource)tableView.DataSource).deals[indexPath.Row].Id,nav);
nav.PushViewController(c,true);
tableView.DeselectRow(indexPath,true);
}
public ListDelegate(UINavigationController nav)
{
this.nav = nav;
}
}
public class ListDataSource:UITableViewDataSource
{
bool toggle=true;
Dictionary<string,UIImage> images = new Dictionary<string, UIImage>();
public List<MyDeal> deals = new List<MyDeal>();
Dictionary<int,ListCellViewController> controllers = new Dictionary<int, ListCellViewController>();
public ListDataSource(List<MyDeal> deals)
{
this.deals = deals;
}
public override int RowsInSection (UITableView tableview, int section)
{
return deals.Count;
}
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell("cell");
ListCellViewController cellController = null;
if (cell == null || !controllers.ContainsKey(cell.Tag))
{
cellController = new ListCellViewController();
NSBundle.MainBundle.LoadNib("ListCellViewController", cellController, null);
cell = cellController.Cell;
cell.Tag = Environment.TickCount;
controllers.Add(cell.Tag, cellController);
}
else
{
cellController = controllers[cell.Tag];
}
if (toggle)
{
cell.BackgroundView = new UIImageView(UIImage.FromFile("images/bg1.jpg"));
}
else
{
cell.BackgroundView = new UIImageView(UIImage.FromFile("images/bg2.jpg"));
}
toggle = !toggle;
MyDeal d = deals[indexPath.Row];
cellController.SetValues(d.Title,d.Price,d.Value,d.DiscountPercent);
GetImage(cellController.Thumbnail,d.Thumbnail);
return cell;
}
private void GetImage(UIImageView img, string url)
{
img.Alpha = 0;
if (url != string.Empty)
{
if (images.ContainsKey(url))
{
img.Image = images[url];
img.Alpha = 1;
}
else
{
var context = TaskScheduler.FromCurrentSynchronizationContext ();
Task.Factory.StartNew (() => {
NSData imageData = NSData.FromUrl(new NSUrl(url));
var uimg = UIImage.LoadFromData(imageData);
images.Add(url,uimg);
return uimg;
}).ContinueWith (t => {
InvokeOnMainThread(()=>{
img.Image = t.Result;
RefreshImage(img);
});
}, context);
}
}
}
private void RefreshImage(UIImageView img)
{
UIView.BeginAnimations("imageThumbnailTransitionIn");
UIView.SetAnimationDuration(0.5f);
img.Alpha = 1.0f;
UIView.CommitAnimations();
}
}
}
Here is the ListCellViewController, that contains a custom cell
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
{
public partial class ListCellViewController : UIViewController
{
#region Constructors
// The IntPtr and initWithCoder constructors are required for items that need
// to be able to be created from a xib rather than from managed code
public ListCellViewController (IntPtr handle) : base(handle)
{
Initialize ();
}
[Export("initWithCoder:")]
public ListCellViewController (NSCoder coder) : base(coder)
{
Initialize ();
}
public ListCellViewController () : base("ListCellViewController", null)
{
Initialize ();
}
void Initialize ()
{
}
public UIImageView Thumbnail
{
get{return thumbnailView;}
}
public UITableViewCell Cell
{
get {return cell;}
}
public void SetValues(string title,decimal price,decimal valuex,decimal discount,int purchases)
{
}
#endregion
}
}
All help is greatly appreciated
I have found a simple (maybe not optimal) solution. The trick I used is a Queue object to store the last n valid image urls, where n the number of words displayable in the screen. Once a cell is reused, the last image url is dequeued and when it is about to be displayed I check if it's in the queue, and if it's not I reject it.

View is not accessible after ParentViewController.View.AddSubview

I am using Monotouch to develop iPad app.
Here is my scenario:
I Created Tabbed base application.
e.g. Home, Admin, Reports....etc
Home tab is UIViewController.
I want three section inside Home Tab:
e.g. Category(Table view with navigation control (reason to use navigation because we have subcategories inside Category) beside Category Table, Items of selected category(Other Table view) and right hand side is detail view of Selected ITEM.
Here is what i did....
Dynamically create two tableview controller and added to main view controller.
HomeViewController.cs:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
RootViewController rvc = new RootViewController("",UITableViewStyle.Grouped);
// navigation controller will manage the views displayed and provide navigation buttons
navigationController = new UINavigationController();
navigationController.PushViewController(rvc, false);
navigationController.TopViewController.Title ="Category";
navigationController.View.Frame = new RectangleF (0, 50, (50), (600));
// Main window to which we add the navigation controller to
this.View.AddSubview(navigationController.View);
itemtable.Delegate = new TableViewDelegate (list);
itemtable.DataSource = new TableViewDataSource (list);
// Perform any additional setup after loading the view, typically from a nib.
}
=====================================================
RootViewController:
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Drawing;
namespace DVPNTN_MobileApp
{
[MonoTouch.Foundation.Register("RootViewController")]
public partial class RootViewController : UITableViewController
{
public List<string> RootData = new List<string> { "Group1", "Group2" };
MonoTouch.UIKit.UINavigationController navigationControllerItem;
string SelectedGroup;
// Allow us to set the style of the TableView
public RootViewController(string selectedGroup, UITableViewStyle style) : base(style)
{
this.SelectedGroup = selectedGroup;
}
class DataSource : UITableViewDataSource
{
static NSString kCellIdentifier = new NSString ("MyIdentifier");
RootViewController tvc;
public DataSource (RootViewController tvc)
{
this.tvc = tvc;
}
public override int RowsInSection (UITableView tableView, int section)
{
return tvc.RootData.Count;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (kCellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (UITableViewCellStyle.Default, kCellIdentifier);
}
cell.TextLabel.Text = tvc.RootData.ElementAt(indexPath.Row);
cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
return cell;
}
}
class TableDelegate : UITableViewDelegate
{
RootViewController tvc;
SubGroupViewController sgvc;
public TableDelegate (RootViewController tvc)
{
this.tvc = tvc;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
string selectedGroup = tvc.RootData.ElementAt(indexPath.Row);
sgvc = new SubGroupViewController(selectedGroup, UITableViewStyle.Grouped);
tvc.NavigationController.PushViewController(sgvc,true);
//tvc.View.RemoveFromSuperview();
//tvc.DidReceiveMemoryWarning();
GC.Collect();
}
}
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 ViewDidLoad ()
{
base.ViewDidLoad ();
TableView.Delegate = new TableDelegate (this);
TableView.DataSource = new DataSource (this);
RootVIewItemController rvc1 = new RootVIewItemController(SelectedGroup,UITableViewStyle.Grouped);
// navigation controller will manage the views displayed and provide navigation buttons
navigationControllerItem = new UINavigationController();
navigationControllerItem.PushViewController(rvc1, false);
navigationControllerItem.TopViewController.Title = SelectedGroup + " " + "Item List";
navigationControllerItem.View.Frame = new RectangleF (0, 300, (50),(700));
//this.View.AddSubview(navigationControllerItem.View);
//rvc1.View.EnableInputClicksWhenVisible = true;
//this.ParentViewController.AddChildViewController(navigationControllerItem);
**> Problem is here --- subview is successfully added to parent view but it's not accessible, mean items are there but we can't touch cell or row???????**
ParentViewController.View.AddSubview(navigationControllerItem.View);
GC.Collect();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return true;
}
}
}
********** ItemViewController **
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace DVPNTN_MobileApp
{
[MonoTouch.Foundation.Register("RootVIewItemController")]
public partial class RootVIewItemController : UITableViewController
{
public List<string> RootData = new List<string> { "Item 1", "Item 2", "Item 3", "Item 4" };
string SelectedGroup;
public RootVIewItemController (string selectedGroup, UITableViewStyle style) : base (style)
{
this.SelectedGroup = selectedGroup;
}
class DataSource : UITableViewDataSource
{
static NSString kCellIdentifier = new NSString ("MyIdentifier");
RootVIewItemController tvc;
public DataSource (RootVIewItemController tvc)
{
this.tvc = tvc;
}
public override int RowsInSection (UITableView tableView, int section)
{
return tvc.RootData.Count;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (kCellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (UITableViewCellStyle.Default, kCellIdentifier);
}
cell.TextLabel.Text = tvc.RootData.ElementAt(indexPath.Row);
//cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
return cell;
}
}
class TableDelegate : UITableViewDelegate
{
RootVIewItemController tvc;
SubGroupViewController sgvc;
public TableDelegate (RootVIewItemController tvc)
{
this.tvc = tvc;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
string selectedGroup = tvc.RootData.ElementAt(indexPath.Row);
Console.WriteLine(
"TableViewDelegate.RowSelected: Label={0}",selectedGroup);
/*
if(sgvc == null)
sgvc = new SubGroupViewController(selectedGroup, UITableViewStyle.Grouped);
tvc.NavigationController.PushViewController(sgvc,true);*/
}
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
TableView.Delegate = new TableDelegate (this);
TableView.DataSource = new DataSource (this);
}
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.
}
}
}
Question:
Is it right way to doing this scenario?
It's work fine but when we add Item view to parent view controller it is not accessible, mean item list are there but cells are not accessible, we can't touch cell and raise even or do scrolling.
Please anybody can help me?
Thanks
I am not completely sure what you wanted to do. I took my best guess and created a sample with two solutions. One solution per tab. The first uses the built-in split view controller. I have read several places the UISplitViewController must be the root of the application. I have broke that rule by adding it as a child of the tab control.
The second creates a custom version of a split control.
using System;
using System.Collections.Generic;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Drawing;
namespace delete04223
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
UITabBarController tabBarController;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// create a new window instance based on the screen size
window = new UIWindow (UIScreen.MainScreen.Bounds);
var viewController1 = new MyUISplitViewController ();
var viewController2 = new MyUISplitViewController2 ();
tabBarController = new UITabBarController ();
tabBarController.ViewControllers = new UIViewController [] {
viewController1,
viewController2,
};
window.RootViewController = tabBarController;
// make the window visible
window.MakeKeyAndVisible ();
return true;
}
}
public class MyUISplitViewController : UISplitViewController
{
public MyUISplitViewController ()
{
this.Title = "Native Split View";
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var viewController1 = new LeftViewController ();
var viewController2 = new DummyViewController ("Pane 1", "Pane 1");
this.ViewControllers = new UIViewController [] {viewController1, viewController2};
this.WeakDelegate = viewController2;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
public class MyUISplitViewController2 : UIViewController
{
public MyUISplitViewController2 ()
{
this.Title = "Custom Split View";
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var viewController1 = new LeftViewController ();
var viewController2 = new DummyViewController ("Pane 1", "Pane 1");
this.AddChildViewController (viewController1);
this.AddChildViewController (viewController2);
this.View.AddSubview (viewController1.View);
this.View.AddSubview (viewController2.View);
}
public override void ViewDidLayoutSubviews ()
{
base.ViewDidLayoutSubviews ();
RectangleF lRect = this.View.Frame;
RectangleF rRect = lRect;
lRect.Width = .3f * lRect.Width;
rRect.X = lRect.Width + 1;
rRect.Width = (.7f * rRect.Width)-1;
this.View.Subviews[0].Frame = lRect;
this.View.Subviews[1].Frame = rRect;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
public class LeftViewController : UINavigationController
{
public LeftViewController ()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
MyUITableViewController table = new MyUITableViewController (this);
this.PushViewController (table, false);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
public override UIViewController PopViewControllerAnimated (bool animated)
{
return base.PopViewControllerAnimated (true);
}
}
public class DummyViewController : UIViewController
{
string _myLabelText = "";
UIToolbar _toolbar;
public DummyViewController (string viewName, string labelText)
{
this.Title = viewName;
this._myLabelText = labelText;
this.View.BackgroundColor = UIColor.White;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
float center = this.View.Frame.Width / 2f;
UILabel label = new UILabel (new RectangleF (center - 50, 100, 100, 40));
label.Text = this._myLabelText;
label.TextAlignment = UITextAlignment.Center;
label.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
RectangleF rect = this.View.Frame;
rect.Y = 0;
rect.Height = 44;
_toolbar = new UIToolbar (rect);
_toolbar.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
this.View.AddSubview (label);
this.View.AddSubview (_toolbar);
}
[Export("splitViewController:willHideViewController:withBarButtonItem:forPopoverController:")]
public void WillHideViewController (UISplitViewController svc, UIViewController vc,
UIBarButtonItem barButtonItem, UIPopoverController pc)
{
barButtonItem.Title = "Menu";
var items = new List<UIBarButtonItem> ();
items.Add (barButtonItem);
if (_toolbar.Items != null)
items.AddRange (_toolbar.Items);
_toolbar.SetItems (items.ToArray (), true);
//popoverController = pc;
}
[Export("splitViewController:willShowViewController:invalidatingBarButtonItem:")]
public void WillShowViewController (UISplitViewController svc, UIViewController vc,
UIBarButtonItem button)
{
// Called when the view is shown again in the split view, invalidating the button and popover controller.
var items = new List<UIBarButtonItem> (_toolbar.Items);
items.RemoveAt (0);
_toolbar.SetItems (items.ToArray (), true);
//popoverController = null;
}
}
internal class MyUITableViewController : UITableViewController
{
static NSString kCellIdentifier = new NSString ("MyIdentifier");
LeftViewController _parent;
public MyUITableViewController (LeftViewController parent) : base (UITableViewStyle.Plain)
{
this.TableView.WeakDelegate = this;
this.TableView.WeakDataSource = this;
this._parent = parent;
}
[Export ("tableView:numberOfRowsInSection:")]
public int RowsInSection (UITableView tableView, int section)
{
if (section == 0)
return 2;
return 3;
}
[Export ("tableView:cellForRowAtIndexPath:")]
public UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (kCellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (UITableViewCellStyle.Default, kCellIdentifier);
}
cell.TextLabel.Text = GetRowName (indexPath);
return cell;
}
private string GetRowName (NSIndexPath indexPath)
{
string ret;
if (indexPath.Section == 0)
{
ret =
indexPath.Row == 0 ? "Row A" : "Row B";
}
else
{
ret =
indexPath.Row == 0 ? "Row D" :
indexPath.Row == 1 ? "Row E" : "Row F";
}
return ret;
}
[Export ("numberOfSectionsInTableView:")]
public int NumberOfSections (UITableView tableView)
{
return 2;
}
[Export ("tableView:titleForHeaderInSection:")]
public string TitleForHeader (UITableView tableView, int section)
{
if (section == 0)
return "One";
return "Two";
}
[Export ("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
Console.WriteLine("Item Selected: Section={0}, Row={1}",indexPath.Section, indexPath.Row);
this._parent.PushViewController (new MySubUITableViewController (), true);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
internal class MySubUITableViewController : UITableViewController
{
static NSString kCellIdentifier = new NSString ("MyIdentifier");
static string [] _names = new string [] {"One", "Two", "Three", "Four", "Five"};
public MySubUITableViewController () : base (UITableViewStyle.Plain)
{
this.TableView.WeakDelegate = this;
this.TableView.WeakDataSource = this;
}
[Export ("tableView:numberOfRowsInSection:")]
public int RowsInSection (UITableView tableView, int section)
{
return 5;
}
[Export ("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
Console.WriteLine("Item Selected: Section={0}, Row={1}",indexPath.Section, indexPath.Row);
}
[Export ("tableView:cellForRowAtIndexPath:")]
public UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (kCellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (UITableViewCellStyle.Default, kCellIdentifier);
}
cell.TextLabel.Text = _names[indexPath.Row];
return cell;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
}

Resources