Thursday, May 10, 2012

Adding custom bindings in MvvmCross for Android/MonoDroid


The MvvmCross binding framework automatically adds one-way bind (from ViewModel to View) to all existing public Properties on any MonoDroid/Android View/widget.
If the public Property isn't of the correct type (e.g. it's some Android enumeration instead of a View), then you can use an IMvxValueConverter to do a conversion.
If you want to do 2-way binding, or there isn't a public Property for what you want to bind to, then you fairly easily do a custom binding. For an example of this, see the custom IsFavorite 2 way binding in the conference sample
This code adds a new bindable pseudo-property "IsFavorite" to every Android Button.
... this is initialised in Setup.cs using code like:
    protected override void FillTargetFactories(MvvmCross.Binding.Interfaces.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
    {
        base.FillTargetFactories(registry);

        registry.RegisterFactory(
                    new MvxCustomBindingFactory<Button>(
                       "IsFavorite", 
                       (button) => new FavoritesButtonBinding(button)));
    }
... and the binding code is:
public class FavoritesButtonBinding
    : MvxBaseAndroidTargetBinding
{
    private readonly Button _button;
    private bool _currentValue;

    public FavoritesButtonBinding(Button button)
    {
        _button = button;
        _button.Click += ButtonOnClick;
    }

    private void ButtonOnClick(object sender, EventArgs eventArgs)
    {
        _currentValue = !_currentValue;
        SetButtonBackground();
        FireValueChanged(_currentValue);
    }

    public override void SetValue(object value)
    {
        var boolValue = (bool)value;
        _currentValue = boolValue;
        SetButtonBackground();
    }

    private void SetButtonBackground()
    {
        if (_currentValue)
        {
            _button.SetBackgroundResource(Resource.Drawable.star_gold_selector);
        }
        else
        {
            _button.SetBackgroundResource(Resource.Drawable.star_grey_selector);
        }
    }

    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            _button.Click -= ButtonOnClick;
        }
        base.Dispose(isDisposing);
    }

    public override Type TargetType
    {
        get { return typeof(bool); }
    }

    public override MvxBindingMode DefaultMode
    {
        get { return MvxBindingMode.TwoWay; }
    }
}

Presenting modal UIViewControllers in MonoTouch using MvvmCross


MvvmCross starts from the premise that all ViewModels are just "normal pages" - so in iOS/MonoTouch that means UIViewControllers presented using a UINavigationController.
To move away from this premise - towards tabbed displays, modal displays, split controllers, popups, etc - then you can adjust the Presenter logic within your MonoTouch app.
The presenter's job is to implement:
public interface IMvxTouchViewPresenter
{
    void Show(MvxShowViewModelRequest view);
    void Close(IMvxViewModel viewModel);
    void CloseModalViewController();
    void ClearBackStack();
    bool PresentModalViewController(UIViewController controller, bool animated);
    void NativeModalViewControllerDisappearedOnItsOwn();
}
The presenter used for your app is selected in AppDelegate construction - e.g. see how theTwitterSearch builds different presenters for iPhone and iPad.

Fortunately, for simple Modal support, one of the standard presenters available isMvxModalSupportTouchViewPresenter.cs
This presenter looks to see if the view being presented has the IMvxModalTouchView marker interface - it tests view is IMvxModalTouchView. If this interface is present, then it uses modal presentation for the view instead of "normal navigation".
To use this, change your AppDelegate code to something:
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        window = new UIWindow(UIScreen.MainScreen.Bounds);

        // initialize app for single screen iPhone display
        var presenter = new MvxModalSupportTouchViewPresenter(this, window);
        var setup = new Setup(this, presenter);
        setup.Initialize();

        // start the app
        var start = this.GetService();
        start.Start();

        window.MakeKeyAndVisible();

        return true;
    } 
Then add the marker interface to your modal View(s):
 public class MyView : MvxBindingTouchViewController, IMvxModalTouchView
 {
      // ....
 }

Tuesday, May 01, 2012

