MVVM Light V4.4 with Xamarin Android support

.NET, MVVM, Phone, Silverlight, Technical stuff, Windows 8, Windows Phone, Work, WPF, Xamarin
See comments

I just published MVVM Light V4.4 to Nuget. For now, this is only the “libraries only” package as I still have some testing to do on the full package as well as on the PCL package.

A “formal” list of changes can be seen here.

Possible breaking change

Let’s start with a possible breaking change. After much feedback “from the field”, I decided to change the names of the MVVM Light DLLs to remove the indication of the framework that they are built for. This might require you to update your XAML files accordingly. I am sorry if that causes you some effort, but I think it makes sense, considering that we are encouraged to share some XAML between the platforms (for example between WinStore and WinPhone), and the naming was breaking this.

So if until now you had (for example) GalaSoft.MvvmLight.WP8.dll, the new assembly is now named GalaSoft.MvvmLight.dll only.

Why was there even “.WP8.DLL” in the first place

At some point early in MVVM Light’s life, I found out that many of the support requests were due to people mistakenly using the WPF DLL in Silverlight. When it was failing to build, they would send me a support request. In order to avoid this, I decided to add “WPF” and “SL” in the DLL name to make things clearer. I then continued with “WP7″, “WP8″, “Win8″, etc. By removing this indication, I hope that I won’t see a rise in this kind of support request again… but I think that by now we are used to having multiple XAML-based platforms.

So what’s new in V4.4

I decided to publish V4.4 even though the “full” package is not ready yet because I had a lot of requests for a Xamarin version of MVVM Light. V4.4 now supports Xamarin Android (see below the paragraph about iOS).

With V4.4, you can do the following steps to add MVVM Light support to a Xamarin application. This small example shows how to create a ViewModel with an observable property and a command, use the VM in an Activity, and add a binding between the observable property and the text of a Button. It also shows how to execute the Command when the button is clicked.

  • Create a new Android application.
  • Add the package “MvvmLightLibs” to your application.
  • Add a new folder named ViewModel.
  • Add a new class named MainViewModel in this folder.
  • Edit the MainViewModel class to look like below. Note that you can use the “mvvminpcsetlambda” and the “mvvmrelay” code snippets of MVVM Light to add the observable property and the command.
public class MainViewModel : ViewModelBase
{
    private int _index;

    public const string HelloPropertyName = "Hello";

    private string _hello = "Hello!";

    public string Hello
    {
        get
        {
            return _hello;
        }
        set
        {
            Set(() => Hello, ref _hello, value);
        }
    }

    private RelayCommand _incrementCommand;

    public RelayCommand IncrementCommand
    {
        get
        {
            return _incrementCommand
                ?? (_incrementCommand = new RelayCommand(
                () =>
                {
                    Hello = string.Format(
                        "Hello! {0} click(s)", ++_index);
                }));
        }
    }
}
  • Edit the MainActivity as follows:
[Activity(
    Label = "AndroidApplication4", 
    MainLauncher = true, 
    Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    private MainViewModel _vm;
    private Button _myButton;

    public MainViewModel Vm
    {
        get
        {
            return _vm ?? (_vm = new MainViewModel());
        }
    }

    public Button MyButton
    {
        get
        {
            return _myButton 
                ?? (_myButton = FindViewById<Button>(Resource.Id.MyButton));
        }
    }

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        this.AddBinding(
            () => Vm.Hello,
            () => MyButton.Text);

        MyButton.AddCommand(
            "Click",
            Vm.IncrementCommand);
    }
}
  • Run the application and click the button. This will actuate the RelayCommand, modify the observable property, which will raise the PropertyChanged event. The data binding will react and update the Button.Text property accordingly.

What are these “AddBinding” and “AddCommand” methods?

In short (because I will write a lot more about this), these are extension methods which are specific to MVVM Light for Xamarin.

AddBinding creates a data binding between two properties. There are multiple ways to create data bindings using this method (for example with BindingMode.OneTime, OneWay, TwoWay) and more guidance will follow soon.

AddCommand binds an ICommand to a UI element, and actuates the command when the corresponding event is raised. Note that this can be any event, and that CommandParameters are also supported. Here too, more guidance will come up soon.

What’s next for Xamarin Android?

In the next few days I will publish a much more complete sample showing how to create a full blown MVVM Light application using SimpleIoc, RelayCommand, ViewModelBase and ObservableObject, a simple NavigationService, two-way Binding etc.

