Single Row GridView using MvvmCross, Infragistics NucliOS, and Xamarin.iOS

MvvmCross is a fantastic framework create by Stuart Lodge. It’s my go-to framework for cross platform development, and works great for any app, regardless of size. Here is a link to the projects GitHub page. Stuart has an excellent series (N+1) on his YouTube Channel as well.

The following example will demonstrate how to create a Core portable project that contains our Models, and ViewModels, as well as an iOS project that uses an Infragistics Grid. MvvmCross is extremely flexible, and allows us to create and register custom bindings, so we can create our own ‘magic’. The source code for this example can be found on GitHub.

Step 1.) Create a new C# PCL Project. We’ll be displaying a collection of Monkey Images, so we’ll name our solution MonkeysList. Since this is the Core project, we’ll call it MonkeysList.Core.

Create new PCL Project

Step 2.) Choose your target platforms for the PCL project. We’ll chose to target Windows Phone 7.5 and higher, Mono for Android, and Monotouch.

2

Step 3.)  Add MvvmCross References. One of the easiest ways to do this is by using Nuget. Search for MvvmCross, and select MvvmCross (It should be the first one in the list).

3

Step 4.) Create Model. Adding the Nuget Packages generates some free code for us! The first thing we’ll do is delete the class.cs file that was created when the PCL project was first created. Next create a folder named Models, and a class Named Monkey, that has a single string type property called ImageUrl.

public class Monkey
{
    public string ImageUrl { get; set; }
}

Step 5.) Create a service that generates a Monkey. This is trivial. First, we need to create a folder called Services. The first that goes in this folder is an Interface, with a single method that creates a Monkey. Next, we need to create a class that Implements this implements this interface.

public interface IMonkeyGenerator
{
     Monkey GenerateMonkey();
}
public class MonkeyGeneratorService : IMonkeyGenerator
{
   public Monkey GenerateMonkey()
   {
     return new Monkey {ImageUrl = string.Format("http://placemonkey.heroku.com/{0}/{0}", Random(20) + 500)};
   }private readonly Random _random = new Random();
 protected int Random(int count)
 {
   return _random.Next(count);
 }
}

Step 6.) Add Monkeys to ViewModel. One of the items created when installing the Nuget packages is FirstViewModel. This comes with an example property. We’ll delete the example, and new list of Monkey. Next, we’ll use MvvmCross to resolve our MonkeyGeneratorService, and use it to create our list of Monkeys. This is done in the class constructor.

public class FirstViewModel 
 : MvxViewModel
 {
 public FirstViewModel()
 {
  //Resolve IMonkeyGenerator from Ioc
  var svc = Mvx.Resolve<IMonkeyGenerator>();
  var monkeys = new List<Monkey>();
 for (int i = 0; i < 20; i++)
 {
   //Generate Monkeys!
   monkeys.Add(svc.GenerateMonkey());
 }
  Monkeys = monkeys;
}
 private List<Monkey> _monkeys;
 public List<Monkey> Monkeys
 {
  get { return _monkeys; }
  set
  {
   _monkeys = value;
   RaisePropertyChanged(() => Monkeys);
  }
 } 
}

That’s it for the PCL project! Below is a picture of what all you should have so far.

4

Step 7.) Create a new Empty iOS project named MonkeysList.Touch
Step 8.) Use Nuget to add MvvmCross to iOS project.
Step 9.) Add a reference to your Core project.
Step 9.) Follow the instructions in ToDo-MvvmCross folder, and replace AppDelegate.cs with the following Code.

 [Register ("AppDelegate")]
 public partial class AppDelegate : MvxApplicationDelegate
 {
   UIWindow _window;
   public override bool FinishedLaunching(UIApplication app, NSDictionary options)
  {
     _window = new UIWindow(UIScreen.MainScreen.Bounds);
     var setup = new Setup(this, _window);
     setup.Initialize();
     var startup = Mvx.Resolve<IMvxAppStart>();
     startup.Start();
    _window.MakeKeyAndVisible();
    return true;
  }
}

Step 11.) Create GridView using Infragistics.