If you install Visual Studio 11 and VSMonoTouch stops building with mscorlib problems...

If you install Visual Studio 11 and VSMonoTouch stops building with mscorlib problems...

or if you are seeing problems referencing simple Core types like System.Action...

Then:

1. Set the flag in Properties > Build > Advanced ... which says "Do not include mscorlib"

2. Make sure you have followed the vsmonotouch setup instructions:

A note on mscorlib.dll

The MonoTouch templates does not include an explicity reference to mscorlib.dll. The default behavior of Visual Studio 2010 is that all projects contain an implied reference to mscorlib.dll. The problem is that the implied version of mscorlib.dll is different from the MonoTouch mscorlib.dll, which will give you warnings in the editor. The project will compile just fine without the reference.

The other problem is how Visual Studio 2010 will not let you add a new reference to mscorlib.dll as it allready have that reference implied. The way to work around this is to add it manually by editing the .csproj file.

  <ItemGroup>
    <Reference Include="mscorlib" />
    <Reference Include="monotouch" />
    <Reference Include="System" />
    <Reference Include="System.Xml" />
    <Reference Include="System.Core" />    
  </ItemGroup> 

Visual Studio will now pick up the MonoTouch version of mscorlib.dll, and the project will still build just fine in MonoDevelop. The next update of the extension will enable you to automatically add this reference if missing.

Monday, April 30, 2012

Using Portable Library tools for MonoTouch and MonoDroid part 1....

Warning: This is only a part 1 post - I haven't worked out how to do part 2 yet!

To get MonoTouch and MonoDroid building with portable library project references in VS2010:
  1. Install the Portable Library tools -  http://visualstudiogallery.msdn.microsoft.com/b0e0b5e9-e138-410b-ad10-00cb3caf4981
  2. Install VSMonoTouch -  https://github.com/follesoe/VSMonoTouch
    - be sure to also copy across the v1.0 framework assemblies in the instructions there
  3. Follow the instructions on  http://jpobst.blogspot.co.uk/2012/04/mono-for-android-portable-libraries-in.html
    - which basically say to install a file called "MonoAndroid,Version=v1.6+.xml" in "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\Profile2\SupportedFrameworks" with content:

    <?xml version="1.0" encoding="utf-8"?><Framework DisplayName="Mono for Android" Identifier="MonoAndroid" MaximumVersion="*" MinimumVersion="1.6" Profile="*"/>
  4. Installl a similar file called "VSMonoTouch,Version=v1.0+.xml" in the same directory and for its content use:

    <?xml version="1.0" encoding="utf-8"?><Framework  DisplayName="VS MonoTouch" Identifier=".NETFramework" MaximumVersion="1.0" MinimumVersion="1.0" Profile="*" />(Note: this file is even hackier than the MonoDroid one - it points the portable tools at Full .Net v1.0 in line with what the VSMonoTouch plugin does!)
  5. That's it!

Although.... if you do want to use System.Net classes within MonoDroid, then you'll also need to add a proxy assembly for it - a MonoDroid class library project producing a DLL called System.Net and containing a single C# file with contents:

using System.Runtime.CompilerServices;
 
/*
 * not available in MonoDroid :/
[assembly: TypeForwardedTo(typeof(System.Net.Sockets.UdpAnySourceMulticastClient))]
[assembly: TypeForwardedTo(typeof(System.Net.Sockets.UdpSingleSourceMulticastClient))]
[assembly: TypeForwardedTo(typeof(System.Net.DnsEndPoint))]
[assembly: TypeForwardedTo(typeof(System.Net.WriteStreamClosedEventHandler))]
[assembly: TypeForwardedTo(typeof(System.Net.WriteStreamClosedEventArgs))]
*/
 
