Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you encapsulate a MonoTouch.Dialog view into a view controller?

I am writing a view controller for adding a new item to my app. It is a perfect fit for MonoTouch.Dialog, as it can be done easily with a table based interface, with a field per relevant property of my item.

This is the code I have currently for showing the add item view (simplified, but the core idea remains):

Item item = new Item();
TapHandler handler = new TapHandler(); 
BindingContext bc = new BindingContext(handler, item, "Add Item");
DialogViewController dv = new DialogViewController(bc.Root, true);
this.NavigationController.PushViewController(dv, true);

While that works, I would prefer if I could encapsulate the details of the view into its own view controller, so the code could look like this:

UIViewController controller = new AddItemViewController();
this.NavigationController.PushViewController(controller, true);

However, I can't figure out how to implement this. I thought the logical thing to do would be to make a subclass of DialogViewController. However, all the constructors of DialogViewController require a RootElement. To get that, you need to firstly create the BindingContext. As you can't run any code before calling the base constructor, it doesn't end up working.

My second approach was to implement subclass of UIViewController, create the DialogViewController, and the add the dialog view controller as a child of my subclass using this.AddChildViewController(dv) and this.View.AddSubView(dv.View). While this works initially, if you have the new view controller in a UINavigationController, and you click a date element, the date view appears as a modal popup rather than in the navigation controller hierarchy. (This makes sense, as the DialogViewController isn't part of the NavigationController hierarchy in this design).

From there I'm stuck. I couldn't find any examples of using MonoTouch.Dialog like this in the examples either. Is this possible to do? Or if it's not, is there a good reason as to why writing code like this is a bad idea?

like image 542
David Miani Avatar asked Mar 20 '12 09:03

David Miani


2 Answers

As you can't run any code before calling the base constructor

That's not quite correct.

It's not ideal but you can inherit from DialogViewController and provide it with an empty RootElement instance, like this:

public class AddItemViewController : DialogViewController {
    public AddItemViewController () : base (new RootElement ()) { }
}

Later you can add your things (or set a new RootElement) to the Root property, e.g.

void Populate ()
{
    this.Root.Add (new Section () { ... });
}
like image 81
poupou Avatar answered Sep 25 '22 14:09

poupou


I found a way to do this, although it seems a little messy (thanks poupou for giving me the idea). I just set Root to null in the base constructor call, and then set it straight away in the contructor method:

class NewItemViewController : DialogViewController
{
    private Item _item;
    public NewItemViewController(bool pushing) : base(null, pushing)
    {
        _item = new Item();
        BindingContext bc = new BindingContext(this, _item, "Add Item");
        this.Root = bc.Root;
        // more setup
    }
    // more methods
}

I wasn't aware you could change the Root object, not just access it.

like image 26
David Miani Avatar answered Sep 22 '22 14:09

David Miani