Prism How to bind Module View to app wide property - c#

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.

Related

MvvmLight Messaging - What is the proper way to register and unregister a message?

I ran into the issue where a Message will fire multiple times, because a Message is being registered multiple times when it is registered in the constructor of a View. A large majority of the S.O. posts, websites, blogs show an example like this:
public ConstructorOfView() {
DataContext = viewModelObject;
Messenger.Default.Register<SomeClass>(recipient, token, method);
}
public someUnloadOrNavigateFromMethod() {
Messenger.Default.Unregister<SomeClass>(parameters and more);
}
Unregistering seems to have no effect for me. Some examples say to register messages inside the ViewModel. This doesn't make sense to me for two reasons: 1) If you set the DataContext of a page to a ViewModel, the ViewModel constructor gets called twice again just like the view constructor. 2) If you register a message inside the ViewModel, how exactly do you tell the view to fire a method, other than making it public static, that shows a message dialog?. The third option of just calling a UI-related element like a dialog inside the viewmodel seems to violate the concept of MvvM.
What is the proper way to register and unregister messages?
Some posts have recommended having the viewmodel call Cleanup(), but somehow you need to register messages to the viewmodel, but it's not clear to me how if you set the recipient of the message as the viewmodel, how does the viewmodel call a non-public-static method in the view to change/display UI?
I normally use a pattern where my view models are registered in an IOC container (take a look at the VireModelLocator class in the MVVMLight starter application) and register messages in the ViewModel constructor.
That way, since the ViewModel creation is handled by IOC, you'll have no issues with multiple creations of the relevant view, the message registration happens only once.
Keep also in mind that registering and unsegistering messages will easily take you to a world of very difficult to find bugs where you send a message but for some reason there's no handler registered jet.
I would also add that 99% of view/viewmodel interaction should happen throgh binding.
I strongly suggest to review the WPF application template that MvvmLight provides in order to identify and understand programming patterns.

How to "refresh" my ViewModels after database changes have been done in another ViewModel?

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.

Sharing Collection between ViewModels

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.

How to pass ViewModel to CodeActivity using WF4 with MVVM and WPF

I am trying to integrate my current WPF/MVVM application to Workflow Foundation 4.0.
Currently one of my ViewModel methods is invoking my sample CodeActivity sending it some parameters.
Inside of my CodeActivity execute method I need to call some methods from the calling ViewModel. I would like to know what the best approach is to do this. So far I have identified three possible ways:
Send my ViewModel instance as an input argument to my CodeActivity
Send my ViewModel instance through a Constructor in my CodeActivity like public MyCodeActivity(ViewModel vm)
Wrap my CodeActivity in a WorkflowApplication and send my ViewModel instance as an extension using SynchronizationContext
So far I have tested options 2 and 3 and they work well apparently.
What is the optimal way to do this to avoid any issues like thread synchronization problems or other?
Thanks in advance,
Edit:
Just to mention a possible scenario: If user picks value 'X' from a given dropdown list in my View I need to add object childA and childB to an ObservableCollection contained by a ParentObject exposed through a public property in my ViewModel. The logic to create the child objects and add them to the parent are in my ViewModel. But I want Workflow to contain the Business Rule itself.
Why does your CodeActivity need to know anything about a specific view model? I would look for another solution that allows your activity to maintain as much independence as possible. Two options I can think of off the top of my head:
Use an abstract class or interface so that your activity is not bound to a single viewmodel, i.e., InArgument<IViewModel>
Facilitate communication using an event aggregation pattern (if possible if WF4, not too sure on this yet?), i.e., give the activity what it needs to do it's job and let your view model listen for an event to receive updates from the activity
Without knowing the specifics of your application, I don't know which option would work best (or work at all), but I would avoid a direct connection between a given view model and a given CodeActivity.

Model view presenter, how to pass entities between 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).

Categories