MVVM design: Blocking MessageBox in ViewModel - c#

This question refers to a WPF application based on PRISM 5.0 and the MVVM pattern.
Sometimes when users make decisions, that could have unwanted or negative consequences, it is very common to ask the user, if he really wants to go on and proceed.
For example:
One common way, is to ask the user with a messagebox, if he really wants to delete data, that can not be restored after deletion.
The problem is:
If I call the MessageBox inside the ViewModel, the ViewModel becomes untestable from the outside.
//BAD!
public class ViewModel
{
public Boolean Delete()
{
//Blocking and therefore untestable in automatic UnitTests
MsgBoxResult result = MsgBox.Show("Do you really want to delete?");
if (result == yes) {//Do stuff that deletes data here;}
}
}
One possibility would be, to ask the question in a different private method, that calls the public method
//BETTER, BUT OK?
public class ViewModel
{
private void OnDeleteAction
{
MsgBoxResult result = MsgBox.Show("Do you really want to delete?");
if (result == yes) {Delete();}
}
public Boolean Delete()
{
//Testable from the outside again, because no blocking question
//Do stuff that deletes data here
}
My question: Is is this a good way or is there a more elegant way to ask the user inside a ViewModel? Can you give me a hint or link, what is the best for PRISM 5.0?
I know, that a rule of thumb is, not to use any UI elements in the ViewModel, but I see no alternative to a blocking MessageBox or something else, that blocks the process, before proceeding.
Thank you any hints!

There are two alternatives that I know of which can reduce coupling between View and ViewModel: using an interaction service, and firing interaction requests. Both are explained very well here; you might want to take a look.
The general idea is that you abstract how asynchronous interactions are done and work with something more similar to event-based logic while at the same time allowing the ViewModel to express that it wants to interact with the user as part of an operation; the net result is that you can document this interaction and unit test it.

Prism Interactivity is the way to go here. This allows you to do Confirmations, Notifications, and create custom dialogs that work well with the MVVM pattern. I use them successfully in my Prism applications.
Here are some links to some code in the Prism repo on GitHub:
Notification Request
Confirmation Request
Custom Content
Custom Request

Related

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.

Prism How to bind Module View to app wide property

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.

Managing prerequisites with MEF and Caliburn Micro

Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.
I thought about this setup:
class Big
{
[ImportMany]
public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
public void Initialize(){...}
}
and
interface IBigPrerequisite
{
public bool IsBusy {...}
public bool Allow {...}
public void StartChecking();
}
Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.
But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?
EDIT - since the question seemed too vague
I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:
Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
pre.PropertyChanged += (s, args) =>
{
if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
{
allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
count++;
if(count == big.Prerequisites.Count() && allow)
windowManager.ShowWindow(big);
}
}
pre.StartChecking();
}
Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.
I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.
Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.
You are mixing concepts here.
Active view management in Caliburn.Micro is handled by the Conductor class. A Conductor-derived ViewModel can display a large number of Screen-derived ViewModels (or other Conductors). Available items are stored in the Items property.
You can find a much better description at "Screens, Conductors and Composition"
MEF has nothing to do with the Conductors and the composition mechanism, although it can be used to pass a list of items to a conductor. You can define an [ImportMany] constructor parameter or public property that receives the Screens to display during initializations and store them in the conductor's Items property.
Using a constructor parameter is more elegant, as you won't have to copy the items from your property's setter to the Items property.
Finally, you shouldn't display messages when creating your views and viewmodels. This is something that should be left for a later step, eg. during the Activate method. The Conductors and MEF get the parts together and build the UI. Executing actions and talking to the user should be done only after the composition step has finished.
I am going to answer this question myself detailing how I ended up solving this.
I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.
It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.
It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.
The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.
Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.

ViewModels opening dialogue

Is anything really wrong with a ViewModel opening additonal dialogues? Lets say I have a MainView and a MainViewModel. The MainViewModel is the datacontext for the MainView and does not, in fact, know or have any dependency on the mainview itself.
However, there are cases when the main view need to open dialogues that will affect the ViewModel data. For example, I may want show a dialogue and diplay some items to allow the users to select from. So, what I have settled on is this:
In my ViewModel, I have the following methods: AddItem, EditItem, and DeleteItem. However, in order to supply the items to add or edit, I need to present a list in some dialogue for the user to to choose from. Right now I have the ViewModel doing this only because I don't want to implement additional levels of abstraction for such simple tasks. Having the ViewModel do this means it can provide the list to be displayed to the user and, when the user finishes editing or selecting, it can easily update its member collections/properties.
Should I be shot for settling with this approach?
Shot? No. But there are good reasons for not doing this.
First, it kills testability of your ViewModel, as there's now a visual component in place. When you try to write automated unit tests against it, you'll still have to interact with it. You could mock it out, but it becomes more difficult to do so when you're calling UI methods.
Second, your viewmodel shouldn't care about what gets displayed. There's a real "separation of concern" issue when you start combining these things.
Third, it just has a "code smell."
There are a few things you can do to circumvent this issue. The first thing I would suggest is Don't use dialogs. Dialogs have their place, but programmers tend to overuse them. Rethink your design, and try to figure out how you can get the job done without interrupting the user.
Second, consider using a messaging framework to send messages between your viewmodel and view to do the navigation to the dialogs (if you absolutely have to use them). Messages are very easy to mock out and/or write unit tests around.
the easy way to do this: use a dialogservice - easy to use, easy to unittest!
see this.
I don't see any problems with ViewModels communicating with each other. The problem is if they start accessing the Views or other Dialogs since that will affect the systems testability.
If you really want a more loosely coupled system you could use some sort of messaging system for communication, but I doubt you need that here :-)
I always use a Seelctor service(just a basic dialog service) to do this - it's testable and mockable and keeps the code very SOLID.
class ViewModel
{
public ICommand ShowListSelectorForCounterparties { get; set; }
public IListSelectorService ListSelector { get; set; }
public void OnExecuteShowCounterpartySelector()
{
this.Counterparty = this.ListSelector.Select<Counterparty>();
}
}
where IListSelectorService can, at runtime, instantiate your dialog, present your list and return the selected item. The main good thing about running it this way is that your unit tests can mock the IListSelectorService.
I'm not sure if you are still looking for any help, but the approach that I have taken when it comes to dialogs is to have the view model raise an event that the view can then handle. The view can now do whatever it wants to get the data to the view model, so you can disply the dialog in the view without a problem. You pass the response from the dialog to the EventArgs of your event so that the view model has the data it is looking for in order to proceed.
For example:
Public Class View
Private WithEvents _VM AS new ViewModel()
Private Sub _VM_AddingItem(Sender AS Object, E AS ViewModel.ItemEventArgs)
Dim Dialog As new SomeDialog()
If Dialog.ShowDialog then
E.Item = Dialog.Item
Else
E.Cancel = True
End If
End Sub
End Class
Public Class ViewModel
Public Sub AddItem(Item AS Object)
Do Some Work here
End Sub
Private Sub _AddItem()
Dim Args AS New ItemEventArgs()
OnAddingItem(Args)
If not Args.Cancel Then AddItem(Args.Item)
End Sub
Protected Sub OnAddingItem()
RaiseEvent AddingItem(me, ItemEventArgs)
End Sub
Public Event AddingItem(Sender AS Object, E As ItemEventArgs)
Public Class ItemEventArgs
Public Property Item AS Object
Public Property Cancel AS Boolean = false
End Class
End Class
Then just wire up your command to the private _AddItem method which just raises the event to collect the necessary data for the AddItem method. I hope this helps :)

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