[assemblyTypeForwardedTo(typeof(System.Net.Cookie))]
[assemblyTypeForwardedTo(typeof(System.Net.CookieCollection))]
[assemblyTypeForwardedTo(typeof(System.Net.CookieContainer))]
[assemblyTypeForwardedTo(typeof(System.Net.CookieException))]
[assemblyTypeForwardedTo(typeof(System.Net.Dns))]
[assemblyTypeForwardedTo(typeof(System.Net.EndPoint))]
[assemblyTypeForwardedTo(typeof(System.Net.WebProxy))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpRequestHeader))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpStatusCode))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpVersion))]
[assemblyTypeForwardedTo(typeof(System.Net.DecompressionMethods))]
[assemblyTypeForwardedTo(typeof(System.Net.WebRequest))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpWebRequest))]
[assemblyTypeForwardedTo(typeof(System.Net.WebResponse))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpWebResponse))]
[assemblyTypeForwardedTo(typeof(System.Net.ICertificatePolicy))]
[assemblyTypeForwardedTo(typeof(System.Net.ICredentials))]
[assemblyTypeForwardedTo(typeof(System.Net.HttpContinueDelegate))]
[assemblyTypeForwardedTo(typeof(System.Net.IPAddress))]
[assemblyTypeForwardedTo(typeof(System.Net.IPEndPoint))]
[assemblyTypeForwardedTo(typeof(System.Net.IPHostEntry))]
[assemblyTypeForwardedTo(typeof(System.Net.IWebRequestCreate))]
[assemblyTypeForwardedTo(typeof(System.Net.NetworkCredential))]
[assemblyTypeForwardedTo(typeof(System.Net.ProtocolViolationException))]
[assemblyTypeForwardedTo(typeof(System.Net.ServicePoint))]
[assemblyTypeForwardedTo(typeof(System.Net.ServicePointManager))]
[assemblyTypeForwardedTo(typeof(System.Net.WebHeaderCollection))]
[assemblyTypeForwardedTo(typeof(System.Net.SocketAddress))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketException))]
[assemblyTypeForwardedTo(typeof(System.Net.WebClient))]
[assemblyTypeForwardedTo(typeof(System.Net.OpenReadCompletedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.OpenReadCompletedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.OpenWriteCompletedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.OpenWriteCompletedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.DownloadStringCompletedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.DownloadStringCompletedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.UploadStringCompletedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.UploadStringCompletedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.DownloadProgressChangedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.DownloadProgressChangedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.UploadProgressChangedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.UploadProgressChangedEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.WebException))]
[assemblyTypeForwardedTo(typeof(System.Net.WebExceptionStatus))]
[assemblyTypeForwardedTo(typeof(System.Net.NetworkInformation.NetworkAddressChangedEventHandler))]
[assemblyTypeForwardedTo(typeof(System.Net.NetworkInformation.NetworkChange))]
[assemblyTypeForwardedTo(typeof(System.Net.NetworkInformation.NetworkInterface))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.AddressFamily))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.LingerOption))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.MulticastOption))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.IPv6MulticastOption))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.Socket))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.ProtocolType))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SelectMode))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketAsyncOperation))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketAsyncEventArgs))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketError))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketFlags))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketOptionLevel))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketOptionName))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketShutdown))]
[assemblyTypeForwardedTo(typeof(System.Net.Sockets.SocketType))]


This approach based on a hint in  http://stackoverflow.com/questions/10361457/is-it-possible-to-use-a-portable-class-library-that-references-system-net-in-mon

I will blog more about this stuff... when I get the final part working - which is building these projects in MonoDevelop on the Mac - currently that's #fail :(

Sunday, April 29, 2012

Using Flurry Analytics from MonoTouch, MonoDroid and WP7 (MvvmCross)

UPDATE - want to do more - someone took this code on to the next level - http://blog.martinlegris.com/2012/11/14/flurry-api-in-mono-for-android/

----

Within a recent MvvmCross project, we used www.flurry.com for our analytics.


Basically what we did was log all important events from the ViewModel using an IAnalytics interface, and then each platform supplied an implementation of IAnalytics like:
WP7:
public class FlurryAnalytics : IAnalytics
{
    public const string ApiKeyValue = "--- your key ---";

    public void StartSession()
    {
        FlurryWP7SDK.Api.StartSession(ApiKeyValue);
    }

