How to access to all viewmodels via the viewmodel base? - c#

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.

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

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.

Questions regarding appropriate use of ViewModelLocator in MVVM

I am working on a WPF/MVVM app using MVVM Light. Right now my ViewModelLocator is pretty standard; it includes a static constructor that registers the ViewModels via SimpleIoc and has properties returning the current instances of the ViewModels.
I don't know how appropriate this is, but I have been exploring using instances of ViewModelLocator in ViewModels to access properties of other ViewModels and to change ContentControl in one of my views. If there are any major problems with doing that, please let me know so that I can find a way around it. For example, I may have something in a ViewModel like:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
private void SomeMethod()
{
_viewModelLocator.OtherViewModel.SomeProperty = something;
}
In a different ViewModel I have the following:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = _viewModelLocator.SomeViewModel;
}
In this case, CurrentViewModel is bound to a ContentControl in my view.
At the moment being able to do this is very convenient but I'd like to get some input from more experienced programmers to make sure that I'm not shooting myself in the foot. If there is a problem with it, are there more acceptable routes I can take to achieve the same results?
Now, if there is nothing wrong with the aforementioned approach, I would like to know if it would be appropriate and/or acceptable to make ViewModelLocator static. To try things out, I did a quick changeover to a static ViewModelLocator. In my MainWindow.xaml, I set the DataContext to:
DataContext="{Binding Source={x:Static vm:ViewModelLocator.Main}}"
...and going back to the first example, I can use:
private void SomeMethod()
{
ViewModelLocator.OtherViewModel.SomeProperty = something;
}
and:
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = ViewModelLocator.SomeViewModel;
}
Right now the program works fine using a static ViewModelLocator, but it is in its infancy, so I'd like to know if this is something that could be a viable option in the future or if I should stay away from a static ViewModelLocator altogether.
Any advice or input on these issues would be greatly appreciated. I am still fairly new to programming and I would like to learn techniques that will serve me well in the long run.
If there are no glaring issues with what I'm doing here, please let me know as well.
Thanks.
It is considered incorrect to reference other view models from view models. This breaks the decoupling that is supposed to make you project more testable and maintainable. If I need to have properties accessable from a number of view models I create a service like iUniversalAppDataService and then use the dependency injection built into MVVM-Light to resolve when the vewimodel is created.
ie this is the constructor of your viewmodel:
public New(IUniversalAppDataService AppDataService)
{
_MyAppDataService = AppDataService;
}
That way any changes/properties within that service are available to any viewmodel that implements the service.
the service needs to be declared in the viewmodellocator as well:
SimpleIoc.Default.Register<IUniversalAppDataService , UniversalAppDataService >
I have used this method to create navigation services that respond to user navigation and of course data services from databases or web data services. I strongly suggest using this service approach because it is WAY easier to maintain in the long run should there be changes to your underlying data model or app architecture.

MVVM : Share data between ViewModels

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.

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