MonoTouch Instantiating a ViewController programmatically for ContainerView - ios

I am trying to work with a container view in MonoTouch and I am following some tutorials online. They talk about adding and removing view controller programmatically from the container. I created a viewcontroller and view in the storyboard of my project and attached a few outlets and one action (for labels and buttons respectively). I created an overloaded construc
Here is the code in the view controller that I am trying to add viewControllers into the container view.
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ContainerView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight;
_controllerOne = new IngredientsController("Perishables");
_controllerTwo = new IngredientsController("Spices");
AddChildViewController(_controllerOne);
ContainerView.AddSubview(_controllerOne.View);
_controllerOne.DidMoveToParentViewController(this)
}
When I add the subview for _controllerOne I get an error because the elements on my controller are marked null. Is MonoTouch incapable of having view controllers being programmatically created if the controller was made in Interface Builder? Below are the two constructors for the Ingredient Controller. When the segue is used then all of the UI controls are initialized properly. Do I need to create the controller programmatically and then instantiate it that way? Any help would be appreciated.
//This ctor does not work
public IngredientsController (string title) : base(NSObjectFlag.Empty)
{
_ingredientTitle = title;
}
//This ctor works
public IngredientsController (IntPtr handle) : base (handle)
{
}

Try to swap the AddSubView() and DidMoveToParentViewController() methods like below:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ContainerView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight;
_controllerOne = new IngredientsController("Perishables");
_controllerTwo = new IngredientsController("Spices");
this.AddChildViewController(_controllerOne); // Root child controller.
_controllerOne.DidMoveToParentViewController(this); // Confirm the rooting.
ContainerView.AddSubview(_controllerOne.View); // Access the view.
}

Try instantiating the view controller like this:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
this.ContainerView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight;
var newController = this.Storyboard.InstantiateViewController("IngredientsController");
this.AddChildViewController (newController);
this.ContainerView.AddSubview (mapController.View);
}
Make sure you set the Storyboard Id in the properties panel for the ViewController

Related

MvvmCross: RaisePropertyChanged not updating binding

I am instantiating a view with a ViewModel like this:
var myView = new MyView { DataContext = new MyViewModel() };
I want to make this view accessible from anywhere in the application so I am adding the view to the rootviewcontroller:
window.RootViewController.View.Add(myView.View);
Where ViewModel inherits from MvxViewModel and MyView inherist from MvxViewController
Inside the MyView I am binding a UILabel to a text property like this
this.CreateBinding(myLabel).To<MyViewModel>(vm => vm.MyTextProp).Apply();
The text property is defined inside the ViewModel like this
private string myTextProp;
public string MyTextProp
{
get { return myTextProp; }
set
{
myTextProp = value;
RaisePropertyChanged(() => MyTextProp);
}
}
The binding works initially when loaded. But when I change the MyTextProp property and RaisePropertyChanged is called the UILabel is not being updated.
I am also binding to an ICommand which works fine and triggers normally.
Instead of doing var myView = new MyView { DataContext = new MyViewModel() };
Let MvvmCross construct your MvxViewController by doing this:
var viewController = this.CreateViewControllerFor<MyViewModel>();
CreateViewController is an extensions method for IMvxCanCreateTouchView, so the class where you do your view construction should be implementing that Inteface, otherwise that method will not be available.
I know IMvxCanCreateTouchView is implemented by MvxTouchViewPresenter and MvxViewController so you can call that method from your Presenter or from another MxvViewController.

Update - MvvmCross iOS with storyboards - TableViewCell not being displayed

I am trying to display a table view whose table view cells have a label in it. I followed MvvmCross N+1 days with N=3 to create this sample.
The table is being displayed, but the label is not being displayed
I have a MvxTableViewController
partial class View : MvxTableViewController
{
public View (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var source = new MvxSimpleTableViewSource (TableView, typeof(CellView), "CellView");
TableView.Source = source;
var set = this.CreateBindingSet<View,ViewModel> ();
set.Bind (source).To (vm => vm.CellViewModels);
set.Bind (source).For (s => s.SelectionChangedCommand).To (vm => vm.ViewCommand);
set.Apply ();
TableView.ReloadData ();
}
}
and an MvxTableViewCell with a label in it
partial class CellView : MvxTableViewCell
{
public CellView (IntPtr handle) : base (handle)
{
this.DelayBind (() => {
var set = this.CreateBindingSet<CellView, CellViewModel>();
set.Bind(cellLabel).To(vm => vm.TextToDisplay);
set.Apply();
});
}
}
As I said the table view is displayed but the label is not displayed in the cell. I can click on the table view and navigate to another view by binding to a command on my view model.
In the log I am getting the following warning
MvxBind:Warning: 13.35 Failed to create target binding for binding Text for TextToDisplay
I don't understand this, as the binding code looks OK to me!
There is one difference in the code from the N+1 N=3 video in that I am using the following code to construct the view source as I do not have a nib/xib
var source = new MvxSimpleTableViewSource (TableView, typeof(CellView), "CellView");
where "CellView" is the identifier entered in the properties for the prototype cell
Could this be the problem. I should also say I am using Xamarin Studio on a Mac.
Please help I have been banging my head against this for hours.
Update - I have had to abandon the use of Storyboards due to rapidly approaching deadlines. Have reverted to using xibs for views and cells. If anyone solves this problem please post your answer

