Structuring a MonoTouch.Dialog application
Asked Answered
F

3

10

From the examples at Xamarin.com you can build basic M.T. Dialog apps, but how do you build a real life application?

Do you:

1) Create a single DialogViewController and tree every view/RootElement from there or,

2) Create a DialogViewController for every view and use the UINavigationController and push it on as needed?

Depending on your answer, the better response is how? I've built the example task app, so I understand adding elements to a table, click it to go to the 'next' view for editing, but how to click for non-editing? How to click a button, go next view if answer is number 1?

Revised:

There is probably no one right answer, but what I've come up with seems to work for us. Number 2 from above is what was chosen, below is an example of the code as it currently exists. What we did was create a navigation controller in AppDelegate and give access to it throughout the whole application like this:

public partial class AppDelegate : UIApplicationDelegate
{
    public UIWindow window { get; private set; }
    //< There's a Window property/field which we chose not to bother with

    public static AppDelegate Current { get; private set; }
    public UINavigationController NavController { get; private set; }

    public override bool FinishedLaunching (UIApplication app, NSDictionary options)
    {
        Current = this;
        window = new UIWindow (UIScreen.MainScreen.Bounds);
        NavController = new UINavigationController();

        // See About Controller below
        DialogViewController about = new AboutController();
        NavController.PushViewController(about, true);

        window.RootViewController = NavController;
        window.MakeKeyAndVisible ();
        return true;
    }
}

Then every Dialog has a structure like this:

public class AboutController : DialogViewController
{
    public delegate void D(AboutController dvc);
    public event D ViewLoaded = delegate { };

    static About about;
    public AboutController()
        : base(about = new About())
    {
        Autorotate = true;
        about.SetDialogViewController(this);
    }

    public override void LoadView()
    {
        base.LoadView();
        ViewLoaded(this);
    }
}

public class About : RootElement
{
    static AboutModel about = AboutVM.About;

    public About()
        : base(about.Title)
    {
        string[] message = about.Text.Split(...);
        Add(new Section(){
            new AboutMessage(message[0]),
            new About_Image(about),
            new AboutMessage(message[1]),
        });
    }

    internal void SetDialogViewController(AboutController dvc)
    {
        var next = new UIBarButtonItem(UIBarButtonSystemItem.Play);
        dvc.NavigationItem.RightBarButtonItem = next;
        dvc.ViewLoaded += new AboutController.D(dvc_ViewLoaded);
        next.Clicked += new System.EventHandler(next_Clicked);
    }

    void next_Clicked(object sender, System.EventArgs e)
    {
        // Load next controller
        AppDelegate.Current.NavController.PushViewController(new IssuesController(), true);
    }

    void dvc_ViewLoaded(AboutController dvc)
    {
        // Swipe location: https://gist.github.com/2884348
        dvc.View.Swipe(UISwipeGestureRecognizerDirection.Left).Event +=
            delegate { next_Clicked(null, null); };            
    }
}

Create a sub-class of elements as needed:

public class About_Image : Element, IElementSizing
{
    static NSString skey = new NSString("About_Image");
    AboutModel about;
    UIImage image;

    public About_Image(AboutModel about)
        : base(string.Empty)
    {
        this.about = about;
        FileInfo imageFile = App.LibraryFile(about.Image ?? "filler.png");
        if (imageFile.Exists)
        {
            float size = 240;
            image = UIImage.FromFile(imageFile.FullName);
            var resizer = new ImageResizer(image);
            resizer.Resize(size, size);
            image = resizer.ModifiedImage;
        }
    }

    public override UITableViewCell GetCell(UITableView tv)
    {
        var cell = tv.DequeueReusableCell(skey);
        if (cell == null)
        {
            cell = new UITableViewCell(UITableViewCellStyle.Default, skey)
            {
                SelectionStyle = UITableViewCellSelectionStyle.None,
                Accessory = UITableViewCellAccessory.None,
            };
        }
        if (null != image)
        {
            cell.ImageView.ContentMode = UIViewContentMode.Center;
            cell.ImageView.Image = image;
        }
        return cell;
    }

    public float GetHeight(UITableView tableView, NSIndexPath indexPath)
    {
        float height = 100;
        if (null != image)
            height = image.Size.Height;
        return height;
    }

    public override void Selected(DialogViewController dvc, UITableView tableView, NSIndexPath indexPath)
    {
        //base.Selected(dvc, tableView, path);
        tableView.DeselectRow(indexPath, true);
    }
}

@miquel

The current idea of a workflow is an app that starts with a jpg of the Default.png that fades into the first view, with a flow control button(s) that would move to the main app. This view, which I had working previous to M.T.D. (MonoTouch.Dialog), which is a table of text rows with an image. When each row is clicked, it moves to another view that has the row/text in more detail.

The app also supports in-app-purchasing, so if the client wishes to purchase more of the product, then switch to another view to transact the purchase(s). This part was the main reason for switching to M.T.D., as I thought M.T.D. would be perfect for it.

Lastly there would be a settings view to re-enable purchases, etc.

PS How does one know when the app is un-minimized? We would like to show the fade in image again.

Fleischer answered 5/4, 2012 at 19:6 Comment(5)
Try looking at the TweetStation app - it relies heavily on MT.DDeach
That's not helping as there is no explanation why anything is done, like 5 DVC's. What I want to know is how to nest dialogs, using either method 1 or 2 above.Fleischer
Chuck, it would help if you describe what kind of application you have in mind, and if you have a worfklow that you want to achieve. Then things will become more clear. Do you think you could post a balsamic mockup of what you are trying to do? I could comment on how you could achieve each step with that.Albin
@Albin Thx Miguel, I added an update to the postFleischer
@Jason: Are you sure that TweetStation is still working?Oreopithecus
H
1

I have been asking myself the same questions. I've used the Funq Dependency Injection framework and I create a new DialogViewController for each view. It's effectively the same approach I've used previously developing ASP.NET MVC applications and means I can keep the controller logic nicely separated. I subclass DialogViewController for each view which allows me to pass in to the controller any application data required for that particular controller. I'm not sure if this is the recommended approach but so far it's working for me.

I too have looked at the TweetStation application and I find it a useful reference but the associated documentation specifically says that it isn't trying to be an example of how to structure a MonoTouch application.

Haversine answered 28/5, 2012 at 9:17 Comment(0)
D
1

I use option 2 that you stated as well, it works pretty nicely as you're able to edit the toolbar options on a per-root-view basis and such.

Demijohn answered 27/9, 2012 at 15:34 Comment(0)
E
0

Option 2 is more feasible, as it also gives you more control on each DialogViewController. It can also helps if you want to conditionally load the view.

Eward answered 2/6, 2014 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.