Xamarin and the MVVM pattern

GraverobberGraverobber Member ✭✭

Hello everyone,

I'm working on my newest app with Xamarin, not my first one though, and this time I plan to strictly follow the MVVM pattern as I kind of fall in love with the idea behind after I finally took the time to understand what it actually brings :D

I watched tons of youtube videos and read many articles from general MVVM explanation to MVVM in Xamarin and so on.
However, often they are not really doing MVVM it's more like VVM (View-ViewModel) or VM (View-Model).
I'm not 100% sure if what they do there is correct and strictly following the MVVM pattern would be overkill as not needed at those points or if it is just not correct.

In this post I would like to clarify my understanding and I hope others will join and help me :)

As it is the easiest I would go with a simple example of what I find on the web and why I think it is not MVVM but VVM.

There is a ContentPage for a Login, as we not focus on UI, for simplicity lets say like that.

<StackLayout>
        <!-- Place new controls here -->
        <Entry x:Name="Username" Placeholder="Username" Text="{Binding Username}"/>
        <Entry x:Name="Password" Placeholder="Password" Text="{Binding Password}"/>
        <Button x:Name="Submit" Text="Submit"/ Command="{Binding SubmitCommand}" />
</StackLayout>

From my understanding, the ContentPage represents the View within the MVVM pattern, so the underlying .cs file that comes with the .xaml, is also a view and should not have any business logic or data or whatever stored.
As you can see we bind some values to Text of Entries and Command of Button.
So all the .cs of the xaml does is defining this BindingContext which is of type SampleViewModel.

public partial class MainPage : ContentPage
{
        public MainPage()
        {
            InitializeComponent();
            BindingContext = new SampleViewModel();
        }
}

The SampleViewModel on the other hand has to define a string Username, a string Password as well as the command, So it will look like this:

public class SampleViewModel
{
        public String Username { get; set; }
        public String Password { get; set; }
        public Command SubmitCommand { get; }

        public SampleViewModel()
        {
            SubmitCommand = new Command(() => { /*Do something here*/});
        }
}

And that should be it. This is the point to which a lot of Tutorials lead but I'm wondering, where is the Model?
I could move the Username and Password String into a model and reference it into the SampleViewModel but I don't really see the point of that here as it doesn't bring any advantage in this rather simple example.

So I'm wondering, is it fine to roll like that?
Are Models only meant for more complex scenarios?
For example when having a Listview displaying contacts a model can describe a single contact but it is not required to have a model that at the same time describes some basic things within the ContentPage. An example that comes to my mind would be a search bar at the top to find a contact. The value entered there could again go into the ViewModel as a String, but no need to have a Model that holds this String.

I think that's it for the start of the discussion :) am I on the right track, is it correct or is it supposed to be otherwise?

Thank you all!