    public void LogEvent(string eventName)
    {
        FlurryWP7SDK.Api.LogEvent(eventName);
    }
}
public class FlurryAnalytics : IAnalytics
{
    public const string ApiKeyValue = "37SHD8L8VATPBS88AMHU";

    public void StartSession()
    {
        FlurryAPI.StartSession (ApiKeyValue);
    }

    public void LogEvent(string eventName)
    {
        FlurryAPI.LogEvent(eventName);
    }
}
Android (a bit more complicated - it needs a hook from every start/stop of an activity):
public class FlurryAnalytics : IAnalytics, IAndroidActivityTracker
{
    public const string ApiKeyValue = "--- your key ---";

    private readonly IntPtr _flurryClass;
    private readonly IntPtr _flurryOnStartSession;
    private readonly IntPtr _flurryOnEndSession;
    private readonly IntPtr _flurryLogEvent;

    public FlurryAnalytics()
    {
        _flurryClass = JNIEnv.FindClass("com/flurry/android/FlurryAgent");
        _flurryOnStartSession = JNIEnv.GetStaticMethodID(_flurryClass, "onStartSession",
                                                         "(Landroid/content/Context;Ljava/lang/String;)V");
        _flurryOnEndSession = JNIEnv.GetStaticMethodID(_flurryClass, "onEndSession", "(Landroid/content/Context;)V");
        _flurryLogEvent = JNIEnv.GetStaticMethodID(_flurryClass, "logEvent", "(Ljava/lang/String;)V");
    }

    public void StartSession()
    {
        // not used in Android - Android relies on Activity tracking instead
    }

    public void LogEvent(string eventName)
    {
        ExceptionSafe(() => JNIEnv.CallStaticVoidMethod(_flurryClass, _flurryLogEvent, new JValue(new Java.Lang.String(eventName))));
    }

    private static void ExceptionSafe(Action action)
    {
        try
        {
            action();
        }
        catch (ThreadAbortException)
        {
            throw;
        }
        catch (Exception exception)
        {
            UITrace.Trace("Exception seen in calling Flurry through JNI " + exception.ToLongString());
        }
    }

    public void OnStartActivity(Activity activity)
    {
        ExceptionSafe(() => JNIEnv.CallStaticVoidMethod(_flurryClass, _flurryOnStartSession, new JValue(activity), new JValue(new Java.Lang.String(ApiKeyValue))));
    }

    public void OnStopActivity(Activity activity)
    {
        ExceptionSafe(() => JNIEnv.CallStaticVoidMethod(_flurryClass, _flurryOnEndSession, new JValue(activity)));
    }
}

Each of these platforms simply injected their implementation into IoC during setup - .i.e:

    this.RegisterServiceInstance (new FlurryAnalytics());
Among the messages recorded were the creation of every ViewModel - which gave us an easy to see picture of which pages were being used in our app. We did this through a BaseViewModel implementation which logged its type name on creation - simple, quick and clean:

public abstract class BaseViewModel 
    : MvxViewModel
    , IMvxServiceConsumer
{
    #region Protected API

    protected BaseViewModel()
    {
        Analytics.LogEvent("ViewModelCreate:" + GetType().Name);
    }

    protected IAnalytics Analytics
    {
        get { return this.GetService(); }
    }
}

Thursday, April 26, 2012

Calculating distance between lat/lng points in MvvmCross


Currently mvvmcross has deliberately not included lat/lng calculations.
The motivation for this was:
  • to keep the code size down - not every app needs those calculations
  • further I have in my mind that some calculations are better done by native libraries rather than generic C# - e.g. some polygon calculations would benefit from native hardware acceleration. This type of thought is there not only for geo-calcuations, but also for other areas - e.g. whereever things like image manipulation are required, then using native acceleration makes sense.