The next step for MVVM Light for Xamarin Android will be to publish a project template and a few item templates specifically for MVVM Light Android. This will allow you to do “File, New Project” in Visual Studio and to get a ready-to-work MVVM Light application.

You will also get item templates for a new ViewModel, a new ViewModelLocator, and a new Activity.

What about iOS?

I want to offer the same level of comfort on Xamarin iOS as on Android. This will however take more time. For multiple reasons, it was much easier to start with Android, and I think it makes sense to publish the Android version (and gather feedback) before the iOS version is complete. This is a work in progress.

And Portable Class Libraries?

Here too, this will follow soon. I decided to publish the non-PCL version first as this was a very frequent request, and the PCL version needs a little more testing first. Stay tuned.

Use with caution! Feedback please!

The Android version of MVVM Light is clearly a work in progress, and I would like to advise caution when using it. While the components (SimpleIoc, Messenger, RelayCommand etc) should work just fine, the Binding library is a brand new development. I have ran quite a lot of tests, but I fully expect it to change in the next few weeks/months.

This is where you play a big role, dear Xamarin developers! Please provide feedback! The best place to do that is on Codeplex (http://mvvmlight.codeplex.com) where we can have a discussion. I will follow this attentively.

As usual, thanks for your patience and for your amazing enthusiasm. I cannot wait to see what you guys create with MVVM Light for Xamarin.

Happy coding
Laurent

Previous entry | Next blog entry

Responses to “MVVM Light V4.4 with Xamarin Android support”

  1. MVVM Light V4.4 with Xamarin Android support Says:

    […] /* 0) { ratingctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating = result[‘Rating’]; SetCurrentRating(‘ctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating_pnlHolder’, result[‘Rating’], “disabled fullStar”, “disabled emptyStar”, true); if(votesCountctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating!=null) { votesCountctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating ++; SetVotesCount(‘ctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating_lblUsersRated’, ‘(‘ + votesCountctl00_cphMiddle_cphContent_tr3w45fwwvre_itemRating + ‘ votes)’); } SetRatingCookie(‘r’, ‘i35499′, ‘1’); } else if (result[‘Status’] == 1) { alert(‘The session has expired. Please refresh the page to be able to vote!’); } } /* ]]> */ (0 votes) 0 comments   /   posted by Silverlight Show on May 08, 2014 Tags:   mvvm-light , silverlight , wpf , windows-phone , windows-8 , laurent-bugnion Read original post by Laurent Bugnion at GalaSoft […]

  2. JasonBSteele Says:

    Hi Laurent,

    I think it’s worth mentioning that MvvmCross already provides Android, iOS, Windows Phone, WPF etc. support, and of course was originally a fork of the excellent MVVM Light.

    I’d be interested to here your thoughts on where you think the two frameworks differ and why one might adopt one over the other. Thanks.

  3. lbugnion Says:

    Hi,

    MVVM Cross is quite a lot more complex than MVVM Light. Part of the success of MVVM Light on Microsoft platforms is due to its simplicity. Because of this, and by popular demand, I decided to bring it to the Xamarin world as well.

    Cheers
    Laurent

  4. Umair Says:

    Hi Laurent,
    I want to conform, weather MVVM Light till now provide support for IOS or not. please help in this

  5. lbugnion Says:

    Hi,

    Yes MVVM Light works with iOS too. Please select the PCL version in Nuget. At this time however I do not provide binding support in iOS but only in Android.

    Hope this helps,
    Laurent

  6. Umair Says:

    Thanks Laurent ,

    Please clarify about what you mean by At this time ?
    Weather it’s mean in this article or in Nuget Package of MVVM Light Libraries only (PCL).

    Please clarify

  7. Umair Says:

    Please Laurent,

    please help me, I will be great thankful to you on your such kindness

    Best Regards,
    Umair Saeed

  8. haider Says:

    So I followed your tutorial above (with mvvm light 5) and it all worked up until I had this code:

    this.AddBinding(
    () => Vm.Hello,
    () => MyButton.Text);

    MyButton.AddCommand(
    “Click”,
    Vm.IncrementCommand);

    AddBinding and AddCommand are not being found.

    Visual studio makes no suggestions for reference and I can’t find it on my own either.

  9. lbugnion Says:

    Hi,

    In the newest version of MVVM Light, the methods are now named SetBinding and SetCommand. I prefer this naming compared to the one in the early beta. Sorry for not updating the blog post, I will do that tonight.

    Cheers
    Laurent

  10. spainb Says:

    Laurent:

    I too am having trouble adding my initial support in both iOS and Android where this.SetBinding(…) is not found.

    I am a bit confused about the install and setup. In both my iOS and Android projects and a common PCL project holding my ViewModels, I have added the MVVM Light Libs Only (PCL) NuGet package. This added references to GalaSoft.MvvmLight, GalaSoft.MvvmLight.Extras and Microsoft.Practices.ServiceLocation in each project.

    Should there be an additional reference that would include an extension method for my Activity or Controller?

    Thanks so much.
    -Bill

  11. lbugnion Says:

    Hi Bill,

    Yes it seems that you are missing the GalaSoft.MvvmLight.Platform DLL. This is where the iOS-only extension methods are defined.

    Not sure why Nuget failed to install this DLL. Can you try to update the Nuget package on the iOS project only? If it still fails, you may be able to add the reference manually, check the platform DLL in the downloaded packages folder. It should be under [YOUR APP FOLDER]\packages\MvvmLightLibs.5.0.2.0\lib\monotouch

    Hope it helps,
    Laurent

  12. spainb Says:

    Laurent:

    Thanks for your reply. I have moved forward slightly in my testing today.

    First, as background, I am implementing a cross platform app that will run on Windows Phone, Windows 8.1, WPF, Xamarin and iOS. I am architecting my projects to rely on a single PCL class holding ViewModels and implementing specific UI’s for each platform, so I am hoping that my ViewModel PCL class library can talk to each UI platform without having to rely on any custom platform specific code.

    Anyway, I am working with Android today. I uninstalled and reinstalled MVVM LIght, and I now appear to have all the required libraries. However this.SetBinding() still is not recognized as a member of my Activity. However, I was able to find the SetBinding class in the Helpers.Extensions namespace and was able to code up the following in my Activity:

    GalaSoft.MvvmLight.Helpers.Extensions.SetBinding( this, ( ) => vm.UserName, ( ) => txtUsername.Text, GalaSoft.MvvmLight.Helpers.BindingMode.TwoWay);
    GalaSoft.MvvmLight.Helpers.Extensions.SetBinding( this, ( ) => vm.Password, ( ) => txtPassword.Text, GalaSoft.MvvmLight.Helpers.BindingMode.TwoWay );

    GalaSoft.MvvmLight.Helpers.Extensions.SetCommand( btnCancel, “Click”, vm.CancelCommand );
    GalaSoft.MvvmLight.Helpers.Extensions.SetCommand( btnLogin, “Click”, vm.LoginCommand );

    The behavior I see after this code is that text in my TextView gets set correctly as the Activity and ViewModel load and are initialized, but any modifications afterwards don’t get reflected in the UI, i.e. the following Cancel Command gets called, but txtUsername.Text does not get updated

    string m_userName = “”;
    public string UserName
    {
    get
    {
    return m_userName;
    }
    set
    {
    Set( ( ) => UserName, ref m_userName, value );
    if ( LoginCommand != null )
    {
    LoginCommand.RaiseCanExecuteChanged();
    }
    }
    }

    public RelayCommand CancelCommand
    {
    get
    {
    return m_cancelCommand
    ?? ( m_cancelCommand = new RelayCommand(
    ( ) =>
    {
    UserName = “”;
    Password = “”;
    } ) );
    }
    private set { }
    }

    In addition, on Android, the CanExecute command does not seem impact the UI. In fact if I use the following code, the Command is active and the button is enabled:

    this.LoginCommand = new RelayCommand( this.Login);

    If I use the following code instead, my Login button is disabled when the activity is loaded, and is never enabled afterwards:

    this.LoginCommand = new RelayCommand( this.Login, CanLogin );

    public bool CanLogin( )
    {
    bool result = ( UserName.Length > 0 && Password.Length > 0 );
    return result;
    }

    If you can point me further in the right direction, I’d be grateful.

    Thanks
    -Bill

  13. Immons Says:

    @lbugnion

    Does Bindings already work for iOS projects?

    I tried both:

    labelAuthor.SetBinding(
    () => viewModel.News.Author,
    () => labelAuthor.Text,
    BindingMode.TwoWay);

    newsBinding = this.SetBinding(() => viewModel.News).WhenSourceChanges((() =>
    {
    this.labelAuthor.Text = viewModel.News.Author;
    this.labelTitle.Text = viewModel.News.Title;
    this.labelContent.Text = viewModel.News.Content;
    this.labelDate.Text = viewModel.News.CreationDate.ToString();
    }));

    but none of this work. Thanks in advance.

  14. lbugnion Says:

    Hi,

    Yes it works, but you need to keep a reference to the binding returned by the SetBinding method. Because bindings are weak referenced, the Garbage Collector will delete them immediately otherwise.

  15. ecosgrave Says:

    Is there any guidance or examples of using MVVMLight NavigationService with Android Fragments rather than Activities that you know of?
    Thanks.

  16. lbugnion Says:

    Hi,

    I don’t know if there is anything published. You would need to implement INavigationService and in the use the FragmentManager instead of the ActivityBase. I implemented something like that for a project I was working on, but it is not ready for publication at this point, sorry.

    Laurent

  17. HK Says:

    Hello Laurent,

    Do you have any sample on how to use Navigation service with the activities which are inherited from AppCompatActivity? In case of AppCompatActivity we have frame / navigation view and Fragments, how do we use Navigation service in that case as we have only one Activity and the child content gets loaded with the help of Fragments..

  18. HK Says:

    I am trying to use 2 way data binding. In my view model, I have a complex property called Model. Now when I assign the Model property from the model received from a service, I don’t get the values in the bound text boxes. If I call raise or set in the setter of Model property, all the properties are initialized to null or empty? Do we need to flatten the Model object properties in ViewModel? If yes, it will be lot of extra code…any sample?

  19. lbugnion Says:

    Hi,

    this scenario is supported. Please send me a repro.

    thanks
    Laurent

  20. HK Says:

    If you can provide an email, I can send code files.
    Step1: In my fragment I have the following code

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
    var ignored = base.OnCreateView(inflater, container, savedInstanceState);

    _currentView = inflater.Inflate(Resource.Layout.Register, null);

    this.SetBinding(() => CommentsText.Text, () => RegisterViewModelL.Model.Comments,BindingMode.TwoWay);

    SignUpButton.SetCommand(“Click”, RegisterViewModelL.OnRegister);

    RegisterViewModelL.LoadData();

    return _currentView;
    }

    You can think of this as a edit screen, where in I am first setting up the binding and then calling the loaddata to get the data from the service for the record in edit. For sample, not passing any id and getting the object. Here is the view Model structure
    RegisterViewModel -> Model (property of ExpenseType) -> Model has a child properties like comments, firstname etc

    public class RegisterViewModel:ViewModelBase
    {
    public RegisterViewModel()
    {
    _onRegister = new RelayCommand(async () => await OnRegisterClick());

    Model = new Contracts.Expense();
    }

    private RelayCommand _onRegister;

    public RelayCommand OnRegister => _onRegister;

    private Expense.Contracts.Expense _model;

    public Expense.Contracts.Expense Model
    {
    get
    {
    return _model;
    }
    set
    {
    _model = value;

    Set((()=>Model), ref _model, value);
    }
    }

    #region Public Method(s)
    public void LoadData()
    {
    //Service layer will return a new instance of expense
    //Expense.Contracts.Expense databaseExpense = new Contracts.Expense(); //**** THIS NEW CAUSES THE ISSUE. IF I KEEP THE CODE IN CURRENT STATE, IT WORKS, BUT IN REAL WORLD, SERVICE WILL RETURN A NEW INSTANCE OF EXPENSE. I DONT WANT TO SET THE PROPERTIES AGAIN HERE.****

    Expense.Contracts.Expense databaseExpense = this.Model;

    databaseExpense.EmployeeNumber = 300;
    databaseExpense.Comments = “Loaded Comment”;

    this.Model = databaseExpense;

    }
    public async Task OnRegisterClick()
    {
    var s = this.Model.FirstName;
    }
    }
    }
    *******************************
    public class Expense : ObservableObject
    {
    private int _employeeNumber;

    private string _comments = string.Empty;
    public int EmployeeNumber
    {
    get
    {
    return _employeeNumber;
    }

    set
    {
    Set((() => EmployeeNumber), ref _employeeNumber, value);
    }
    }

    public string Comments
    {
    get
    {
    return _comments;
    }
    set
    {
    Set((() => Comments), ref _comments, value);
    }
    }

    }
    }

  21. lbugnion Says:

    Hi,

    My contact info is in the About section above. Please send me a repro (i.e a small app that demonstrates the issue, not just code).

    Thanks
    Laurent

  22. Steven Says:

    @HK, did you ever figure out your Fragments/AppCompatActivity/MVVMLight issue?

Comments for MVVM Light V4.4 with Xamarin Android support