create or inject ViewModel when building a "tabs" application - xamarin.ios

We try to build an application with a few tabs. As reference-project we use that example: http://slodge.blogspot.co.uk/2013/06/n25-tabs-n1-days-of-mvvmcross.html
To get the ViewModel-instances we need to create the tabs, we used the "HomeViewModel"-pattern as mentioned in that post: Create View Model using MVVMCross built in factory?
What I don't like at this approach is the initialisation of ViewModel's with "new". As far as I understand, it skips the whole ViewModel-Lifecycle (https://github.com/slodge/MvvmCross/wiki/View-Model-Lifecycle) which we really like. In our current project, we'd like to use the "start()" lifecycle-method, but it's never called due to initialisation with "new".
What worked for us was to go that way:
var loaderService = Mvx.Resolve<IMvxViewModelLoader>();
var vm = (UserListViewModel)loaderService.LoadViewModel(new MvxViewModelRequest(typeof(UserListViewModel), null, null, null), null);
So my question: Is that the way to do the job or is it just a dirty workaround and there is a much better solution?
Update: We came to that solution:
CreateTabFor<SettingsViewModel>("Settings", "settings");
//This method loads the ViewModel
private UIViewController CreateTabFor<TTargetViewModel>(string title, string imageName)
where TTargetViewModel : class, IMvxViewModel
{
var controller = new UINavigationController();
controller.NavigationBar.TintColor = UIColor.Black;
var viewModelRequest = new MvxViewModelRequest(typeof(TTargetViewModel), null, null, null);
var screen = this.CreateViewControllerFor<TTargetViewModel>(viewModelRequest) as UIViewController;
SetTitleAndTabBarItem(screen, title, imageName);
controller.PushViewController(screen, false);
return controller;
}

The 'viewmodel lifecycle' is an area of conflicting interests in MvvmCross. The root cause is the conflict between:
viewmodel's which are just the models for any view
viewmodel's which are specifically used within the 'ShowViewModel' navigation process
For simple 'whole page' User Experiences, the C-I-R-S viewmodel lifecycle is easy to support and to ensure it gets consistently used.
However, as soon as the user experience starts to merge in tabs, flyouts, hamburger menus, dialogs, split views, etc then:
the developers sometimes want to control viewmodel lifecycles themselves
it's not as easy for the framework to ensure that view models are always created, activated and tombstoned/rehydrated consistently
Personally, I like your approach - of trying to ensure all viewmodels are independent and all constructed the same way - but MvvmCross doesn't force this approach on all developers.
Specifically for tabs, most of the existing examples do use the 'owned sub-viewmodel' pattern that you've identified.
However, it should be relatively easy to implement other mechanisms if you want to - just as you already have.
In particular, you can:
use the loaderService directly - getting hold of it via Mvx.Resolve<IMvxViewModelLoader>();
use ShowViewModel with a custom presenter to create both views and viewmodels - the beginnings of this is illustrated in that N=25 video but you could take it much further and actually add the tabs in response to ShowViewModel calls.
use alternative calls to create the child tabs and their viewmodels inside the Views - e.g. where the Touch sample currently calls
var screen = this.CreateViewControllerFor(viewModel) as UIViewController;
this could easily be replace with something like:
var screen = this.CreateViewControllerFor<ChildViewModel>() as UIViewController;;
(or one of the other overloads from MvxCanCreateIosViewExtensionMethods.cs)
One repo where I know some users have taken some of these ideas and played with them is the Sliding menu repo - I think they have chosen to use this.CreateViewControllerFor<TViewModel> to create their view models. This may or may not be the way you choose to go - but it might be of interest for you to experiment with.

Related

How to implement a SideNavigationViewController into a UIViewController?

A little confused on how to implement this into my main view controller. The example project shows it as a navigation controller, but I wasn't able to add an existing class on a fresh navigation controller or my current UIViewController. I could just be implementing it wrong though. Much appreciation if I can gain some traction on how to work with these.
If you could share some code that would be great.
How things work:
Navigation Controllers
There are currently 4 different Navigation Controllers that each offer their own features. The controllers can be used individually, or together.
SideNavigationViewController
The SideNavigationViewController offers 3 bodies to display content: mainViewController, leftViewController, and rightViewController.
MainViewController
The mainViewController must always exist, and has a facility for transitioning between view controllers using the transitionFromMainViewController method. Using this method is as easy as passing a UIViewController in its first parameter.
sideNavigationViewController?.transitionFromMainViewController(InboxViewController())
There are further parameters that allow for animations, completions, etc... to be set when transitioning between view controllers.
LeftViewController and RightViewController
The leftViewController and rightViewController can be set only once. To make them dynamic, you would need to use another Navigation Controller as its view controller.
NavigationBarViewController
The NavigationBarViewController offers a NavigationBarView along side the ability to manage two UIViewControllers, the mainViewController and the floatingViewController.
MainViewController
The mainViewController is like the SideNavigationViewController's mainViewController, and has a transitionFromMainViewController method that transitions from view controller to view controller in the body portion of the NavigationBarViewController.
FloatingViewController
The floatingViewController is a modalViewController and when set, it pops over MainViewController and NavigationBarView. Setting that value is like so:
navigationBarViewController?.floatingViewController = InboxViewController()
To close and hide the floatingViewController set it to nil, like so.
navigationBarViewController?.floatingViewController = nil
SearchBarViewController
The SearchBarViewController offers a single transitioning mainViewController, as well, has a SearchBarView at the top. Transitioning the mainViewController is like so:
sideNavigationBarViewController?.transitionFromMainViewController(InboxViewController())
MenuViewController
The MenuViewController is another controller that has a mainViewController, which takes the entire screen. Floating above it, is a MenuView that is used to transition between mainViewControllers.
menuViewController?.transitionFromMainViewController(InboxViewController())
Final Notes
These Navigation Controllers can be used in any combination and any amount of times creating a robust and intricate stack of controllers that act like one.
I hope this helps :)