It may be that mvvmcross provides an "official" location helper IoC plugin (or set of extension methods) at some point in the future... e.g. it maybe that we build an IoC plugin around http://xamarin.com/mobileapi... and I'm also very happy for others to build and publish them too.
So....
At a very simple level, working out the distance between two lat/lng points is easy to do in C# - there are heaps of fairly simple code example available like the excellent javascript ones at http://www.movable-type.co.uk/scripts/latlong.html - and there are heaps of libraries on github and codeplex likehttp://sharpmap.codeplex.com/
In RunSat (including on iPhone) I use:
using System;

namespace Cirrious.NewRunSat.Core.Models.Utils
{
    public class DistanceCalcs
    {
        /// 
        /// Calculates the distance between two points of latitude and longitude.
        /// Great Link - http://www.movable-type.co.uk/scripts/latlong.html
        /// 
        /// 
First coordinate.
        /// 
First coordinate.
        /// 
Second coordinate.
        /// 
Second coordinate.
        /// the distance in metres
        public static Double DistanceInMetres(double lat1, double lon1, double lat2, double lon2)
        {

            if (lat1 == lat2 && lon1 == lon2)
                return 0.0;

            var theta = lon1 - lon2;

            var distance = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) +
                           Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) *
                           Math.Cos(deg2rad(theta));

            distance = Math.Acos(distance);
            if (double.IsNaN(distance))
                return 0.0;

            distance = rad2deg(distance);
            distance = distance * 60.0 * 1.1515 * 1609.344;

            return (distance);
        }

        private static double deg2rad(double deg) {
          return (deg * Math.PI / 180.0);
        }

        private static double rad2deg(double rad) {
          return (rad / Math.PI * 180.0);
        }
    }
}
Note that the license on this snippet is CC attribution - because its derived from movable type -http://www.movable-type.co.uk/scripts/latlong.html:
I offer these formulæ & scripts for free use and adaptation as my contribution to the open-source info-sphere from which I have received so much. You are welcome to re-use these scripts [under a simple attribution license, without any warranty express or implied] provided solely that you retain my copyright notice and a reference to this page.

Supplying separate iPad and iPhone views in a single Universal iOS MvvmCross project (MonoTouch)


The default convention used by the MvvmCross platform is to automatically register all views using reflection.
    protected virtual void InitializeViews()
    {
        var container = this.GetService();

        foreach (var pair in GetViewModelViewLookup())
        {
            Add(container, pair.Key, pair.Value);
        }
    }
where GetViewModelViewLookup returns a dictionary of ViewModel type to View type:
    protected virtual IDictionary GetViewModelViewLookup(Assembly assembly, Type expectedInterfaceType)
    {
        var views = from type in assembly.GetTypes()
                    let viewModelType = GetViewModelTypeMappingIfPresent(type, expectedInterfaceType)
                    where viewModelType != null
                    select new { type, viewModelType };

        return views.ToDictionary(x => x.viewModelType, x => x.type);
    }
In universal iPad/iPhone apps you do occasionally want to include multiple views for each viewmodel - using one view in the iPad and one view in the iPhone.
To do this, there are now (literally just now!) some attributes available to mark your views as being "unconventional" - these are:
The last of these is probably what you want in this case - you could implement simple iPhone/iPad switching for a MainViewModel using two views declared like:
[MvxFormFactorSpecificView(MvxTouchFormFactor.Phone)]
public class MyIPhoneView : BaseView
{
    // iphone specific view ...
}

[MvxFormFactorSpecificView(MvxTouchFormFactor.Pad)]
public class MyIPadView : BaseView
{
    // ipad specific view ...
}

Alternatively if you want a very custom configuration, you can override all 'convention-based' behaviour - you can implement your own override of GetViewModelViewLookup - e.g.:
protected override IDictionary GetViewModelViewLookup(Assembly assembly, Type expectedInterfaceType)
{
    if (IsIPad)
    {
        return new Dictionary() 
        {
            { typeof(HomeViewModel), typeof(IPadHomeView) },
            { typeof(DetailViewModel), typeof(IPadDetailView) },
            { typeof(AboutViewModel), typeof(SharedAboutView) },
        };
    }
    else
    {
        return new Dictionary() 
        {
            { typeof(HomeViewModel), typeof(IPhoneHomeView) },
            { typeof(DetailViewModel), typeof(IPhoneDetailView) },
            { typeof(AboutViewModel), typeof(SharedAboutView) },
        };
    }
}

