Two views - one ViewModel - c#

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

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

Correct approach when notifying ViewModels of UserControl events in WPF MVVM?

In my WPF View, I'm loading data into User Controls like this:
<ContentControl Content="{Binding ItemEditVm}" />
And then in the ViewModel:
private ItemEditViewModel _itemEditVm;
public ItemEditViewModel ItemEditVm
{
get
{
return _itemEditVm;
}
set
{
_itemEditVm = value;
OnPropertyChanged("ItemEditVm");
}
}
I've got a series of DataTemplates to say which View belongs to which ViewModel. And then in my business logic, I can just spin up a new ViewModel for the UserControl then assign it to the property and all works as expected.
However, to resolve the next task in this application, I need to be able to notify the parent ViewModel of events occurring inside the UserControl. I've done this with a simple event on my child ViewModel and a listener on the parent:
public event EventHandler ItemEditViewModelChanged();
So when I create my ViewModel I can just add a listener:
ItemEditViewModel vm = new ItemEditViewModel(itemId);
vm.ItemEditViewModelChanged += vm_ItemEditViewModelChanged;
And do what needs to be done in vm_ItemEditViewModelChanged().
However, I am instinctively uncomfortable with this. While it doesn't violate any MVVM principles direclty (things are still testable, Views and ViewModels are still separate), it doesn't seem a very flexible way of doing things and it does create undesirable logical links between ViewModel classes.
Is there a better way of doing this? Is my approach to creating and loading UserControls into ContentControls a poor way of creating child controls? Or am I worrying over nothing?
I personally prefer to implement things like this with dependency injection. Typically there will be multiple notifications that need to be made, so start by declaring an interface:
public interface ICustomEventHandler
{
void Event1();
void Event2();
// .. etc
}
Then in the child vm you use dependency injection to inject whatever object needs to watch it:
public class ChildVM
{
[Inject] public ICustomEventHandler Watcher {get; set;}
// .. etc ..
}
First of all this makes mocking very easy, so your unit tests are covered, but more importantly you've formalized the dependencies between this module and the rest of the code and also kept your options open as to how best to implement it. (A simple solution would be for the parent to implement that interface directly and inject itself into the child at creation, in another case you may need to use an intermediate class with singleton scoping or multiple clients).
I am not sure whether this work for you but just my thought.
If you have a MainViewModel which holds your all other ViewModels like the picture above then you can expose Properties/Methods to invoke MainViewModel and Let MainViewModel take the decision to talk to a different ViewModel.

WPF - MVVM Viewmodel setup