YUI widgets - dynamic updates

I am new to web programming and of course to YUI.
I tried using the overlay, chart and node-menunav.
Wanted to know if there is any option of creating these widgets using dynamic data coming in JSON format and updating the widgets as the new data comes in?
For us all the properties will come in JSON data from server and then using that data we need to render menubars, charts, property browser. Now i am not finding how to proceed with this requirement.
Thanks.
There is no default way of syncing widgets via Ajax. The only widget that comes by default with ways of updating its data is the DataTable widget. For the rest, and even for DataTable's attributes, you need to do it yourself.
However, if the data and widgets are complicated enough, you should consider using the YUI App Framework. The combination of Models and Views will help you a lot for creating complex layouts with widgets. Model will give you a way to link attributes to a JSON backend easily, specially if you're using a RESTful API endpoint. And View will give you tools for setting up the markup and reacting to events.
The Model's load and change events will let you know when the data updates. So in your view you'll be able to react to these events and set the corresponding attributes in your widgets:
var MyView = Y.Base.create('myView', Y.View, [], {
initializer: function () {
this.get('model').on('change', this._updateWidgets, this);
},
_updateWidgets: function () {
var model = this.get('model');
this.someWidget.set('someAttr', mode.get('someAttr'));
}
});
But as I said there is no right way of doing this. You can use whatever technique you like. The App framework is just a set of basic components that you can use to structure you application. It's designed for flexibility so it can accommodate many ways of using it. Other ways could use IO directly or use DataSources combined with Widget Plugins. This is a question with many correct answers.

How to pass data to layout in Zend 2?

I've looked around, and there are a few links about this in Zend 1 at best. The best solution I've found is
// controller:
return array('viewValue' => 'something');
// layout.phtml
$children = $this->viewModel()->getCurrent()->getChildren();
$viewValue = $children[0]->viewValue;
In the layout, but it seems a little kludgy. It's even stranger because when I do get_class_methods on the layout it doesn't show a viewModel() method. Basically, I've looked around the API (and source code) and haven't found much. Zend 1 also seems to have more access; some old solutions involved getting the view, and directly modifying it, but in Zend 2 we return a new array (or view model). Any tips?
As for why, I'm using a jQuery mobile layout. So the heading is separate from content, but the structure should be the same (should belong in the layout).
The view models are hierarchically build. The top level view model is the "layout" and a child view model is injected after a controller is dispatched. This means you can build quite some tree of models for your application.
The top level view model (so the one representing the layout) is also located in the MvcEvent. That object is passed along in the application during bootstrap, but also linked to the controller when the controller is initialized.
The MvcEvent is accessible with $this->getEvent() in the controller, the view model by $event->getViewModel(). So to cut things short, just do this:
controller MyController
{
public function myAction()
{
$this->getEvent()->getViewModel()->foo = 'bar';
}
}
And in your layout.phtml:
<?php echo $this->foo; ?>
This pretty much is, how it is done. The new Zend\View-Components are pretty much all ViewModels nested into each other. Rob Allen has written a great article about it on how to work with variables throughout ViewModels.
Furthermore most often i think this approach isn't the best way. It'd be much better to have a ViewHelper or a Layout-Placeholder to do the job. Once again a great article has been written, this time by my dear Bakura, aka Michael Gallego.
Currently, either of those approaches would be your way to go.