Note that eventually you may decide that you need additional ViewModels as well as Views for the iPad app - the iPad has, after all, a much bigger screen - in this case you can add them manually. Ultimately, when your app hits a few million users, you may even decide to completely branch the tablet code away from the phone code - but that can generally wait until you hit that few million mark...

Getting Location information in MvvmCross

I've added a lesson in the tutorial that shows the IMvxGeoLocationWatcher location fetching interface being used.
      private void DoStartStop()
      {
          if (!IsStarted)
          {
              _watcher.Start(new MvxGeoLocationOptions() { EnableHighAccuracy = true }, OnNewLocation, OnError);
          }
          else
          {
              _watcher.Stop();
          }
          IsStarted = !IsStarted;
      }
      private void OnError(MvxLocationError error)
      {
          // TODO - shuold handle the error better than this really!
          LastError = error.Code.ToString();
      }
      private void OnNewLocation(MvxGeoLocation location)
      {
          if (location != null && location.Coordinates != null)
          {
              Lat = location.Coordinates.Latitude;
              Lng = location.Coordinates.Longitude;
          }
      }  
This seems to work OK on:
I haven't yet written the code for WinRT...

Saturday, April 21, 2012

Experiments with Portable Class LIbraries - mvvmcross

I've tried to refactor mvx into portable class libraries today.

Initial results have been quite promising - so I think it will happen for real at some point soon.

The basic approach I've taken is to create a "core" mvvmcross portable library:


This single project contains 90% of the mvx code.

The code that doesn't fit into this is all platform specific and interface driven - i.e. it's things like the platform specific views, navigation and container code; or platform specific services like file IO, GPS/location information, launchers and choosers, etc. This code is now moved to small platform specific library projects:




The Binding and Dialog projects for now remain untouched - that's OK because they were never shared by the "core" projects any way - so they are always platform specific and there's no advantage in making those portable.

Moving on the sample projects, well the core of these can now be made portable:


So there is only one "core" project shared between all three ui projects - which is NICE :)


However, there are some problems currently…

  • I've not quite finished! I've got the tutorial sample up and running, but there are still a few platform specific injection objects to make before all the samples will run... and there's lots more testing needed:
    • A Json object
    • A Native Color object
    • A Visibility Color object
  • ObservableCollections are a bit unpleasant to use - INotifyCollectionChanged doesn't exist as a portable interface :/ Because of this any kind of observable collection will need to be wrapped for presentation on wp7
  • ValueConverters are a bit unpleasant to use – IValueConverter doesn't exists as a portable interface :/  Because of this all value converters need to be wrapped before use on wp7
  • I've no idea how this would work in WinRT yet – there will definitely be reflection and interface issues in .net 4.5
  • I don't know what the next version (v2) of the portable class libraries will look like yet!
  • The monotouch and monodroid visual studio tooling isn't working nicely yet – you can't yet reference a portable library project from mt and md, you can only reference a compiled assembly – which means you can't do multi-platform refactoring.
  • Forcing the core projects to be portable may be too limiting... the list of assemblies you can now reference is small.... 

I need to think about this some more.... I think portable class libraries is probably the right direction moving forwards - in the long term! But it's not all upside....

Thursday, April 19, 2012

Wow - PlayStationSuite Open Beta - C# on the PS Vita

Someone tweeted about this -  http://www.playstation.com/pss/developer/index_e.html

So I downloaded it and had thirty minutes of playtime :)

Here's a video of my experience: http://youtu.be/FSZl1-FvUgE





