I've searched and nothing is helping me get to where I need to get.
Description of my problem(s):
We have a single dialog window which hosts multiple views (usercontrols). Clicking next and back will move you forward and backwards in this dialog similar to a wizard.
Out of the 6 dialogs, 4 of them reference the same core data. For example we will say an ObservableCollection
That being the case, I have 4 viewModels which all need to reference this same ObservableCollection. I don't want to save and then reload the list everytime I move on to a new step in the "wizard" dialog.
My question is what's the best/most practical way to accomplish this.
The following things I've considered:
Static class
Singleton - ehhhh
Passing parameters between views (although this is difficult as the nextlocation and previouslocation are very generic).
Mediator pattern? My problem with the mediator pattern is that I don't want to "communicate" between views. I just want all of the views to share the same data source.
Observer pattern? If I'm using an ObservableCollections and implementing INotifyPropertyChanged, then I shouldn't need to notify anyone of a change should I?
Please let me know additional info you might need to help me with this and I'll happily provide it.
I'm not really looking for code examples as I am design. Although if code examples can help explain the design, I'm all for it.
Lastly, EventAggregator is not an option as I'm not using any frameworks (unless I'm not understanding EventAggregator correctly).
Thanks in advance!!
like Randolf said DI would work. i do this with MEF and contructor injection with CreationPolicy shared. you just have to put the stuff you wanna handle for you 4views in one export class. how easy is that :)
and btw: Mediator pattern is "communicate" between viewmodels not views.
[Export]
public class MyClassWichHasDataSharedFor4Views {}
public class Viewmodel1
{
[ImportingContructor]
public Viewmodel1(MyClassWichHasDataSharedFor4Views shareddata)
{}
}
public class Viewmodel2
{
[ImportingContructor]
public Viewmodel2(MyClassWichHasDataSharedFor4Views shareddata)
{}
}
public class Viewmodel3
{
[ImportingContructor]
public Viewmodel3(MyClassWichHasDataSharedFor4Views shareddata)
{}
}
public class Viewmodel4
{
[ImportingContructor]
public Viewmodel4(MyClassWichHasDataSharedFor4Views shareddata)
{}
}
now the 4 viewmodels has a reference to your core data
Based on the description of your dialog and how it works, I would have one ViewModel that controlled the overall "Wizard".
This DialogWizardViewModel would contain:
ObservableCollection<SomeModel> Data
ObservableCollection<ViewModelBase> DialogWizardViews
ViewModelBase SelectedView
ICommand NextCommand
ICommand BackCommand
Your DialogView would contain something like a ContentControl bound to the SelectedView, and your Next/Back commands would simply switch the SelectedView to the next or previous view in DialogWizardViews
For example,
<DockPanel>
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Command="{Binding BackCommand}" Content="Back" />
<Button Command="{Binding NextCommand}" Content="Next" />
</StackPanel>
<ContentControl Content="{Binding SelectedView}" />
</DockPanel>
The Data can can set in your child ViewModels when you first create the DialogWizardViews, or whenever you switch the SelectedView depending on what you prefer.
DialogWizardViews = new ObservableCollection<ViewModelBase>()
{
new DialogViewModel1(Data),
new DialogViewModel2(),
new DialogViewModel3(Data),
new DialogViewModel4(Data),
new DialogViewModel5(Data),
new DialogViewModel6()
};
SelectedView = DialogWizardViews.FirstOrDefault();
Remember, with MVVM your ViewModels are your application while the Views just provide a user-friendly interface for users to interact with the ViewModels. Ideally you should be able to run your entire application from something like test scripts, or a console application, without the View at all.
If you need to pass something around, it should be handled by some parent object within the application hierarchy, or use some kind of communications system such as Prism's EventAggregator or MVVM Light's Messenger. You don't need to use the entire framework to make use of these objects - you can just pick out the parts you're interested in.
I know it has been a long time since this question was asked, but after struggling a lot with the same problem
RayBurns's Response here really helped me come to the really simple and relieving realization that there is no need to feel like you have to make viewmodels for each of your usercontrols. I now use one viewmodel for a bunch of different views over the evolution of a Collection as a family of related information whose states are all relevant to eachother .
Otherwise, if you really must share data between viewmodels, I'd absolutely do this as a parameter to the constructor like #blindmeis demonstrates.
The nature of how DataContexts are set up and shared in the first place (for me!) seems to lie in the code-behind of the View. That's the only thing I put there, but it allows me to share ObjectContexts in Entity Framework, establish Master-Details relationships with one view-many viewmodels, etc.
Forming a repository "higher layer" is also great, but be cautious that you're copying over/transferring the data several times over before it reaches its destination.
Anywho, that's my two cents. Hope it helps. After a lot of discomfort that's what I ultimately found myself converging to.
It sounds to me like your views share the same Model, which should be observable, and your ViewModels should all represent the Model in different ways.
If your Model and ViewModels implement the Observer pattern, that seems to be the cleanest, "rightest" approach.
A simple "dependency injection" should work. Constructor of the second viewmodel depends on that Shared Data parameter injected into his constructor, and so on.
Related
I'm new to MVVM so I'm trying to figure out what is the best way to do this. I'm using WPF with Caliburn Micro for this.
I have two different views (each with their view models) for the model I'm trying to manipulate. One view shows the model in a tree view while the other shows a table view of the data.
My model basically looks something like the following
public class Foo
{
public string Name {get;set;}
public string[] Categories {get;set;}
}
The Views are different ways to visualize collections of Foo. The table view is pretty straightforward, but the tree-view will group Foo by the category it contains.
So if an instance of Foo is something like
var fo = new Foo(){Name="one",Categories=new[]{"a","b","c"}};
Then the treeview would be
a
|_ one
b
|_ one
c
|_ one
I have two questions about how to connect the model to the view model in the spirit of MVVM.
What is the best way to populate the viewmodels from the model for the different views? I was thinking something like a singleton FooManager that is accessed from the view models. Or would using the caliburns SimpleContainer be better suited for this?
Lets say I manipulate Foo in the table view by changing it's category collection. How would I propagate the change to the treeview, since that would mean that Foo would appear in a different tree node? Would Foo need to implement PropertyChangedBase' and somehow bubble up the changes to the other ViewModel? Or would it be better forFooManagerto implementPropertyChangedBase`. Seems like the latter would be more reasonable.
TIA
For collections that change reference BindableCollection and are presented on the view.
As for bringing data into a view you can do it through a combination of DI/IoC, via constructor injections on the ViewModel in question. Most of that is done thru Interfaces that can be found in the Container of your choosing either SimpleContainer to MEF if you prefer or what ever IOC/DI container you choose really, the framework is such that can be extended with any container. Going with Interfaces allows for mocking and unit testing of the viewmodels.
Yes bubbling of the change to the View is usually done through what you had though by means of implementing INotifyPropertyChange which is part of the PropertyChangedBase class object.
One thing that will probably rear its ugly head is that Collections based off ObservableCollection don't necessarily bubble the changes of the underlying item's properties in the collection, that is an entirely different thread on SO
I'm currently writing a rather small desktop application using the MVVM Approach. It also utilizes Entity Framework 6 for the database access. Right now, my top-level ViewModel instantiates the 'smaller' ones, and passes them the DbContext I'm using. The smaller ViewModels I use correspond to UserControls sitting in a separate TabItem each. But if I change something in the database in one tab and switch the tab afterwards, the UI isn't keeping up, logically, since there is no OnPropertyChanged("SomeObservableCollection") Happening.
I thought about just "refreshing everything inside" when a TabItem becomes active, but on one hand, I don't know how to do this (it would basically be doing OnPropertyChanged(..) for every UI-relevant property, right?), and on the other hand, it does seem neither elegant nor 'correct'.
What should I do about this? And is using one global DbContext even good practice? I read about short-lived DbContext instances being better, but I also found the opposite statement regarding desktop applications...
How do you handle this scenario? It can't be that rare actually, can it? Thanks!
You have to look at using a Messenger (MvvMLight) or EventAggregator (Caliburn.Micro).
So when your context has changed you pass the message about it and update your SomeObservableCollection so OnPropertyChanged("SomeObservableCollection") will be raised.
Might Help . I have done this in small project . any better solutions are welcomed.
**Viewmodel 1 Where changes occurs**
//database call
string result = _dataService.Insert(data);
if(result=="Success")
{
//notify viewmodels using default messenger instance
MessengerInstance.Send(new NotificationMessage("notifycollection"));
}
Viewmodel 2 where we receive notification
public AssignTimeSlotViewModel(IDataService dataService)
{
// registering the notification
MessengerInstance.Register<NotificationMessage>(this, receiveNotification);
}
#region Messenger - receivers
private void receiveNotification(NotificationMessage msg)
{
if (msg.Notification == "notifycollection")
{
/// Call Database to keep collection updated.
// raise propety changed event if neccessary.
// Do Something
}
}
#endregion
Thats not an easy subject at all.
If you handle with a small amount of data and performance is not a problem for you, you could update your bindings every time the view gets loaded. Here you can see how to accomplish that.
A Problem if you do that is, that you have to do some extra logic for saving last selected items and reselect them after the view gets loaded.
Using a messenger could be an option too. But in my experience the messenger could make thinks messy if it is not implemented correctly. For example please dont use some magic strings as messeages.
I know this may seem silly but, what is the best way to bind to Application Wide properties using MVVM and Prism?
Problem: ConnectionStatus Status {...} (Implements INotifyPropertyChanged etc..)
How do I go about accessing this property in specific modules? I want to be able to use the Status property across different modules?
What is the best way of getting this data across different modules?
Solutions
Currently I am leaning towards having the following view model in the infrastructure project (shared across modules)
namespace Project.Infrastructure
{
public class AppViewModel
{
public ConnectionStatus Status {...}
}
}
And in IoC define AppViewModel as Singleton, and pass this in the constructor of ModuleViewModel
namespace Project.ModuleA
{
AppViewModel _appViewModel;
public class ModuleViewModel
{
public ModuleViewModele(AppViewModel appViewModel)
{
....
}
}
}
Question
Is this the best way to do this or is there a better way of doing this?
E.g.
Using EventAggregator and ConnectionStatusChangeEvent to subscribe and publish to changes in the connection? But in this case if someone subscribes to the event after it got pubblished (such as online) they will not get any starting value, so a IStatusService could be used at the start?
Using RegionContext and binding that to the Status property in the Shell? But this seems to defeat the purpose of Shell not knowing what the Modules use etc..
Or is there something that I have completely missed?
I have read the whole Prism(v4) documentation and just not 100% sure of which is the best way of implementing this.
I do not like ViewModels knowing about each other. I took the approach you listed in E.g #1 - that EventAggregator assists in moving information around for me. I do this currently with a database connection and settings, both used throughout viewmodels. I pass the model property around after it is created first time and when updated.
The ViewModel that creates the model subscribes to a Request and UpdateRequest, and publishes a Response. So a Request returns the current property, UpdateRequest will refresh or recreate as appropriate.
The Response is pushing to any listeners - such as a newly created ViewModel who has in its constructor a publish of the Request. This means that the constructor doesn't initialize everything, your going to have the Response listeners covering extra work, and sometimes you may need to wait for multiple responses to fully initialize.
You asked what is the best way... - I feel my answer is right, but do what is right for your project. I like strict MVVM, but it doesn't always have to be so rigid.
I am wondering is it good practice to try to make a view that takes in a generic view model?
I am wondering this because someone mentioned that he was anticipating to have to do lots of duplicate code unless he started to make a generic view and generic view model.
So basically the views would be like just a set of controls. One view might have 2 controls(say a text-box and radio button) another view might have 50 controls on it.
They will all have the same look and feel(it just grows by number of controls) . Basically he was thinking having a view model takes in the object(domain object) looks at it and see's 50 fields and renders the right control types.
I guess a edit template could be used to figure out the controls however I am just not sold on a generic view model.
I like generics and they can do very powerful things and in some situations they are good but I am just not overall to crazy about them and try to not use.
I find most of the time it may reduce duplicate code but sometimes it makes the code alot more complicated. Of course this could just because I am still a relatively new to programming and it could be still above my skill level.
The next problem I have with it is I think that view models should be as flat as possible and only expose data that is actually going to be used so people don't start using properties that should never been in the view in the first place.
The next problem I have with it that it could just keep going if you have some complex object that has objects in it that has objects in it. It could go for a long long time.
Personally I avoid using generics in view models. I agree with most of the reasons you mentioned against them and particularly this one:
The next problem I have with it is I
think that view models should be as
flat as possible and only expose data
that is actually going to be used so
people don't start using properties
that should never been in the view in
the first place
The idea behind view models is that they need to be specifically tied to the requirements of a given view, not making them general (/generic) as your domain models are. I prefer duplicating code in view models compared to having some generic monster reused all over the views and partials.
And even in cases where you need to generate dynamic forms and controls you don't need to use generic view models.
So, unless you have some hyper specific scenario (can't think of any at the moment), it's probably a good thing to avoid generics in view models.
This being said, don't rule them out completely, if you feel that there is a situation in which generic view models could be useful don't hesitate to present it here, by explaining the scenario and showing all the code so that we can discuss it.
I don't see anything wrong with generic ViewModels. It is a good way to remove duplication and keep compile-time checks, as opposed to ViewBag.
Example:
Imagine you have a set of Model classes for Product, Category, etc.
Each class (ProductModel, CategoryModel) has an associated display and editor template, which generates appropriate view.
Now you want to construct a set of pages for view and edit.
I usually create a Layout (Master page in web forms) to render the common content (header, footer, menu, etc.)
Then I would create individual, strongly-typed views that accept as model ProductViewModel, CategoryViewModel, etc.
Now we need to define those view model classes. Each view model class should take an instance of ProductModel, CategoryModel, etc (which will be passed to the template). But the layout often requires some additional data (ie. selected menu, logged-in user name, etc). My solution is to create a generic ViewModel that encapsulates this duplicate data for the Layout:
public class EntityViewModel<T>
where T : EntityModel
{
public T Entity { get; set; }
public string UserName { get; set; }
public string SelectedMenu { get; set; }
}
Then you can easily create a ProductViewModel : EntityViewModel<ProductModel>, which contains everything the Layout need to render the page, and you can add there any additional, product-specific data.
As far as ViewModels go, I typically have all of my ViewModels inherit from a BaseViewModel that exposes methods that aid in implementing MVVM. If you'd like to see an example, just comment below.
I really do not like puting business logic inside viewmodel. I think that besides regular properties and error handling inside constructor nothing should be in view model. It makes much cleaner code, and you can more freely make additions to view model.
If you have to much duplicated code you can isolate it to separate viewmodel and then nest it where you need it.
This way you also have only what you need on your view.
Edit : Accepted Chris Holmes response, but always ready to refactor if someone come up with a better way! Thanks!
Doing some winforms with MVP what is the best way to pass an entity to another view.
Let say I have a CustomerSearchView/Presenter, on doubleClick I want to show the CustomerEditView/Presenter. I don't want my view to know about the model, so I can't create a ctor that take an ICustomer in parameters.
my reflex would be,
CustomerSearchView create a new CustomerEditView, which create it's own presenter.
Then my CustomerSearchView would do something like :
var customerEditView = new CustomerEditView();
customerEditView.Presenter.Customer = this.Presenter.SelectedCustomer;
Other possible approach would be a CustomerDTO class, and make a CustomerEditView that accept one of those CustomerDTO, but I think it's a lot of work something simple.
Sorry for basic question but all example I can find never reach that point, and it's a brownfield project, and the approach used so far is giving me headache...
I don't know exactly how you are showing your views, so it's a bit difficult to give you specific advice here. This is how I've done this sort of thing before:
What we did was have the CustomerSearchViewPresenter fire an event like OpenCustomer(customerId). (That is assuming that your search view only has a few pieces of Customer data and the customerId would be one of them. If your search view has entire Customer objects listed then you could call OpenCustomer(customer). But I wouldn't build a search view and allow it to populate with entire objects... We keep our search views lightweight in terms of data.)
Somewhere else in the application is an event handler that listens for the OpenCustomer() event and performs the task of creating a new CustomerEditView w/ Presenter (and I'm going to defer to my IoC container do this stuff for me, so I don't have to use the "new" keyword anywhere). Once the view is created we can pass along the id (or customer object) to the new CustomerEditView and then show it.
This class that is responsible for listing the OpenCustomer() event and performs the creation of the CustomerEditView is typically some sort of Controller class in our app.
To further simplify this situation, I've done this another way: I create both the CustomerSearchView (& presenter) and CustomerEditView (& presenter) when the application or module starts up. When the CustomerSearchView needs to open a Customer for editing, the CustomerEditView becomes the responder to the OpenCustomer event and loads the data into itself, and knows how to show itself in whatever container it is supposed to do.
So there's multiple ways to do this.
How about:
//In CustomerSearchPresenter
var presenter = new CustomerEditPresenter();
var customerEditView = new CustomerEditView(presenter);
presenter.SetCustomer(customer);
//In CustomerEditPresenter
public void SetCustomer(customer)
{
View.Name = customer.Name;
View.Id = customer.Id;
...
}
In think your customer search view should just delegate to its presenter you need to have an action execute.
There are a couple of crucial insights to get a natural flow in any MVP code:
It's the presenter that drives the view, not the other way around.
Because of 1. the view need not know about the presenter's existence. Less dependencies usually means easier maintenance.
In C#, I find events being a great asset when decoupling presenters from views. More details in a previous answer: Model-View-Presenter in WinForms
I would look at MS Prism 4, and their nice Navigation interface. Also look at Silverlight and WCF Navigation. They are well done and handle things like prompting the user for confirmation from "dirty" forms, with cancellation.
I would look at the PageFunction() documentation in WCF as well, for how to "call" a page from another, and get back info.
Here's how it works (javascript, sorry):
User double-clicks customer on customer list:
CustomerList.onDblClick(customerId){
app.fireEvent('customerEditRequest', id)
}
...
app.onCustomerEditRequest(id){
this.mainRegion.requestNavigate('customers/edit', id);
}
If navigation to edit view was successful...
CustomerEditView.onNavigatedTo(context){
this.model.load(context.parameters.id));
}
CustomerEditView.onSaveButtonClick(){
this.model.save();
app.fireEvent('customerEdited', id);
}
...
app.onCustomerEdited(id){
app.mainRegion.requestNavigate('customerlist', id);
}
There are a few different ways you could do it:
send a callback function to the edit form, from the customer list. edit form will call it, and you do what you want when it's called.
have the edit form raise on "customerEdited" event that you listen to and react to (no app-wide bus)
use an application-wide Event Bus to manage the events centrally, shown.
I used to have my views communicate with their presenters, but have moved away from that. It doesn't conform to the original definition of a pattern (not a reason in itself for deviating just a contributing factor to exact those benefits). Views ideally should be kept as dumb and with as few dependencies as possible. View should communicate w/ Presenter (any "observers") via delegates/events/some "fire-and-forget" mechanism. As a matter of fact, I've introduced a controller into MVP specifically to intercept View events and either re-fire to presenter (rarely) to communite w/ Presenter, or to communicate with a system or Presenter-specific event bus - enabling me to change user action alerting mechanisms w/out touching the view. Have to be careful with an event bus though; pretty soon you start throwing all events in there, app gets chatty/bogged down in handling events, and events aren't the fastest things in .Net. Sunchronization is an added concern, esp if ur app need to have a more "conversational" interaction with your user.
Should bear in mind that although Presenter is usu view/process-specific, views (and view-models) can be reused; having the View in a containment/delegation relationship with the Presenter strongly couples View/limits its reuse. This could be reduced by some DI, but I find DI containers to be unnecessary complexity in most cases (since I have to know how to create objects anyway and how often do you change out an object for another semantically similar one after creating/testing it?). Concrete dependency goes nowhere except another layer/adds more obscurity/makes things more difficult to debug/trace. Been on a "simplicity" kick lately though, and mostly prefer to do my on Factory/object creations/ORM mappings for most apps, since there's usu a "1-to-1" btw db tables/entities and n need for the added complexity of a generic 3rd-party ORM tool that by taht generic context/needing to serve different apps has to make things harder than they need to be, even if u understand how they work (not the point).
Moreover, it's still quite feasible for View to observe Model in MVP (as in MVC), so I wouldn't be so quick to rule this out. I don't prefer to do this myself, but it' doesn't "break" the pattern. Matter of fact, I developed something similar to MVP about a decade ago because I didnt like the "circular loop" btw the MVC components (View knowing about Model); I preferred to have the cleaner separation btw View and Model that all these patterns (including MVC) professed, as well as a desire to keep View as dumb as possible (observing Model woujld mean View would need more intelligence to process Model changes). What I ended up doing was something like MVVM and strategy patter, where I used "substructures" of the model to pass in to the View, serving as "change notifiers". This kept everything view purpose-specific and flexible/reusable (tough combo).