Posts

  • FaizalSaidaliFaizalSaidali USMember ✭✭

    Hi @Graverobber ,
    I have changed your ViewModel code like this.

        public class BaseViewModel : INotifyPropertyChanged
        {
            #region INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
            {
                var changed = PropertyChanged;
                if (changed == null)
                    return;
    
                changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "", Action onChanged = null)
            {
                if (EqualityComparer<T>.Default.Equals(backingStore, value))
                    return false;
    
                backingStore = value;
                onChanged?.Invoke();
                OnPropertyChanged(propertyName);
                return true;
            }
            #endregion
        }
    
        public class SampleViewModel : BaseViewModel
        {
            #region Fields
            private UserItemViewModel user;
            #endregion
    
            #region Properties
            public UserItemViewModel User
            {
                get { return user; }
                set { SetProperty(ref user, value); }
            }
            #endregion
    
            #region Commands
            public Command SubmitCommand { get; }
            #endregion
    
            #region Constructor
            public SampleViewModel()
            {
                SubmitCommand = new Command(() => { /*Do something here*/});
            }
            #endregion
        }
    
        public class UserItemViewModel : BaseViewModel
        {
            #region Fields
            string username;
            string password;
            #endregion
    
            #region Properties
            public string Username
            {
                get { return username; }
                set { SetProperty(ref username, value); }
            }
    
            public string Password
            {
                get { return password; }
                set { SetProperty(ref password, value); }
            }
            #endregion
        }
    
  • GraverobberGraverobber Member ✭✭

    Hi @FaizalSaidali

    thank you for your response!

    Would it be possible to elaborate your code a bit and explain the idea behind?

    From what I see you created a BaseViewModel (I have that too but for the sake of the simplicity in my example I skipped that, as well as all "smart" inheritance things as it is not necessary to discuss about the MVVM pattern itself).

    If I understand your code correctly, and please correct me if I'm wrong, then UserItemViewModel is just named in an unfortunate way and is the Model for the user informations. (= finishing MVVM pattern Where UserItemViewModel = Model, ContentPage = View and SampleViewModel = ViewModel)
    In SimpleViewModel you keep a reference to the UserModel, but it actually is never initialised, is that intended?

    However even if, what it results in is what I meant in my first post, what is the advantage of that model in this simple example other than just strictly following MVVM pattern?

    And small question on the side, how do you Bind the values from this model to the view now? By
    {Binding user.Username} (or something similar)?
    If yes, wouldn't that break the MVVM pattern again as the View now has to be aware of the Model?

    Thank you again!

  • FaizalSaidaliFaizalSaidali USMember ✭✭

    Hi @Graverobber,
    In my understanding, the MVVM has 3 phases Model, View, ViewModel. But in some cases we cannot achieve the proper binding using the ViewModel, Like ListView. So we need to make the model's properties also maintained as bindable(with OnPropertyChanged event, then only UI will reflect). Then I was confused about the model name. The API response models and DB models keeping under models. But this one also act as ViewModel role. After some research, I find out this naming extension.
    This model is a ViewModel and also an item of a collection, so I called it ItemViewModel.
    When we create User property in SampleViewModel, we should initialize it. Otherwise app will crash with null exception.
    Then, we bind as Binding="{Binding User.Username}". In this case we can set TwoWay mode binding.

    This is only my thoughts. I am a beginner in the developing field and this is my little knowledge and little experience in the Xamarin and MVVM. I am little curies about to learn like this and thank you for appreciate.
    If any queries about me and my coding. please said me frank, then only I can improve.

    Thank you again :smile:

  • L0gicaL1nsanityL0gicaL1nsanity Member ✭✭

    To me the only time the Model in MVVM comes into play is when your view actually needs to display something from your model. OP, what you wrote as an example would be a fine start, just no Model is needed yet. but if, let's say, you wanted to display some user data, then you would do as the above poster suggested and add an element to your view with {Binding User.Username} And you would just have to have a User property in your viewmodel who's type is the model that exists else where.

    Unless we're doing it way wrong haha!

  • GraverobberGraverobber Member ✭✭

    Thanks @FaizalSaidali and @L0gicaL1nsanity !

    So I'm on the right track at least :)

    @L0gicaL1nsanity
    I'm still not 100% sure about the {Binding User.Username} because this makes the View aware of the model (even if it comes through the ViewModel).
    But from my understanding the View should be free of such a dependency.

    What I saw in some Tutorial that actually followed the MVVM pattern was that they more or less mirrored the parameters of the Model into the ViewModel just to pass it to the view. So for example:

    ViewModel:

    public class SampleViewModel
    {
        public string Username {get; set;}
        public string Password {get; set;}
    
        private SampleModel SampleModel;
    
        public SampleViewModel()
        {
            SampleModel = new SampleModel();
        }
    }
    

    Then the Model:

    public class SampleModel
    {
            public string Username {get; set;}
            public string Password {get; set;
    }
    

    Right now I don't actually remember how, but then the parameters where Bound together in order to notify each other about data changes. So changing Username in Model also changes the one in ViewModel and changing it in ViewModel updated it in Model.

    Then the view only dictates that there is supposed to be a parameter named Username but doesn't care were it comes from.
    {Binding Username}

    But on the other hand, doing it your way doesn't actually make the View aware of the model object, it just dictates that there is supposed to be a User model with that information :D

    The more I think about it the more I get confused. xD

    Another thought, perhaps the ViewModel should use the parameters from the Model in the get and set.

    Thanks to all!

  • JohnHardmanJohnHardman GBUniversity mod
    edited May 17

    @Graverobber said:
    Hello everyone,

    I'm working on my newest app with Xamarin, not my first one though, and this time I plan to strictly follow the MVVM pattern as I kind of fall in love with the idea behind after I finally took the time to understand what it actually brings :D

    I watched tons of youtube videos and read many articles from general MVVM explanation to MVVM in Xamarin and so on.
    However, often they are not really doing MVVM it's more like VVM (View-ViewModel) or VM (View-Model).
    I'm not 100% sure if what they do there is correct and strictly following the MVVM pattern would be overkill as not needed at those points or if it is just not correct.

    In this post I would like to clarify my understanding and I hope others will join and help me :)

    As it is the easiest I would go with a simple example of what I find on the web and why I think it is not MVVM but VVM.

    The good thing is that your observations are valid (IMHO) and you are asking the right questions.

    I agree that the majority of samples found on the web seem to be VVM or just MV rather than MVVM. Clearly, in many scenarios, that can be done, and it's not unreasonable as it can avoid code duplication in simple apps. However, as apps get more complex, implementing the full MVVM, with differentiated Models and View Models becomes sensible.

    In my current app, I typically have three types of Model:
    (1) Models that use a Data Access Layer to store data in, and retrieve data from, a SQLite database, as well as synchronising with a cloud-based database via a REST API
    (2) Models that store data in, and retrieve data from, local persisted storage (sub-categories for settings and files)
    (3) Models that cache data for the lifetime of the app, but that do not persist it.

    In the same way that you commonly see people using a BaseViewModel, I utilise a BaseModel which I then subclass for the three variants above. Actually, BaseViewModel and BaseModel have a lot in common, so I have a base class for those too with the common bits in. I also make use of DTOs (Data Transfer Objects), typically within the Data Access Layer.

    I then have ViewModels, which provide Views with the information that they need. The ViewModels retrieve that data from the appropriate Models (with each ViewModel potentially accessing multiple Models), combine/package/transform it as appropriate, and then make it available via public properties. When Views call setter properties in the ViewModel, the ViewModel state is updated. I maintain a flag in each ViewModel that says whether a change to the ViewModel should immediately update the related Models. Where that flag says to not do immediate updates to the Models, I expose a Save Command that can be called by Views, typically when the user presses a button, or when the user pops a particular page.

    Like most people, I utilise a BaseViewModel. I don't currently use Fody, but might do in future. I also make use of lazy initialisation and weak references in some ViewModels.

    I then have Views, which present the UI to the user, interacting with the ViewModels via properties and events. Where I use ValueConverters, I have those ValueConverters in the View layer, not in the ViewModel layer. Whilst it is possible to have different controls on a page interact with different ViewModels (by giving different controls different BindingContexts), I don't normally do that. Instead, I have a ViewModel provide everything that a page needs (or indeed, that multiples pages need, if the requirements are very similar). My Views never interact directly with the Models.

    What I don't do is to have any UI information in the ViewModel, other than when I provide the user with functionality for settings Colors, Fonts etc. Even there, I am removing those bits where possible, and only allowing the user to choose from themes that I make available via Style properties, not via the ViewModels. I also do not currently re-use page objects - I used to but XF used to have issues with this. Now, there appear to be issues with not doing so (custom renderers appear to leak managed memory - they get Disposed but apparently not finalized - still awaiting confirmation from Xamarin), so I might switch back to re-using page objects in future.

    I use declarative C# for my Views, but whether I would do that in a simpler app I don't know. I might possibly use XAML in something simpler.

    For testability, I provide interfaces for Models, View Models, Data Access Layer etc., so that I can mock/fake things during testing. Where I maintain static instances of anything, I always include a setter so that I can replace the instance during unit or integration testing.

    That's my way of doing things, but it's not the only way. Hope it helps.

  • L0gicaL1nsanityL0gicaL1nsanity Member ✭✭

    @Graverobber I guess I think of that in the same way as I talked about my {Binding User.Username} the User object here is just a ViewModel representation of the Model via a property on the viewmodel object. I'm still new to this so take what I say with a grain of salt. but I guess I believe it to mean that as long as there is a separation in the code base, it's ok if the View looks for properties to be named the same as what's in the model.

    But in any case, in your example you can have Username property be called MyFavoriteUser and as long as you map that to the model's Username property, then it will functionally work right? So maybe your approach is even more decoupled.

    Idk I feel like we need an expert to chime in xD

  • GraverobberGraverobber Member ✭✭
    edited May 17

    Thank you @JohnHardman, this was a nice explanation and makes a lot of sense.
    @L0gicaL1nsanity I'm tagging you in order to see JohnHardmans Post ;D

    I was working more on the app today and came across a point where I would need to do something like that in a custom ContentView:

    BindingContext as ContentViewViewModel

    Then I could get the Count of a Collection and initialise my Grid just fine.

    Is this okay? Because from that point on the view will be hardly bound to this ViewModel, no other ViewModel could be used and the View couldn't be re-used.
    Or is it fine to assume that a View always corresponds to a specific ViewModel?
    I mean the View does BindingContext = ContentViewViewModel in the constructor, so it already is fixed on this ViewModel anyway.

    Thanks to all, very helpful already!

  • L0gicaL1nsanityL0gicaL1nsanity Member ✭✭

    Good stuff. Will I be seeing any of you all at the Xamarin Conference in houston in July!?

  • JohnHardmanJohnHardman GBUniversity mod

    @Graverobber said:
    Thank you @JohnHardman, this was a nice explanation and makes a lot of sense.

    Don't forget to Like the post if it helped/helps :-)

    @Graverobber said:
    I was working more on the app today and came across a point where I would need to do something like that in a custom ContentView:

    BindingContext as ContentViewViewModel

    Then I could get the Count of a Collection and initialise my Grid just fine.

    Is this okay?

    Yes, there's nothing wrong with that

    @Graverobber said:
    Because from that point on the view will be hardly bound to this ViewModel, no other ViewModel could be used and the View couldn't be re-used.
    Or is it fine to assume that a View always corresponds to a specific ViewModel?
    I mean the View does BindingContext = ContentViewViewModel in the constructor, so it already is fixed on this ViewModel anyway.

    I forgot to mention in the previous post, that I also have a BaseContentPage, which is templated as BaseContentPage<T>, where the T is the ViewModel type to use for that page. The BaseContentPage sets the ViewModel, and then nulls it when the page is popped, in order to avoid memory leaks.

    That doesn't mean that individual controls on that ContentPage cannot have a different BindingContext, just that there's usually no need to do so.

  • JohnHardmanJohnHardman GBUniversity mod

    @L0gicaL1nsanity said:
    Good stuff. Will I be seeing any of you all at the Xamarin Conference in houston in July!?

    Only if Xamarin/Microsoft want to pay for my flights from the UK ;-)

  • GraverobberGraverobber Member ✭✭

    Thank you once again @JohnHardman the idea with the is actually really good.
    I liked both your posts ;)

    @L0gicaL1nsanity
    Would love to be there but I guess I'm facing the same issue as JohnHardman, just from Germany :D

Sign In or Register to comment.