MVVM: How to maintain data which all the view models will use? - c#

Maybe the title is not so descriptive.
I'm working right with Galasoft MVVM framework, and I realized in my application I need all the time or use these data in the view models.
The data which I need is this Authentification model
Username : string
Password : string
IsGuest : bool
I guess it is not a good idea and the best way to pass these data through navigation.
A few months ago, I was using Prism and I remember something called Container, where you can register and save your object in all the lifecycle of your application.
Another way which I was thinking is to save it in App class, but I'm not sure if this is a good idea.
By the way, I'm working on Metro UI applications.

Don't store the data in the App because it is part of the View. To use it you would effectively have to reference the View from all of your ViewModels. A core principle of MVVM is that the Model(s) only have access to other Model items, the ViewModel has access to other ViewModels and the Model, and the View has access to ViewModels
There are a couple of choices you could consider
Create a static class AuthenticationData where this gets initialized
Pass the authentication data to the constructor for each view model
Store the authentication data in an IoC container (GalaSoft has a SimpleIoc class)
Options 2 and 3 could make it easier to mock your authentication data for testing purposes if you use an IAuthenticationData interface

For Authentication there's already something there you can use. Check IPrincipal/IIdentity interfaces. Upon authentication these are set to Thread.CurrentThread.CurrentPrincipal and can be used later.
The Container you are referring is probably Unity which is an IoC container and GalaSoft also comes with a simple one.

Related

Where do I put my login logic in WPF and how do I handle it in MVVM?

I'm currently working on an application that implements the MVVM architecture, where I am trying to do the login logic.
I have a pretty good idea of what the main responsibilities of both INotifyPropertyChanged and ICommand are, and have already implemented them to all my view models that need them.
Here's a short of my code:
I have an ApplicationViewModel.cs that handles the main window ApplicationView.xaml.
The main
window has a sidebar menu on the left, and a <ContentControl> that that is binded to the CurrentViewModel property of type ViewModelBase in ApplicationViewModel.cs.
All child view models are contained in a List<ViewModelBase> property. It gets its views from a DataTemplate with the corresponding view model, thus providing me a working navigation system.
So here's what I initially thought of doing:
In a child view model called LoginViewModel.cs, I thought it was logical to do the login logic, as it also handled the view itself. I wrote a model class User.cs with corresponding properties to the database columns. I wrote some classes that would help me get the data from the database to the application.
The view model checks for how many characters are entered and executes the Login once the user has entered 4 characters for the pin code, which instantiates a User object in LoginViewModel.cs
The problem here for me, is that I need the instance of the User to be application wide and therefore probably needs be in the ApplicationViewModel.cs instead.
So, from that, I have 2 questions:
Is there a better approach to this and a better way handle the login logic?
If the logic I already made is fine, how do I hand the instance of the User from the child view model LoginViewModel.cs to the parent view model ApplicationViewModel.cs?
Yes; it wasn't quite natural to come towards this solution when I first started, but you actually can add some kind of 4th layer in MVVM, the Services layer (well, it's more of a pattern than an actual MVVM layer).
Services are single-instance objects that you inject into your viewmodels, and serve exactly that kind of purpose, which is holding and potentially treating data that should circulate between viewmodels.
You will need a dependency injector, a class that will bother with finding the correct service for the classes injected with it.
So you have two concepts to study:
Services
Inversion of control/dependency injection
I can't just give you an implementation of a dependency injector, because I personally don't have one.
I'm using a MVVM framework that provides me with one already.
It's basically used this way:
You create an interface for each of your services; it keeps concerns separated (no coupling between service implementations and viewmodels).
You register your service implementation by their interfaces (something like myDependencyInjector.Register<IMyService>(typeof(MyService)) at the start of your program
You add the desired service interfaces to the relevant viewmodels' constructors (MyViewModel(IMyService myService))
You could implement custom authentication and authorization by creating classes that derive from the IIdentity and IPrincipal interfaces and override the application thread's default identity. Please refer to the following blog post for more information about how to do this.
Custom authorization in WPF: https://blog.magnusmontin.net/2013/03/24/custom-authorization-in-wpf/.
You basically create an IPrincipal and use the AppDomain.CurrentDomain.SetThreadPrincipal method to associate this principal with the AppDomain in your application. You can then use the Thread.CurrentPrincipal.Identity.IsAuthenticated property everywhere in your application to determine whether the user is authenticated.
In the code sample, the actual authentication is done by the AuthenticationService class. You could for example implement this one to check the passed in credentials against a remote database. The view model uses this service to perform the authentication.

How to create shared Model for 2 different Views?

I create the instance of my model in ViewModel2. This is sufficient for most of data. However, I also have some data, which is presented in different View, which is operated by ViewModel1. Should I just go ahead and create singleton pattern using for example SimpleIOC then obtain model instance from ViewModel1? If there is more proper way to do that according to MVVM concept I would like to know.
Use an IOC container to hold the Model (or Data Access Layer to the model) and inject it into any ViewModels that require it. This is the pattern used by the MVVMLight framework (see https://msdn.microsoft.com/en-us/magazine/jj991965.aspx or start a new MVVMLight project in Visual Studio)

Should viewmodels contain static functional methods?

If I have a Viewmodel designed to serve a purpose for a view -
Is it a good practice to add bunch of static methods to the viewmodel like
- getting a list of items(viewmodel object) by consuming data from db?
- updating the db using a property in the viewmodel?
I am using .NET MVC and feel like my viewmodels get cluttered with bunch of static functions and update methods.
The main reason behind creating viewmodel for the views was because the views started to contain a lot of functionalities for which info had to be fetched from all over the place. So instead, i decided to create a viewmodel to get the info from one place with one call.
Am I following a good coding pattern here? Or am I shooting in the dark?
Is it a good practice to add bunch of static methods to the viewmodel
No, your viewmodel should simply be a POCO, containing as little (if not zero) business logic. A view models only job is to move data from the controller to the view.
Generally:
The controller should obtain an instance of a model from somewhere
this can be consumed by the view directly or if multiple models needs
combining or extra information (not in a model per se) is required
then a view model can be created.
Ideally the view model should be created outside of the controller
(keeping the controllers job clean), this can be achived simply by
using a factory pattern
If you read the wikipedia page for the MVC pattern. You'll notice it is solely designed for the presentation of data, not business logic:
Model–view–controller (MVC) is a software architectural pattern for
implementing user interfaces.
so really none of the MVC objects (Model, View or controller) should contain business logic. The MVC patterns job is to render data (full stop)
That all said it is common to put simple business logic into the controller. Once sites get more complex, though, this should be avoided, for fear of creating a god object
Am I following a good coding pattern here?
No, it's not a good pattern.
The main reason behind creating viewmodel for the views was because the views started to contain a lot of functionalities for which info had to be fetched from all over the place. So instead, i decided to create a viewmodel to get the info from one place with one call.
Store functionalities or any kind of logic is not the ViewModel's purpose. It should be just a transport mechanism that holds the data transported between the View and the Controller.
Consider move your "funcionalities" to Application, Service or another layer that makes sense for your application's architecture.

Alternatives on passing parameters from ViewModel to ViewModel in MvvmCross

We are at the preparation on porting a huge windows mobile app to Xamarin
and we are using MvvmCross to help us with the Mvvm.
The application is huge, where workflows live between several pages. So there is a need to pass states/objects between pages. As those states can be big, it does not make sense to serialise them between navigation calls.
My question is: what are any proven or used alternatives to pass objects between view models? Is there some session manager?
Note: we are starting with Android, so maybe there is also good an Android only solution.
Hint: I posted this question on Programmers as well, not sure what's the better platform for this: https://softwareengineering.stackexchange.com/questions/285219/alternatives-on-passing-parameters-from-viewmodel-to-viewmodel-in-mvvmcross
A couple of options I use are:
1) Persist state to a SQLite database and pass an identifier from ViewModel to ViewModel. This is simple and ensures that the state remains even between app restarts.
2) Another option, which is useful in a wizard-like setting is to use a Cache service. I simply created an interface to add and remove entries in a cache by key. I treat it like a standard MvvmCross service and use IoC to inject into my view models. At the start of the process, create a GUID to use as your key, add your state to the cache. Simply pass the key to the next view model, where it can retrieve the state from cache.