Firstly I played with the UI Composer (designer) - and set up a tip calc like display (like the one in https://github.com/slodge/MvvmCross/ for MonoTouch, MonoDroid, WP7 and WinRT)

It was easy to do - just drag and drop the UI elements, then set their properties, including the generated variable name to use.

When finished, I just hit "Build" in the designer - this spits out:
  • a language csv resource file
  • a C# wrapper for that resource file
  • a scene.cs file - just a partial class with a constructor - this then becomes your "view controller" file for you to edit as you please
  • a scene.composer.cs file - this contains the generated code for the rest of the partial class - basically lots of layout code which matches what you drew in the designer


With that done I then I opened the main PSS Studio (looks and feels like MonoDevelop)

In this studio I:
- ran the new project wizard
- followed the simple instructions in the bundled help file to add the high level ui reference to the project and to add a little code (3 lines?) to help it render
- used project|add to add the files generated above
- tweaked the BuildAction Property for the Csv file to 'content'
- used the monodevelop editor to add the code for tipCalc - this was normal C# code:





using System;
using System.Collections.Generic;
using Sce.Pss.Core;
using Sce.Pss.Core.Imaging;
using Sce.Pss.Core.Environment;
using Sce.Pss.HighLevel.UI;
 
namespace PssUI1
{
    public partial class Scene1 : Scene
    {
        public Scene1()
        {
            InitializeWidget();
   HookThingsUp();
  }
  
  private void HookThingsUp()
  {
   SliderPercent.ValueChanged += (s, e) => {
    TipPercentText.Text = ((int)e.Value).ToString();
    Recalc();
   };
   TipPercentText.TextChanged += (s, e) => {
    SliderPercent.Value = int.Parse(TipPercentText.Text);
    Recalc();
   };
   TotalText.TextChanged += (s, e) => {
    Recalc();
   };
   Recalc();
  }
  
  private void Recalc()
  {
   var total = double.Parse(TotalText.Text);
   var tip = SliderPercent.Value * total / 100.0;
   total += tip;
   this.TipLabel.Text = tip.ToString();
   this.TotalLabel.Text = total.ToString(); 
  } 
    }
}


That was it!

Then I could hit F5 and the code ran in a PS Vita simulator:

That was it!

:) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :)

 
For a full blow by blow video: 
http://youtu.be/FSZl1-FvUgE


Really impressed - good job Mono (Xamarin?) and Sony - really good job :)

Sunday, April 15, 2012

video of me talking MvvmCross at wpug - MonoTouch, MonoDroid, WP7 and WinRT MVVM - also... the internet is full of kittens



Not the best audio quality - sorry

Also had some techical issues with the projector resolution... and ran out of time - I blame Matt - he asked me for an hour, then cut me down to 45 minutes on the day!

http://vimeo.com/39019207

Friday, March 30, 2012

Slides from my talk at @DevEvening this week

Similar talk to last week - just thinned down a bit (not everyone in the room was a mobile dev) and also I had slightly longer to talk and managed to pace it better.

Monday, March 26, 2012

Some HTML, Javascript, Jquery, D3.js and CoffeeScript magic - a bit like an html pivotviewer

I put this demo together last week for a school project -  http://slodge.com/teach/

It uses all sorts of html and js goodness inside and it's definitely at prototype stage - but I'm thinking about ways it could grow and change....

Ideally I'd quite like to get access to raw data from school SIMS databases. I will investigate further - but I am not paying GBP5000 for an SDK

MvvmCross slides from my @wpug talk last week

Slides from my @wpug talk last week - will shorten them for this week's DevEvening talk - always learning :)

Saturday, March 24, 2012

Update on MvvmCross - SQLBits conference app

I've been working on a lot of Mvvm on MonoTouch, MonoDroid and WP7 recently - and I've added a bit of WinRT too. 

I've built an Mvvm framework - mvvmcross for this - and it enables code sharing and databinding acoss all the platforms.

As an example app, I've just built and released the SQL Bits conference app. Source code is on https://github.com/slodge/MvvmCrossConference and screenshots are below:

On WP7:


On Android:


On iOS:


All of these apps are **Native apps** using MvvmCross on top of WP7 SDK, MonoTouch and MonoDroid