What's the best practice to creating different views when sharing one child frame in an MFC MDI app?

I'm not necessarily looking for code help, but rather a high level answer so I can research the solution myself. Basically, I have an MDI app with multiple docs and their views, I'd like all the views to open up as tabs in the one child frame that I have. The thing is my child frame is statically configured with a splitter window with two views, a form and a list view, in the OnCreateClient method. I'd like to keep this as the default tab that appears when the app is launched.
I have a third view (editview) with it's own document template, which I'd like to be able to open as a separate tab. I will have other views that will behave this way. What's the best way to approach this?
Will I need to create separate child frames for each view? Will I lose the 'tab' feature if I create separate child frames?
Or will I have to modify the child frame's OnCreateClient method to test which document template is the current one and create the view for that doc template? I'd like to know how some of you seasoned programmers have had or would do it.
Thanks.
In case this helps others, from what I've gathered, it is perfectly acceptable to create a new child frame class derived from CChildFrame or just use that as your frame with your new view. The doc, frame, and view will be added to the doc template in the initInstance method. for example, let say you have a pair of trios (2 docs, 2 views, 2 frames):
pDocTemplate = new CMultiDocTemplate(IDR_testappTYPE,
RUNTIME_CLASS(CMydoc1),
RUNTIME_CLASS(CMyframe1),
RUNTIME_CLASS(CMyview1));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
pDocTemplate2 = new CMultiDocTemplate(IDR_testappTYPE,
RUNTIME_CLASS(CMydoc2),
RUNTIME_CLASS(CMyframe2),
RUNTIME_CLASS(CMyview2));
if (!pDocTemplate2)
return FALSE;
AddDocTemplate(pDocTemplate2);
If you add another trio with a different childframe because this new frame doesn't use splitters like the ones above, you would do it this way.
pDocTemplate3 = new CMultiDocTemplate(IDR_mditest3TYPE,
RUNTIME_CLASS(CMydoc), //same doc
RUNTIME_CLASS(CMyframeWithoutSplitters), //new frame
RUNTIME_CLASS(CMyview3)); //new view
if (!pDocTemplate3)
return FALSE;
AddDocTemplate(pDocTemplate3);

Loading existing data into MonoTouch.Dialog

I am new to MonoTouch from a VS/C# background and am trying to rewrite an existing c# app.
I have made one simple MonoTouch app which succesfully loads data into a List<> from an XML file, and was starting to add Master/Detail code when I discovered the existence of MonoTouch.Dialog which looked like it would make my job much easier. So I started a new project using the sample code at http://docs.xamarin.com/ios/tutorials/MonoTouch.Dialog , changing the basic class to match what I needed.
But I am stuck with trying to prepopulate the DialogViewController with my existing List<>. I have tried using LoadMoreElement but cannot find an example of its use and don't know if it's the best way of doing this.
Thanks Anders.
In the interim period I discovered a different method:
_rootElement = new RootElement ("Riders")
{
new Section()
{
from x in riderList.Riders select (Element) new RootElement(x.Name)
{
new Section()
{
new StringElement("Rider",x.Name),
new StringElement("Club",x.Club),
....
....
...ill try both and see what suits best.
But I'm struggling to find any documentation to describe the methods for the dialog classes, e.g. Section.AddAll() and others used in the link you have provided.
If you want to create a list within an existing dialog view, you can for example create an empty Section and to this section add the list the elements from the list as RadioElement:s or CheckboxElement:s, depending on how many elements you want to be able to select simultaneously.
To facilitate selection, you may need to create a Group/RadioGroup and reference this group when you create the respective list elements in your section.
Here is a quick example of creating a new Section and adding the list elements, assuming that only one element can be selected simultaneously:
var list = new List<SomeClass> { ... };
var listGroup = new RadioGroup("grp", 0);
var listSection = new Section();
listSection.AddAll(list.Select(elem =>
new RadioElement(elem.ToString(), "grp") as Element));
If you want more specialized handling of the elements in the list or the events associated with list actions, you may want to subclass RadioElement or CheckboxElement. There is a good example on how to do this in the answer to this SO question.

Resources