|
|
Comments and Discussions
|
|
 |

|
Hi,
Thanks for the samples. I am quite new at this and I have been looking for something like this for quite some time.
I used your classes and I get the following exception every time:
Viewmodel is not referenced by any registered View.
in the FindOwnerWindow method of the DialogService class. it seems that the views member of the DialogService is not populated with my MainWindow.
When I debug, the code never goes through IsRegisteredViewPropertyChanged
Am I declaring some in the wrong way?
public class MainWindowViewModel : ViewModelBase
{
private readonly IDialogService dialogService;
public MainWindowViewModel()
{
this.dialogService = ServiceLocator.Resolve<IDialogService>();
OpenDialogCommand = new RelayCommand(OpenDialog, CanOpen);
}
public ICommand OpenDialogCommand { get; private set; }
private void OpenDialog(object o)
{
NewDialogViewModel newDiag = new NewDialogViewModel();
dialogService.ShowDialog(this, newDiag);
}
private bool CanOpen(object o)
{
return true;
}
}
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ServiceLocator.RegisterSingleton<IDialogService, DialogService>();
ServiceLocator.RegisterSingleton<IWindowViewModelMappings, WindowViewModelMappings>();
MainWindow test = new MainWindow();
test.Title = "New";
test.DataContext = new MainWindowViewModel();
test.Show();
}
}
Thanks in advance.
|
|
|
|

|
I am guessing that you haven't set the attached property DialogService.IsRegisteredView in the XAML.
|
|
|
|

|
Yes! Indeed I was missing this.
Thanks again for the samples and help!
Cheers.
|
|
|
|
|
|

|
I am developing a WPF application that follows MVVM pattern. To display modal dialogs, I am trying to follow the way you have suggested.
Situation in my application is slightly different.
I have an ApplicationViewModel class that acts as ViewModel for MainWindow.xaml.
This ApplicationViewModel contains a ViewModel, say VM1 which in turn contains
another ViewModel, say VM1Child;
MainWindow.xaml contains a user control say ChildView1 which is binded with VM1. ChildView1 contains another user control say ChildView11 which is binded with VM1Child.
VM1Child contains AddCommand, and I need to display Modal Dialog when AddExecute method corresponding to AddCommand is called. How can I accomplish that?
|
|
|
|

|
If you register ChildView11 in DialogService, i.e.
<UserControl
x:Class="Test.ChildView11"
...
service:DialogService.IsRegisteredView="True">
</UserControl>
you should be fine.
|
|
|
|