Reference UIViewController within ContainerView

I have created a ContainerView in Xamarin, which automatically created a new ViewController.
I have created the class for this called Test1ViewController:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace test1
{
public partial class Test2ViewController : UIViewController
{
public Test2ViewController (IntPtr handle) : base (handle)
{
}
}
}
I am trying to reference this view controller in the ViewDidLoad() method of the main view controller. However if I put the following:
Test2ViewController.PresentViewController(picker, true, null);
I get a static error message, which makes sense as I am trying to reference the class not the specific object. Am I missing something, how do I reference the UIViewController in the ContainerView from the parent UIViewController?
What I am trying to achieve, is including the Scandit Barcode scanner within the container view:
// Setup the barcode scanner
var picker = new ScanditSDK.SIBarcodePicker ("API-KEY");
picker.OverlayController.Delegate = new BarcodeScanner ();
Test2ViewController.PresentViewController(picker, true, null);
picker.StartScanning ();
Assuming that variable picker is supposed to represent a Test2ViewController instance:
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.picker = new Test2ViewController();
this.PresentViewController(picker, true, null);
}

MonoTouch for IPad: How to show another UIViewController in a UIPopoverController?

As title said, I want to show another UIViewController from an existing UIViewController which is hosted in UIPopoverController. I tried the following method:
_secondViewController = new SecondViewController();
this.ModalPresentationStyle = UIModelPresentationStyle.CurrentContext;
this.ModelInPopover = true;
this.PresentModelViewController(_secondViewController, true);
However, the secondViewController is shown in the main view controller, instead of the popover controller.
In this post somebody mentions that it cannot be done and it violates the HIG. However, I have seen this in other apps (e.g. Yahoo! Email) if I'm not mistaken.
I'm also thinking about another approach: If I could create a UINavigationController within the popover context, it might work by just adding new ViewController to the NavigationController. But how?
Remember that UINavigationController derives from UIViewController.
So, you can use the controller contained within UIPopover just like any other container... in this case it's best to use UINavigationController inside UIPopover to display ViewControllers.
Usage:
var _NavController = new NavController();
Popover = new UIPopoverController(_NavController);
Popover.PopoverContentSize = new SizeF(..., ...);
Popover.PresentFromRect(...);
NavController:
public class NavController : UINavigationController
{
UIViewController _FirstViewController;
UIViewController _SecondViewController;
public NavController()
: base()
{
}
public override void LoadView()
{
base.LoadView();
_FirstViewController = new UIViewController();
// Initialize your originating View Controller here.
// Only view related init goes here, do everything else in ViewDidLoad()
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// When a button inside the first ViewController is clicked
// The Second ViewController is shown in the stack.
_FirstViewController.NavButton.TouchUpInside += delegate {
PushSecondViewController();
};
this.PushViewController(_FirstViewController, true);
}
public void PushSecondViewController()
{
_SecondViewController = new UIViewController();
this.PushViewController(_SecondViewController, true);
}
}

In MonoTouch, how do I assign a custom view to my view controller?

If I want to use a custom view object with my view controller, instead of just using the one that's initialized by default, can I just assign it to the view controller's View property. For example, is the following the correct/safe approach?
public class MyView : UIView
{
}
public class MyController : UIViewController
{
// Constructors.
public MyController()
{
View = new MyView();
}
}
Seems to work in a simple test, but I don't want to be introducing any time-bombs.
Or, should I be adding my custom view as a subview of the existing view in ViewDidLoad?
You should be adding the custom views as subviews.
public class MyView : UIView
{
}
public class MyController : UIViewController
{
public override void ViewDidLoad()
{
var myView = new MyView();
this.View.AddSubview(myView);
}
}

Resources