[Register("SingleRowGridView")]
 public class SingleRowGridView : UIView
 {
 //GridView that is displayed
 public IGGridView GridView;
//Column Definition of GridView's column
 private IGGridViewImageColumnDefinition _col;
//Datasource Helper to assist with databinding
 public IGGridViewSingleRowSingleFieldDataSourceHelper Ds;
public SingleRowGridView()
 {
 Initialize();
 }
public SingleRowGridView(RectangleF bounds)
 : base(bounds)
 {
 Initialize();
 }
void Initialize()
 {
BackgroundColor = UIColor.Black;
//Create a Gridview that's a bit farther down than center
 //This Grid has a single row of 200x200 cells
 GridView = new IGGridView(new RectangleF(0f, Frame.Size.Height / 2 - 100, Frame.Size.Width, 200f), IGGridViewStyle.IGGridViewStyleDefault)
 {
 AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin | UIViewAutoresizing.FlexibleTopMargin,
 SelectionType = IGGridViewSelectionType.IGGridViewSelectionTypeCell,
 HeaderHeight = 0f,
 EmptyRows = false,
 RowSeparatorHeight = 0f,
 AllowHorizontalBounce = true,
 AlwaysBounceVertical = false,
 RowHeight = 200f,
 ColumnWidth = IGColumnWidth.CreateNumericColumnWidth(200f),
 Theme = new IGGridViewLightTheme()
 };
AddSubview(GridView);
  //Create Image Column definition for Image property that gets the image from a URL
  _col = new IGGridViewImageColumnDefinition(@"Image",
 IGGridViewImageColumnDefinitionPropertyType
 .IGGridViewImageColumnDefinitionPropertyTypeStringUrl);
   //Create a new Datasource helper that is initialized with the column we just created
   Ds = new IGGridViewSingleRowSingleFieldDataSourceHelper(_col);

   //set the Grid's datasource to the one that we created
   GridView.DataSource = Ds;
   GridView.ReloadData();
  }
}

Step 12.) To bind data to an Infragistics datasource helper, the binding class must inherit from NSObject. This is one of the reasons that we have to implement a custom binding solution in MvvmCross.

//The DataSource helper's data property must be of type NSObject
 [Register("SingleRowData")]
 public class SingleRowData : NSObject
 {
    public SingleRowData(string image)
    {
      Image = image;
    }
   [Export("Image")]
    public string Image { get; set; }
 }

Step 13.) Create Target Binding for our GridView. First, create a new folder named Target. Add a class named SingleRowDataSourceTargetBinding. This class will Inherit from MvxTargetBinding, and override SetValue, TargetType, and DefaultMode. SetValue gets called when the Property Change notification is fired, and is where

//Inherit from MvxTarget binding to perform custom binding 
 public class SingleRowDataSourceTargetBinding : MvxTargetBinding
 {
 //Return View as User Defined View
 protected SingleRowGridView View
 {
     get { return Target as SingleRowGridView; }
 }
public SingleRowDataSourceTargetBinding(SingleRowGridView view)
 : base(view)
 {
    if (view == null)
    {
      MvxBindingTrace.Trace(MvxTraceLevel.Error, "Error - GridViewSource is null in SingRowDataSourceTargetBinding");
    }
 }
//Override SetValue to perform binding
 public override void SetValue(object value)
 {
   var view = View;
   if (view == null)
     return;

   var monkeys = (List<Monkey>)value;   //Grab items from list that was passed in, and create new NSObject[]
 if (monkeys != null)
 {
    View.Ds.Data = monkeys.Select(t => new SingleRowData(t.ImageUrl)).ToArray();
  //Must Call ReloadData 
    View.GridView.ReloadData();
    }
  }
//Set the target type
 public override Type TargetType
 {
    get { return typeof(NSObject[]); }
 }
//Set the Default binding Mode
 public override MvxBindingMode DefaultMode
 {
    get { return MvxBindingMode.OneWay; }
 }
}

Step 14.) Register the Target Binding just created. In the Setup.cs class that was generated from adding MvvmCross from Nuget, override the FillTargetFactories method, and register the target binding.

//Set up Target Bindings
 protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
 {
    registry.RegisterCustomBindingFactory<SingleRowGridView>("SingleRowData", source => new SingleRowDataSourceTargetBinding(source));
    base.FillTargetFactories(registry);
 }

Step 15.) Edit FirstView, set up bindings, and profit! Delete the code that was generated by MvvmCross for binding to the example HelloWorld string. Add a new SingleRowGridView to FirstView, and create the bindings.

[Register("FirstView")]
 public class FirstView : MvxViewController
 {
    private SingleRowGridView _gridView;
   public override void ViewDidLoad()
   {

     base.ViewDidLoad();
    //Initialize new SingleRowGridView
    _gridView = new SingleRowGridView(View.Bounds);
   // ios7 layout
   if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
       EdgesForExtendedLayout = UIRectEdge.None;

   //Bind GridView 
   var set = this.CreateBindingSet<FirstView, Core.ViewModels.FirstViewModel>();
   set.Bind(_gridView).For("SingleRowData").To(vm => vm.Monkeys);
   set.Apply();
  Add(_gridView);
 }
}

Here’s what the end result looks like.

iOS Simulator Screen shot Oct 14, 2013 11.26.48 PM

Thanks for stopping by! Enjoy!