Friday, June 6, 2014

The many hoops of MVVMCross on iOS

EDIT: I just lost section 10-13 due to a server error. Thanks blogger... I can't remember what was written. :)

WARNING: This is a very unstructured post following my first attempts of creating a MvvmCross application using Xamarin.ios. As I go along with this, I'll try to restructure it.

This post is all about the hoops I had to jump to get started With MvvmCross for iOS using Xamarin.

I'm using the 3.1.2-beta1 nuget package available at http://www.nuget.org/packages/MvvmCross/3.1.2-beta1. This is a beta and I'm sure a lot will change before the stable release.

I have a simple solutions structure with a shared PCL core project and a platform specific project for each target device.

1. A PCL profile that works

The nuget package doesn't install using the profile I usually use.

I started by setting up a core PCL project using the following profile.


This will give you some headaches if you plan to use HttpClient later on. I'll update this with a solution when I cross (no pun intended) that bridge.

I then installed the MvvmCross nuget package by typing

install-package mvvmcross -pre

in the Package Console Manager.

2. Create the ios project

Don't use storyboarding. It doesn't make sense if you're using MvvmCross.You can use it if you really must but this post explains why it doesn' fit well.

I ended up creating an empty universal ios project and installed the MvvmCross nuget package using the same install-package command described in the first step.

Instructions for how to bootstrap your MvvmCross solution can be found in the ToDo-MvvmCross folder. It's basically tells you to reference your core project and the replace the code in the AppDelegate.cs file with the code found in AppDelegate.cs.txt.

3. Learn the naming Conventions

Create the ViewModels in the core project and a corresponding View in the platform specific project. They magically find each other. This is really simple MvvmCross stuff but it's one of those things that might get you off track.

If my viewmodel is named TestViewModel then the view must be TestView.

4. Binding to the ViewModel

The outline is to add a ViewController and make it inherit from MvxViewController. Add controls (or subviews) to the xib-file in xcode and create references by ctrl-dragging them into the .h file.

When I created my first controller I had trouble finding the CreateBindingSet method. It turns out it's an extension method living in Cirrious.MvvmCross.Binding.BindingContext. So simply add a using statement like the one below.

using Cirrious.MvvmCross.Binding.BindingContext;

The this.Bind(...) method, as found in most samples, isn't there any more.

So it would look something like this in the ViewDidLoad override.

var set = this.CreateBindingSet<TestView, Core.ViewModels.TestViewModel>();
// set.Bind(label).To(vm => vm.SomeProperty);
set.Apply();
Oh, and also put the binding stuff below the call to the base method.

5. Mac jumping

I prefer using Visual Studio for coding so I have my development environment set up using a virtual machine through Parallels. I was first really glad to learn about the ios designer that came along with Xamarin 3.0, but unfortunatly it doesn't work on xib-files, only storyboards. *wierd*

So, I had to jump back to my MacOS and open up Xamarin studio. From there I opened the test project by navigating into the windows disk from the desktop. It opened up just fine. So when ever I need to fiddle with the xib-file I jump back into MacOS, double click the file in Xamarin Studio and edit it in Xcode. Nice and simple. :P

6. I want to bind a table view to something

I added a TableView to my TestView.xib file and created a reference to it. (in xcode).

Since it's hard to find any examples of anyone using the CreateBindingSet<> thingy I started to convert some earlier code samples.

I hit a rock wall. Consider the code below.

var source = new MvxStandardTableViewSource(MainTableView, "TitleText Name;");

set.Bind(source.ItemsSource).To(wm => wm.Persons); // NOT WORKING
set.Bind(source).To(wm => wm.Persons); // WORKS FINE

 

First thing, there is no error on failed bindings. Why not? I'm sure there is a good reason for it, but silent errors doesn't make you happy when you're unfamiliar with a framework.

Second thing, you apperantly bind directly to the source and not the source.ItemsSource. After that it works fine. I tried binding to simple arrays of string using a binding of TitleText only and to a list of custom objects using TitleText Name as the binding string.


7. You lose access to your windows disk from mac when sleeping

2014-06-07

Not verified more than once. I switched over to MacOS and put the computer to sleep, still running Windows 8.1 in Parallels. When I resumed it the day after, Xamarin Studio was unable to find the project on Mac since I couldn't browse the windows disk from mac.

The solution was to restart the virtual machine. I'll follow this up if it happens again and try to come up with a solution.

8. MvxRelayCommand is now MvxCommand

It just is.

9. Lambda expression not working when binding to SelectionChangedCommand

Resolved: Just add a reference to System.Windows.

When trying to bind to the SelectionChangedCommand of the MvxStandardTableViewSource the following doesn't compile.

set.Bind(source).For(s => s.SelectionChangedCommand).To(vm => vm.PersonSelectedCommand);

But this do and works.

set.Bind(source).For(s => s.SelectionChangedCommand).To("PersonSelectedCommand");

The first fails with the error

Cannot convert 'lambda expression' to non-delegate type 'string'

I personally would prefer the first version to work to avoid compile time errors. But it's only a nice-to-have thing since there is a lot of other loose bindings around.
 

That's it for now

I do realize that this is a messy post and I'll do my best to replace it with a proper one after I get a full grip on this, if possible.

No comments:

Post a Comment