How to create and organize non UI related elements using the MVVM pattern

I'm creating a WPF application using the MVVM design pattern. I've only recently started learning both, but have a solid grasp on how the basics work.
The application will have classes that are not UI related, such as a networking thread and message handler, and a class to save and load settings.
These elements of the program don't have a clear connection with the UI. How should they be created and initialized? These are "application wide" services that will not fit a particular ViewModel, and don't feel like a Model either.
Is there a correct way to do this? What should "own" and create these objects? (The ViewModel, or rather make them static and create themselves?)
Here is a diagram of the MVVM model, with a few adjustments to show what I am looking for: (Highlighted text and purple box)
When a "user has joined" message is received the the server, the service will send an event to the model that has subscribed to it, notifying it of the new user. The ViewModel will see this change, and add the user's name to the UI.
You can have services that are linked to a certain functionality of a UI. (Only the main windows uses them, for example) And there can also be services that are shared between many windows.
For the first scenario, I usually instantiate the services in my ViewModels.
For application wide services, I'd rather create the instances in App.xaml.cs and pass the reference to my viewmodel.
Here is an example from one of my projects.
private void Application_Startup(object sender, StartupEventArgs e)
{
ConnectionManager connMan = new ConnectionManager();
MainViewModel mvm = new MainViewModel(connMan);
new MainWindow(mvm).ShowDialog();
// TODO: save settings, etc. here
this.Shutdown();
}
If your services do not rely on any state information, you could use static classes as well. And that is what I usually use for settings management, for example.
Edit: For the example you've posted, you have to ask yourself this question:
Who is responsible for creating and maintaining the network manager object?
If it is the ViewModel, it can host the object inside itself. If it is created by an external object, you would pass it to the ViewModel. There are pros and cons to either approach and I don't have enough information to suggest you one of them right now.
You can use a DI Container and register your services with it. It is then a matter of personal preferences if you use Dependency Injection or use the DI Container as a mere Service Locator.
The basic idea behind a service locator is to have an object that knows how to get hold of all of the services that an application might need. So simply speaking ServiceLocator is a singleton Registry.
The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation.
A good implemantion is the Microsoft Unity Container. You can use it as an DI container or a Service Locator.
In this situation, try to keep a List (eg ObservablleCollection<T>) in the ViewModel, and model-specific data type like Person, User in Model.
Then create separate namespaces such as Workers, Helpers or Managers, which are static classes that are only responsible for their specific area. For example: Workers / Sql / SqlWorker, Workers / Network / NetworkWorker.
Later in the ViewModel, call these methods in the appropriate commands.
I think it would be a simple and advanced solution, since workers will not interfere with each other (if only via abstract interfaces), besides they will not be connection to the UI.

Categories