I'm having some issues with the setup i'm currently using with my mvvm application. Having seen some posts on here, i get the feeling i may be doing this slightly wrong.
I have several models which contain lists of child models such as:
Project - Contains a list of proformas
Proforma - Contains a list of shipments orderedItems
Shipment - Contains a list of Containers
Container - Contains a list of packages
We do not have any viewmodels that relate directly to these model currently, we instead simply have viewmodels that represent the list of models, for example we have a proformalistviewmodel which simply contains a list of proformas.
My issue is, that with this setup i'm a little confused as to what viewmodel should own which data, for example the ProfomalistViewModel has a reference to the currently selected Project, all the data management for these models (the loading and saving of the list of proformas) is done via manager classes which are loaded via DI.
My question is should i instead be following what I'm seeing and having a ProjectViewModel which contains a list of proformas, and a ProformaViewModel which contains a list of shipments and ordereditems and so on.
The reason for this, is that originally none of the models we're linked, projects did not own a list of proformas they were instead loaded separately via the managers using the selected project ID (using a relational db) and we're currently changing the models to the system i described above.
A viewmodel should be a model of the user interaction for a particular area of functionality
For instance, if you have a project list page and the user can do certain things like delete a project, edit a project, print information about the project then you should design a viewmodel that contains the data and actions associated with this interface:
e.g. the viewmodel should contain:
* A bindable container for the project data (list of projects)
* Actions that handle edit/delete interaction
* An action to handle the print functionality
The actual functionality inside these actions may not be contained within the viewmodel (the VM may have received injected services such as the print service or the project repository) but the responsibility of execution of these actions lies with the VM.
It may also be necessary to wrap each data item (project) in a viewmodel so that additional interaction dependent properties/actions can be added - such as the 'selected' property (imagine the user wants to multi-select a load of projects in the view - you could add a selected property to the ProjectViewModel which will wrap each project which makes binding easy)
You may end up with something like the following:
public class ProjectOverviewViewModel
{
public IList<ProjectViewModel> Projects { get;set; }
public ProjectViewModel SelectedProject { get;set;}
public void EditSelected()
{
// Code to open edit page for the selected project
}
public void Print()
{
}
}
and the ProjectViewModel with a selectable property
public class ProjectViewModel
{
// Either put the actual data item in here and wrap it:
public Project Project {get;set;}
// Or copy properties onto the viewmodel using automapper or some other mapping framework...
// or manually :(
// e.g. properties mirrored from the entity object:
public int ProjectId { get;set;}
public string ProjectName { get;set;}
// The selected property - now your 'Selected' logic is a function of the view/viewmodel
// not the entity. The entity should only be concerned with data persistence
public bool IsSelected {get;set;}
}
You may also want to composite viewmodels together in order to build more complex views. Imagine you have a projects page and a "users involved in a project" page, and you wanted another page that showed both side by side (and allowed you to click a project which would refresh the users pane) - this is possible by compositing the viewmodels (by creating another viewmodel which contains the two viewmodels as properties and wires up the interaction between the two)
public class ProjectAndUserOverView
{
public ProjectOverviewViewModel ProjectOverview {get;set;}
public ProjectUsersViewModel ProjectUsers {get;set;}
// Code here to listen for property changes in ProjectOverview and if SelectedProject changes
// call ProjectUsersViewModel to refresh the data for the selected user
}
Ultimately you are just modelling the user interaction, and the more modular you can make it, the easier it will be to make cleaner more maintainable code
There are some good MVVM frameworks - my personal fave is Caliburn Micro as it makes the above very easy (it heavily uses conventions by default) and is easy to get into.
MVVM is design pattern which have 3 parts: Model, ViewModel, View. DIagram looks like this:
http://en.wikipedia.org/wiki/Model_View_ViewModel#Pattern_description
You use ViewModels wrong. Only data for displaying should be in ViewModel.
Your Model for example:
public class Project
{
public Proforma Pr{get;set;}
}
public class Proforma
{
public string Name{get; set;};
}
You have View for project display(I inject ViewModel to constructor, tou can use DataContext instead):
public partial class ProjectView
{
private ProjectViewModel vm;
public ProjectView(ProjectViewModel vm)
{
this.vm = vm;
}
}
If you want to display proforma name on Project view, you should provide it as string in ViewModel.
public class ProjectViewModel
{
private Project pr;
public string ProformaName{get{return pr.Pr.Name;}}
}
If you provide Proforma like proforma, your View will know about model. It will be a violation of the pattern.
My five cent is that MVVM is a pattern, not a religion. I use it at far as it goes and makes sense. There's many parts where MVVM is undefined (like user interaction from commands), and I read a lot about ViewModels being created just to fit MVVM (which bloats both design and object count). I would suggest you think more DataContext-wise, like "Selections of global interest are kept in a global DataContext, Proforma related data is kept in a Proforma DataContext" and so forth, where DataContext is some sort of ViewModel. In the end, you'll probably wind up rigging those up with UI.
You shouldn't create ViewModels for your model objects.
Generally speaking, a ViewModel should belong to a UserControl. Its role is to wire your view (your XAML) together with your model (business logic).
In your case, if I understand it correctly, you have a bunch of classes that implement business logic (Project, Shipment etc.). Your ViewModel will have access to the business logic, and provide properties for your view to bind to.
I do not see any problem with having view models that wrap model data objects. Viewmodels do not have to be "one per view". They can represent a row in a list or whatever.
Having said that, I am quite happy binding directly to model objects and I do it a lot. The only time I create a view model to wrap it is if I need extra state per object that is required by the view.

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