MVVM : Share data between ViewModels - c#

How do I share data between multiple ViewModels ?
For example there is a class named Project in application .
public class Project : ModelBase
{
private string _projectName;
public string ProjectName
{
get { return _projectName; }
set
{
_projectName = value;
RaisePropertyChanged(() => ProjectName);
}
}
}
In multiple ViewModels application should access ActiveProject.
What's the best way to share Project between ViewModels ?
Mediator Pattern ? (Messaging)
Static object
Singleton pattern (If yes how?)
I've used Messaging before but it needs much codding . For all ViewModels I've to create ActiveProject property and also have to register a messenger to update that.
I use MVVM Light framework.
Any code example would be appreciated.

I would create a ViewModel that acts as a parent to all the Project ViewModels. (Let's call it Solution)
The Solution ViewModel would have the property ActiveProject and an observable collection of Projects.

I would recommend the Mediator Pattern. I have used an EventAggregator for this type of messaging between VM's before and there is really not much to it.

Don't, don't. Don't use singletons this way in your MVVM application. In fact, the Project class should be a model for your ViewModels. Just pass it in vm's constructor. If you really need to share one instance of Project class in multiple vm's, then use factories and some type of cache when constructing view models. If your vm reguires some more information, just create special Model class which will derive from Project (or implement IProject), so you can easilly use interface segregation principle.

Singleton will definitely help. To implement, if I had a class named User:
private static User mInstance;
private User () //constructor
{
}
public static User Instance
{
get
{
if (mInstance == null)
mInstance = new User();
return mInstance;
}
}

You could have a static collection which your view model populate before you navigate to the new view model. The target view model can then retrieve the data from within it's constructor.
For example ViewModel1 (VM1) will create a Project and populate it. VM1 will then put the Project into a shard, static, collection. VM1 will then navigate to another view model (VM2). In the constructor of VM2 you would go to the collection and retrieve the Project placed in there by VM1.
If you used a dictionary of key-value pairs it would also allow you to share other data between view models.

Related

How to pass reference to class instance when creating viewmodel

I am developing a program that contains a main view and 5 user controls. I have created the XAML and created a view-model to sit behind each of these views in which the view is bound too.
I have a main Program class and I want to have some other classes such as product, testTool, etc.
When the application starts I load mainWindow, that will then create the mainWindowViewModel and in turn create the Program class.
When a user presses a button I want the mainWindowViewModel to display userControl1 but I want userControl1ViewModel to be able to see the Program class and access its properties and methods.
I keep reading things like "pass the instance of the class in by reference" which is fine but if userControl1View creates userControl1ViewModel how can I pass a reference to the 'program' class created at the start of the program?
This is what dependency injection is designed to solve.
First of all, if you're doing MVVM then you should be able to run your entire application without creating any views at all i.e. only view models. If you have a MainWindow with a ChildView (say) then in general you match those with corresponding view models:
public MainViewModel : ViewModeBase
{
public ChildViewModel MyChild {get; } // gets assigned later
Then in your XAML:
<Window ...
<local:ChildView DataContext="{Binding MyChild}" />
Sometimes you'll need MyChild to display different views, each of which will have its own corresponding view model, and you may need to change it at run-time. In those cases MyChild will need to be of type object (or some common base class) and will also need to support property change notification:
public class MainViewModel : ViewModelBase
{
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
}
Then in your XAML you create a ContentControl instead:
<Window ...
<ContentControl ="{Binding MyChild}" />
With this is place you then use DataTemplate in your window or application Resources section to specify which views are matched to which view models:
<DataTemplate DataType="{x:Type vm:FooViewModel}">
<view:FooView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:BarViewModel}">
<view:BarView />
</DataTemplate>
So now if you do something like this in your MainViewModel...
this.MyChild = new FooViewModel();
...the ContentControl is automatically populated with a control of type FooView. Furthermore, it's DataContext will automatically be set to the instance of FooViewModel that you created. And you then re-assign it like so:
this.MyChild = new BarViewModel();
...then the FooView will be replaced with a BarView.
So with DataTemplating in place all you have to worry about is passing references of your ViewModels into each other, and that's where dependency injection comes in. It's a big topic, I suggest you go and read up on it, but the idea is you create all of your view models via the DI framework (instead of the new operator) and let it glue all the bits together. Your Products, for example, might be part of a repository class that manages all of them, so you start by declaring an interface:
public interface IProductRepository
{
Products[] AllProducts();
Product GetProductByName(string name);
... etc ...
You then create an actual class that implements this interface and during setup you give your dependency framework the rules for what it should do whenever anything requests an IProductRepository (use a single instance, create a new one etc). Then, whenever anything in your entire application needs to access the product repository, all it has to do is declare a property with an [Inject] tag (this is if you use Ninject, each library has it's own way of doing this):
public class MyClass
{
[Inject]
public IProductRepository ProductRepo {get; set;} // <-- gets injected
Now, when you create an instance of type MyClass the dependency injection framework will create it for you and automatically initialize ProductRepo using the rules you provided it.
That's a very simple overview of how DataTemplating and Dependency Injection work in MVVM, once you start using them you'll wonder how you ever managed without. The main issue in your question, as far as I can tell, is that you're trying to get your view models to talk to each other. In general that's not how MVVM is implemented. View models communicate via services that get injected into them As a general rule of thumb their job is to serve as the conduit between those services and the front-end GUI elements, not each other.
What you're talking about is not actually simple process, what you're talking about is architecture to get the references you expect where you expect them. This can be solved a rather huge number of ways, so I'm going to throw out a fairly unsound but extremely quick example below. Architectural problems are noting inline with // HACK:s
Typically, you'll want the Models coming from a central location, such as database backing, which controls handing over the proper instance.
public abstract class Model
{
// HACK: Don't bother wiring up OnPropertyChanged here, since we don't expect ID to get updated that often, but need a public setter for the Provider
Guid ID { get; set; }
}
// HACK: While using a generic here makes for readable code, it may become problematic if you want to inherit your models
public class ModelProvider<TModelType> where TModelType : Model, new()
{
// HACK: Use better dependency injection than this
private static ModelProvider<TModelType> _instance = new ModelProvider<TModelType>();
public static ModelProvider<TModelType> Instance => _instance;
private ModelProvider() { }
// TODO: Make this into a dictionary of WeakReferences so that you're not holding stale data in memory
ConcurrentDictionary<Guid, TModelType> LoadedModels = new Dictionary<Guid, TModelType>();
private TModelType GenerateModel(Guid id) => new TModelType { ID = id };
private TModelType LoadKnownModel(Guid id)
{
throw new NotImplementedException("Implement a data store to get known models");
}
public TModelType GetNew() => LoadedModels.AddOrUpdate(Guid.NewGuid(). GenerateModel);
public TModelType GetById(Guid id) => LoadedModels.GetOrAdd(id, LoadKnownModel);
}
And then your ViewModels have access to
ModelProvider<Product>.Instance.GetById(WellKnownGuid);
For testing, WellKnownGuid might as well be a static id in Program

How to access to all viewmodels via the viewmodel base?

I've created a ViewModel class that have inside the implementation of INotifyPropertyChanged, now I also have other ViewModels that inherit from the ViewModel (base).
All working good actually but I have a doubt.
So let's say that I've in the CustomerViewModel an ObservableCollection called Price, like this:
private ObservableCollection<Models.Price> _price = new ObservableCollection<Models.Price>();
public ObservableCollection<Models.Price> Price
{
get { return _price; }
}
this ObservableCollection should be populated by other classes, 'cause I need to access to the same resource.
I really don't understand how can I do this in mvvm. I though to a Singleton ViewModel, so something like this defined in the base VM:
public static ViewModel Instance { get; set; }
So import all the childs VM into the base and access them via ViewModel.Instance.Price;
but doesn't seems a good practice for me. Any idea?
With this implementation, you can share the same Datasource to all ViewModels
public class PriceGenerator {
private PriceGenerator() {
this.Prices = new ObservableCollection<Price>();
this.Generate();
}
void Generate() {
//Generate Objects here
this.Prices.Add(generatedPrice);
}
public ObservableCollection<Price> Prices {
get;
}
private static PriceGenerator _instance;
public static PriceGenerator Instance => _instance ?? (_instance = new PriceGenerator());
}
There are generally two approaches to this.
Even if you don't have a real database/repository, implement a singleton class that simulates this. This singleton class should also implement INotifyPropertyChanged (and/or INotifyCollectionChanged as appropriate). All ViewModels will be able to access this simulated repository, and interested ViewModels can choose to subscribe to this repository's PropertyChanged callback. For your question, it is generally tidier to have a repository that handles just prices, rather than having a simulated repository that stores 101 different information.
Have a main ViewModel. Some people would visualize that the MainWindow being the main view, with a corresponding main ViewModel. This ViewModel is intentionally made a singleton, which other ViewModels can access through static call. This main ViewModel is basically acting just like #1 - it is like a repository that stores 101 different information. That main ViewModel is likely to look untidy, but it is simply to trace where things are stored - if you need any data, it's probably in there.
Personally, I prefer to use the first approach. lokusking's answer is an example of this approach. Although his "repository" does more than storing data.

MVVM Xamarin Forms Design

So I was looking at https://github.com/xamarin/Sport as an example I came across when googling something for my current project. It is similar to what Im working on because I use an azure backend as well.
I have a question about their mvvm layout. I thought that in mvvm the models were sort of POCOs and not supposed to implement INotifyPropertyChanged. Arent they acting as both a Model and a ViewModel in this case? Look at the Athlete model and the AthleteViewModel. The VM has a property for for Athlete and so the model is used as a VM as well.
In my project, if I had the same types, I would have an Athlete model, an AthleteViewModel and an AthletePageViewModel. Where the Athlete and AthleteVM would be automapped. The only reason to populate and or create the Athlete is to persist it to the service or local storage.
Is one way more "correct" than the other way? Or am I just doing it wrong and over complicating it? I almost don't want to continue with the way I'm doing it because I dont want to have a bunch of "extra" model files if I can just use some of my VMs as models.
Thanks.
There's no ultimate master set of strict rules that you need to follow in order to implement the MVVM design pattern. In fact, the guidelines are generally quite blurry.
From what I've seen, there are a couple of different methods of which a model may be exposed to the view. Here they are:
Method 1 - INotifyPropertyChanged in the Model
public class Car : INotifyPropertyChanged
{
private string _Model;
public string Model
{
get { return _Model; }
set
{
_Model = value;
NotifyOfPropertyChange();
}
}
...
}
public class CarViewModel
{
//The entire model is exposed to the view.
public Car Model { get; set; }
...
Method 2 - INotifyPropertyChanged in the View Model
public class CarViewModel
{
private Car _Car;
//The model property is exposed to the view, not the model itself.
public string CarModel
{
get { return _Car.Model; }
set
{
_Car.Model = value;
NotifyOfPropertyChange();
}
}
...
In terms of a preferred method, I would say method 2 is the better option. Why?
The Model object is not exposed to the view.
The View Model only exposes what the View needs.
Method 2 does have its downsides. Imagine if you needed to expose lots of model properties, or imagine if your model changes, it is certainly easier to simply implement INotifyPropertyChanged in the model and expose it to the view. Programmers are lazy by nature, therefore in order to save hassle, you'll see method 1 just as much as method 2.
But that isn't a bad thing.
Is one way more "correct" than the other way? Or am I just doing it wrong and over complicating it?
Remember, the MVVM design pattern is just a pattern. Neither options are correct, it's mostly down to the developers preference how they choose to approach the implementation of the pattern, as long as the main MVVM concepts are there, that's all that matters.

Two views - one ViewModel

I must have misunderstood the concept of ViewModels and Views. But at this moment I can't rebuild the application from ground and this time doing it better. My situation is that I have a view where the user can load files and read them, a plotter shows the graphs and some operations are implemented. I want to be able to generate reports (like summary) of the data but I want it in other view. I'm using ModernUI, this other view is in another tab.
What I want is have that two tabs synchronized, when I load a file in the "plotter tab", the file must be loaded in the other view too. For that I think what I need is to bind the view to the same ViewModel, where I have for example LoadedFiles = List<File>, so I will be able to achieve it. The problem is that if I bind it either
MainViewModel vm = new MainViewModel();
DataContext = vm;
or in XAML
<UserControl.Resources>
<UserControl.DataContext=local:MainViewModel/>
</UserControl.Resources>
I'm actually binding to different MainViewModels and the data is not shared anymore. Do I need some classes from MVVM libraries such Locator and so? How this could be done? What can I do in the future in order to have separate ViewModels for each View but the same (or different) data?
You could create a new class that has your LoadedFiles property and then each unique view model can reference this class. You can share the one class with these shared properties between multiple view models. I am using MVVMLight's Locator with an Autofac container to inject this class into each of my view models (basically using Inversion of Control and Dependency Injection).
You can read up on Inversion of Control and Dependency Injection here.
Some sample code-
public MyClass
{
public List<File> LoadedFiles{get; set;}
}
public ViewModelOne
{
public MyClass MyClassInstance {get; set;}
public ViewModelOne(MyClass myclass)
{
MyClassInstance = myclass
}
}
public ViewModelTwo
{
public MyClass MyClassInstance {get; set;}
public ViewModelTwo(MyClass myclass)
{
MyClassInstance = myclass
}
}
You could also use MVVMLight's Locator to set each View's DataContext to the appropriate View.
<UserControl x:Class="View1"
DataContext="{Binding ViewModel1, Source={StaticResource Locator}}"...>
Store the VM in a parent VM's property, then bind the property to two ContentPresenters using different ContentTemplates (containing the respective views).
You should ask yourself if both of your views should share the same viewmodel?
Does they share the sameproperties in the view model or that they have different properties?
If they should share the same viewmodel you should use locator create the viewmodel from the locator and pass the locator to the views.
Otherwise, You should have two viewmodels. in order to keep minimal cuppling between the viewmodels you should use a service which known by both of the viewmodels (better via interfaces). One viewmodel notify the service about action that have been performed, and the second viewmodel has been handle that action (By register to event)
Good Luck,
M. Moshe

In MVVM, is every ViewModel coupled to just one Model?

In an MVVM implementation, is every ViewModel coupled to just one Model?
I am trying to implement the MVVM pattern in a project but I found that sometimes, a View may need information from multiple Models.
For example, for a UserProfileView, its UserProfileViewModel may need information from UserAccountModel, UserProfileSettingsModel, UserPostsDataModel, etc.
However, in most articles I read about MVVM, the ViewModel only consists on one Model via Dependency Injection. So the constructor takes in only one Model.
How would the ViewModel work when it has to get information from multiple Models? Or would such a situation ever occur in MVVM?
PS: I am not using the Prism or Unity Framework. I am trying to implement similar patterns into a project that I am working on which doesn't use Prism or Unity. That's why I need to understand exactly how some of these things work.
In my understanding of the MVVM pattern, the only practical requirement is that the View gets all its data from the properties of a ViewModel (probably through a binding mechanism). The ViewModel is a class that you craft specifically for that view, and takes on the responsability of populating itself as required. You could think of it like ActiveRecord for the view.
As such, it doesn't matter what you do inside the ViewModel to obtain the data that its properties should show. You could get it by querying some services, reading one or more business entity models, generating it on the spot, or all of the above. It's perfectly normal to need a combination of all these things to make a functional view.
As in any presentation pattern, the point is just to separate the process of showing some data on the screen, from the process of obtaining that data. That way you can test each part of the process separately.
Edit: Here's a small but hopefully complete example of the flow of dependencies.
// Model/service layer
public class MyModelA
{
public string GetSomeData()
{
return "Some Data";
}
}
public class MyModelB
{
public string GetOtherData()
{
return "Other Data";
}
}
// Presentation layer
public class MyViewModel
{
readonly MyModelA modelA;
readonly MyModelB modelB;
public MyViewModel(MyModelA modelA, MyModelB modelB)
{
this.modelA = modelA;
this.modelB = modelB;
}
public string TextBox1Value { get; set; }
public string TextBox2Value { get; set; }
public void Load()
{
// These need not necessarily be populated this way.
// You could load an entity and have your properties read data directly from it.
this.TextBox1Value = modelA.GetSomeData();
this.TextBox2Value = modelB.GetOtherData();
// raise INotifyPropertyChanged events here
}
}
public class MyView
{
readonly MyViewModel vm;
public MyView(MyViewModel vm)
{
this.vm = vm;
// bind to vm here
}
}
// Application layer
public class Program
{
public void Run()
{
var mA = new MyModelA();
var mB = new MyModelB();
var vm = new MyViewModel(mA, mB);
var view = new MyView(vm);
vm.Load();
// show view here
}
}
You can use multiple models in a view model. The purpose of the view model is to abstract away the business / data layer (i.e. the model).
However, using more than one model usually indicates that the view is too large. You might want to split it into user controls (which have their own view models).
a viewmodel contains the "view logic" - so all you wanna show on the view is exposed through the viewmodel. if you wanna show data from diffenrent "models" then your viewmodel agregate this and the view can bind to.
the main purpose from mvvm was btw unit test. this mean easy testing of view logic without UI.
EDIT: why do you think:
ViewModel only has one single parameter for the View in its constructor
EDIT2:
there btw two main approaches to work with mvvm, first is "View First" second is "Viewmodel First" you can of course mix up both and choose the best approach for you needs.
A ViewModel may and in many cases does use multiple Models. It is itself a "Model" of your view.
Consider a profile screen that a user enters their personal information including address. If the address is stored in an "addresses" table and the rest in a "profile" table, then the ViewModel uses both the Profile and Address models to create a unified ViewModel.
As jgauffin mentioned in his answer, many times you can use user controls to achieve a one to one relationship, but you can also introduce needless complexity by trying for this 100% of the time.
I would make sure you understand the difference between view, viewmodel, and all other model classes. The ViewModel is the model object that is filled with data that the view can be bound to. It just exists to provide data to the view, which makes the ViewModel object unit-testable, and the whole business logic separate from the view. So, you can develop your business logic entirely without using the view itself, and can replace the view with just building or using another view and binding to the ViewModel object's properties. If a view is full of empty text fields for example, the contents of the text fields can be bound to different properties of the view model.
There usually really should only be one view model. BUT if it's too complex, you can use subproperties of the bound objects like described in Binding to ViewModel.SubClass.Property (sub-property)
The ViewModel can get the data it returns to the view from a lot of different sources, business objects, databases, whatever.
Usually there is one ViewModel per Model. These ViewModels contain the logic to handle the model's data. On the other side every view has it's own view model, too. So this means:
class ModelA
{
bool TestValue{get;set;}
}
class ViewModelA<ModelA>
{
ValueViewModel<bool> TestValue{get; private set;}
public ViewModelA(ModelA model)
{
base.Model = model;
this.Initialize();
}
}
class ModelB
{
string Username;
}
class ViewModelB<ModelB>
{
ValueViewModel<string> Username{get; private set;}
public ViewModelB(ModelB model)
{
base.Model = model;
this.Initialize();
}
}
These are the ViewModels that encapsulate the models. The views have their own ViewModels:
public ViewModelForExactlyOneView
{
public ViewModelA{get;set;}
public ViewModelB{get;set;}
}
To answer your question, ViewModel1 refers to ViewModelA and ViewModelB. The View therefore can get it's data from ViewModel1.ViewModelA.TestValue.
just use the User model in your view
public partial class User : Login
{
public string Password { get; set; }
public List<Customer> customer { get; set; }
}
in this the another model login inherited and the customer model also used in this model..

Categories

Resources