|
That change alone was not enough. I had to modify FindOwnerWindow method in DialogService class. private Window FindOwnerWindow(object viewModel) { FrameworkElement view = null; // Windows and UserControls are // registered as view. // So all the active windows and // userControls are contained in views foreach (FrameworkElement viewIterator in views) { // Check whether the view // is an Window // If the view is an window // and dataContext of the // window, matches with the // viewModel, then set // view = viewIterator Window viewWindow = viewIterator as Window; if (null != viewWindow) { if (true == ReferenceEquals(viewWindow.DataContext, viewModel)) { view = viewWindow; break; } } else { // Check whether the view // is an UserControl // If the view is an UserControl // and Content of the userControl, // matches // with the viewModel, then set // view = userControl // In case the view is an user // control, then find the // Window that contains the // user control and set it as owner System.Windows.Controls.UserControl userControl = viewIterator as System.Windows.Controls.UserControl; if (null != userControl) { if (true == ReferenceEquals(userControl.Content, viewModel)) { view = userControl; break; } } } } if (view == null) { throw new ArgumentException("Viewmodel is not referenced by any registered View."); } // Get owner window Window owner = view as Window; if (owner == null) { owner = Window.GetWindow(view); } // Make sure owner window was found if (owner == null) { throw new InvalidOperationException("View is not contained within a Window."); } return owner; } Please have a look at it.
|
|
|
|

|
I fail to see why the code works in your situation. Isn't it identical to mine, with the only change that you only allow Window and UserControl being registered, while I allow any FrameworkElement.
In that regard, your code is more restrictive than mine, which is the reason I don't understand why your code works and not mine. Could you please help me understand? Is your code open-source, i.e. can I look at it?
|
|
|
|

|
I Think the problem lies in the following line of code. FrameworkElement view = views.SingleOrDefault(v => ReferenceEquals(v.DataContext, viewModel)) In my application,in case of user controls, the corresponding viewModel is content of that user control, not the DataContext.
|
|
|
|

|
The lines after the one you posted should take care of that:
Window owner = view as Window;
if (owner == null)
{
owner = Window.GetWindow(view);
}
If view isn't a Window, Window.GetWindow(view) will get the window. These lines are all part of the source code, can you verify that you have them?
|
|
|
|

|
I corrected my post. Please have a look at it. The reason is something else. I edited my post accordingly.
|
|
|
|

|
If your changes work go with them, otherwise provide me with a sample that can compile that has the issue.
|
|
|
|

|
It is working. Thank you very much for your help.
|
|
|
|

|
Here is a better solution to that so called "problem":
Window.ShowDialog()
Yay!
|
|
|
|

|
This saved me a lot of time figuring out how to use MVVM with dialogs myself. I only had to make a few minor changes to make it work with my View and ViewModel in separate projects. Thank you!!
|
|
|
|

|
Congratulations!
I have been looking to overcome this problem in MVVM for months. The sad reality is that the most important personalities I know (that are really good developers), have always been silent about this issue. I even contacted with Laurent Bugnion, author of MVVM Light. He is busy and presented a very basic approach to the problem, that was in fact, limited to Yes, No, Cancel dialogs. Josh Smith left .NET. Wrote to Tomer Shamam, didn't reply, yet. No other trustyworthy person want to say a word on this.
Well, I'm stuck with no solution. Yours seems to be a blow of fresh air. Can you please tell me if you plan to update this? Please, add me to your Twitter account or tell me your username I'm @SuperJMN.
I have high hopes on you.
Thanks a lot.
|
|
|
|

|
Hi CandyBeat.
The problem of opening dialogs or message boxes is usually solved in one of two ways: either by using a mediator (like Laurent Bugnion) or a service that handles the problem. I prefer the latter. The only problem with going that route is how do one connect a view and a view model before opening it as a dialog? My solution enforces the developer to either declare the view type, which to some MVVM developers is a sacrilege, or to have a mapper class describing the relationship between views and view models.
I have no plans to update the article in the near future. I would propose you to have a look at Sacha Barber's MVVM framework called Cinch[^]. It is a competent framework with a lot of downloads, which hopefully means that it will be maintained.
If you have any specific questions, feel free to ask.
|
|
|
|

|
Hi! I see your point and I think you're right. Connecting the View and the ViewModel should be made by a third component in the relationship.
I saw in your simple App that you are using the Service Locator pattern. Do you think you could build a sample using MEF? Would it be too complex? About the Cinch Framework, I think I will make the step, but I'm afraid of using a Framework that is somewhat unofficial or unsupported. Anyways, I will look into it.
Regarding the need of using Windows from the ViewModel this is my point of view:
You are in a Window (main) and the user chooses to edit some type of entity, for example, the user wants to Options/Preferences… Then in an abstract way of seeing this, the user want to temporarily change the context (the focus of his actions) and the unique reason for it is to modify data related with preferences. This is: the user wants to edit some Preferences ítem and when it's done, he will go back to where the actions started.
In fact, I see the workflow like calling an external program that modifies the required information and returns. This is valid only for Dialogs (Modal Windows). So the ViewModel may start up the action just with a method like:
var returnValue = DialogService.Edit(preferences);
The DialogService then should execute the necessary actions to edit that entity. Of course it would have some overloads so the developer would choose what kind of "Edit" he will be using (over the and a default one).
Please, tell me your opinion. And THANKS a lot for your comment!
|
|
|
|

|
You can download the code using MEF from here. I think you need Visual Studio 2012 in order to open it.
Regarding your thoughts on how the dialog service should operate, here is my spin on it. I think the DialogService needs to be generic and ignorant of anything else than opening dialogs. This basically translates well into the single responsibility principle. That means that some other class needs to take responsibility of:
1. Opening the dialog using the dialog service
2. Wait until dialog is closed and investigate whether the user wishes to proceed with saving the changes
3. Save the changes
To me this sound like the kind of code I would place in a command, e.g. a command called PreferencesCommand that would be called from the application menu or whatever.
Does this sound reasonable?
|
|
|
|
|
|

|
I see no reason for a service.
See this[^]
If it's not broken, fix it until it is
|
|
|
|

|
The core of the service is dialog management. A view model in my perspective should not hold a instance of a dialog and call its Window.ShowDialog, instead it lets the service open the dialog. This, among other things, makes writing unit tests easier.
I glanced at your code and nowhere do I see you opening a dialog from a view model, which is the whole purpose of this article. Could you elaborate on the validity of your comment, and how you propose to accomplish the task with your code?
|
|
|
|

|
disore wrote: I glanced at your code and nowhere do I see you opening a dialog from a view model
and
disore wrote: A view model in my perspective should not hold a instance of a dialog
You're saying two different things here.
A ViewModel should never open a View. That couples them together, which isn't separation of concerns. Use a factory instead.
If it's not broken, fix it until it is
|
|
|
|

|
Let me make myself perfectly clear since you obviously are putting a lot of effort in trying to misunderstand me.
Fact 1: ViewModelA is data context to the view DialogA
Fact 2: In view DialogA there is a button bound to a command in ViewModelA
Fact 3: ViewModelB is data context to the view DialogB
Scenario: When the user clicks the button in DialogA, DialogB should be displayed
Please explain how you would do this in MVVM with referring to the code in your article.
|
|
|
|

|
disore wrote: Let me make myself perfectly clear since you obviously are putting a lot of effort in trying to misunderstand me.
I'm not putting effort into anything. I just think your 'solution' is over-engineered. I'm entitled to my opinion, and based of the votes you're getting, I'm not alone. If you can't take constructive criticism, then you're not going to learn.
The click event should never create an instance of a view. That couples the ViewModel for View A to the View B. As I said, look up factory patterns. I have a code example at home. I'll try to remember to post it later tonight.
If it's not broken, fix it until it is
|
|
|
|

|
Constructive criticism means you should provide me with at least one alternative solution solving the same problem in a more elegant/optimized/cleaner way, and still you haven't presented one yet.
I asked you for a solution based on three facts and one scenario, and you give me ramblings about click events? Read my previous post again. The button is bound to a command in the view model, no events anywhere. You use commands in your own article, surely you must understand the basics of them?
You are also saying that ViewModelA isn't suppose to create ViewModelB. I can live with that. Let the view models inherit interfaces and have a dependency injection framework create them for us. But indifferent of whether we use a DI-framework or the factory pattern, the problem of opening dialogs still exist.
This is a challenge: provide a solution for the three facts and one scenario. I'll see what you've come up with first thing tomorrow.
|
|
|
|

|
disore wrote: Constructive criticism means you should provide me with at least one alternative solution solving the same problem in a more elegant/optimized/cleaner way, and still you haven't presented one yet.
I'v done that already twice. For the third time, look up factory patterns.
I'm not going to do your research for you.
We're done here.
If it's not broken, fix it until it is
|
|
|
|

|
The factory pattern is a creational pattern, thus have nothing to do with opening dialog from a view model, which is what this article aims to provide a solution for.
With all due respect sir, I don't think you know what you are talking about. Please don't post any more messages until you know what you are talking about, they are clearly worthless.
|
|
|
|

|
I use a factory patter to open dialogs in my MVVM apps, so it certainly is not me who is clueless.
You're an arrogant ass and I'll have nothing more to do with you.
Vote 1
If it's not broken, fix it until it is
|
|
|
|
|

|
i'm quite disappointed sir.
i saw the sample project and i noticed that you need to make those many classes and interfaces for each viewmodel.
|
|
|
|

|
Can you please elaborate more on your thought regarding the code? Which are the 'many classes', and which specific interfaces do you have a problem with?
|
|
|
|

|
all i want is to avoid referencing view classes in the view model.
i see that you can do it by registering a view class to the view model.
but what i am disappointed with, is that i need to create Service Interface (i.e. IPersonService) for every Model Class and create a class(i.e. PersonService) that implements it.
|
|
|
|

|
CodeLinguist wrote: i see that you can do it by registering a view class to the view model.
Yes, the implementation of IWindowViewModelMappings which in my case is WindowViewModelMappings contains the relationships between views and view models. But no view model interfaces are involved in this stage, i.e. MainWindowViewModel and PersonDialogViewModel doesn't have to inherit some special interface.
CodeLinguist wrote: but what i am disappointed with, is that i need to create Service Interface (i.e. IPersonService) for every Model Class and create a class(i.e. PersonService) that implements it.
This has nothing to do with MVVM or the solution I am presenting when it comes to opening dialogs from a view model. You don't have to have a service with a Load method that returns the persons, how you instantiate your models is up to you. For all I know the models in your application can be provided by a RIA-service and sent over HTTPS to your client. I am not presenting a solution on how to load models, I am presenting a solution on how to open dialogs.
|
|
|
|

|
how about defining an IView interface, put a property of that type for every view model and set the view at application startup?
in this way i you can avoid mentioning(referencing) the view classes and
the view models can directly communicate to each other..
does this make sense?
interface IView
{
object DataContext;
void Show();
bool? ShowDialog();
}
class PersonViewModel: ViewModelBase
{
public static Type _View;
public static Type View
{
get{return _View;}
set{
if (value.GetInterface("IView"))
throw new ArgumentException("does not implement IView interface")
_View=value;}
}
public bool? ShowDialog()
{
var view = (IView)System.Activator.CreateInstance(View);
view.DataContext = this;
return view.ShowDialog();
}
}
class PersonDialog : Window, IView
{
...
}
class App
{
protected override void OnStartup(StartupEventArgs e)
{
PersonViewModel.View = typeof(PersonDialog);
}
}
|
|
|
|

|
This is a perfectly viable solution as well, but I would recommend having another class opening the dialogs, not the view models them self. Otherwise unit tests could hang because a dialog was opened.
|
|
|
|
|

|
Hi CodeLinguist,I am interesting in your above code, I am a new learner about MVVM, would you pls show me detailed info to showdialog ? thx.
I can do!
|
|
|
|

|
I don't see how this facilitates separation of concerns at all. I have an application in which the View and ViewModel layers are in completely separate projects. Having the View project dependent on the ViewModel project would be undesirable, albeit not the end of the world, but I'm sure we can all agree that having the ViewModel dependent on the View would totally break the MVVM pattern.
In the solution you've provided your WindowViewModelMappings needs to go in the View because it needs to know about the dialog windows (i.e. PersonDialog). DialogService uses WindowViewModelMappings directly so it too must go in the View. But DialogService is used by MainWindowViewModel in order to invoke the dialog window, and since it can't be moved out of ViewModel you wind up with the ViewModel needing the reference the View solely to use the dialog service. The only reason your example project compiles at all is by virtue of the fact that the two layers appear in the same project. True separation of concerns hasn't really been achieved because the architecture breaks once the two layers are separated.
Please correct me if I'm wrong or have missed something obvious.
|
|
|
|

|
Hi Mongalong.
Lets start with the issue of two projects. I usually place views and view models in the same project. Why? Because even though they aren't referencing each other, changes in the view most often means changes in the view model. For convenience, if the two classes are located on the same place it means less browsing in the solution explorer for me. Does this mean I am breaking separation of concern? No. Most MVVM samples are having views and view models in different projects, but I fail to see the real benefit of that structure. You could perhaps enlighten me?
Lets continue with the remarks about references between projects. Here is a project structure which I think satisfies your needs:
ViewProject - Your project with views. This should only reference MvvmProject.
ViewModelProject - Your project with view models. This should only reference MvvmProject.
MvvmProject - This project should contain all MVVM service classes and their implementation, and also the interfaces they are referring to in my code sample, e.g. IWindowViewModelMappings. It should be considered as the project where classes helping you develop efficient MVVM code is located.
ApplicationProject - This is the final project, and should act as the entry point of the application. It is referencing all other projects and is responsible for setting up the service locator. This means that the implementation of WindowViewModelMappings is located here, since this project knows of both views and view models.
This architecture doesn't break separation of concern since the views are unaware of view models, and view models are unaware of views.
Did I make any sense?
|
|
|
|

|
The project structure you propose is indeed what we use ourselves but I haven't yet been able to shoehorn your solution into that structure. I'll keep trying though because in principle I do like many aspects of your implementation.
With respect to separating ViewModels and Views into different projects, I found this became an issue during unit testing. Like a lot of other projects we have a DLL project for unit testing that NUnit can load and run as well as a console application that loads that same DLL, fires off the unit tests and performs various reports. The tests themselves consist of standard domain level tests (CRUD etc) but we also do full integration testing in which the unit tests effectively run the application (i.e. the ViewModels) and simulate user input by firing off the various ICommands etc that GUI elements are normally responsible for. For example, a typical test might be for the user to select an option from the menu and for the correct page (i.e. SomeChildPageViewModel) to be added to the MainWindowViewModel's collection of open pages. The only way you can do this is if you can run the ViewModel layer standalone.
With respect to dependencies, my experience has been that the View project has to be dependent on the ViewModel project, there's not really any way around that in a real application. At the very least the View is dependent upon the ViewModel in an abstract conceptual sense since it has to adhere to the object interfaces in order for data binding to work, but it also needs to be dependent upon it in practice as well. Many of the data types that your Views will pass to the ViewModels will be things like typed enums etc that are declared in, and ultimately used by, the ViewModel objects, so that reference has to be there in order to refer to them in the XAML.
|
|
|
|

|
I'm sorry but have only minor experience in full integration testing, I usually only unit test and leave the UI testing for the Quality Assurance team. Although, I would be interested in what your experiences are with integration tests. Are they hard to write? Are they prone to be updated due to changes in UI? Etc...
I agree with you that there is a dependency between views and view models in the respect of bindings. And I find it perfectly acceptable for views to know about their view models. When writing XAML I always define d:DataContext="{d:DesignInstance local:SomeViewModel}" to get validation that the bindings are correct, and this is only possible if the view have a reference to the view model.
Good luck, I really hope you find a solution to your problems.
|
|
|
|

|
Hi Disore, I've seen that you use code contracts in your code and have setup an NUnit and Moq project. I am a Visual Studio 2010 Express user and was wondering if the code contracts can be tested with Nunit or Moq (independently of VS Express)? Do you have any experience with that? Thanks for the great article Dirkster99
|
|
|
|

|
Hi.
No, sorry, I have no experience of that. I only used code contracts for a short period of time, since I think they are too restricted. It was a good idea, but I am finding myself perfectly ok without them.
|
|
|
|

|
Hi Disore, Thanks for the info. I cam across a similar problem as you try to solve in your article - I have also written an article <a href="http://www.codeproject.com/Articles/413517/Closing-Windows-and-Applications-with-WPF-and-MVVM">Closing Windows and Applications with WPF and MVVM</a>[<a href="http://www.codeproject.com/Articles/413517/Closing-Windows-and-Applications-with-WPF-and-MVVM" target="_blank" title="New Window">^</a>] to see if I can get a simple reference application that could be MVVM conform in WPF (I did not know your article then). My first version was not received too well. So, I researched service patterns in more detail and found your article and incorporated the DialogService into a second code sample in my article. Please have a look and let me know if there is something crucial missing or wrong. Thanks again for the service sample here - I find your article quit useful indeed
|
|
|
|

|
This demonstrates an effective way to separate concerns, but it seems to me a bit overly complicated just to invoke a dialog.
In the framework we use (built in-house), if a view wants to show another view such as a dialog, it invokes an ICommand on its viewmodel, which can then do any preliminary work as needed (e.g., run stuff through domain objects), and raise an event for the view to handle (event data contains a new viewmodel needed by the new view), at which point the view creates and opens the new view. The view does indeed know its viewmodel (but not vice versa), which I find completely acceptable, and we have base classes for views and viewmodels that provide common behavior. There's some code-behind in the base view class to wire this up, but I also find that completely acceptable, so long as concrete views have very little or none.
Again, though, your solution is pretty elegant and does keep things decoupled.
|
|
|
|

|
Hi Phil.
I've seen view driven examples to open dialogs and message boxes, and have nothing against them. In your example the view runs a command to indirectly open the dialog, but I assume the view model could run that command as well based on its own decisions, i.e. the operation of opening a new dialog doesn't have to be started by the view, it could be started by the view model as well?
I am unsure whether you can talk about your solution since it in-house (I developed this code on a dare by a co-worker that some kind of registration between view and view model had to be made before opening dialogs could be accomplished, and we ended up using this code at work after I won the dare) but how does the view model know when the new dialog has been closed? A event is sent when the dialog should be opened, is another command executed by the view when the new dialog closes?
As a final remark, I implemented this solution with one requirement in mind: opening dialogs should be accomplished with minimal code in view and view model, i.e. the footprint of the dialog framework should be kept at a minimal. Setting one attached property in the view, and call one method on a already implemented interface is pretty simple according to be. No boiler plate code, nothing strange. Just a synchronous call to a service and then investigate the result, pretty simple don't you think?
|
|
|
|

|
Like what you have done. I have been following what you have done and adapting it so it fits my project. How can we go about making the popup dialog Edit data; in other words, when we select a Person from the list and click on "Show Information", ideally we can change data and click Save.
So sending the modified data to the PersonViewModel is what I am after...
Thanks in advance...
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A solution for how to solve the problem of opening dialogs from a ViewModel when using the MVVM pattern.
| Type | Article |
| Licence | CPOL |
| First Posted | 26 May 2009 |
| Views | 140,801 |
| Downloads | 4,785 |
| Bookmarked | 138 times |
|
|