9

I have an MVVM application. In one of the ViewModels is the 'FindFilesCommand' which populates an ObservableCollection. I then implement a 'RemoveFilesCommand' in the same ViewModel. This command then brings up a window to get some more user input.

Where/what is the best way to do this whilst keeping with the MVVM paradigm? Somehow doing:

new WhateverWindow( ).Show( ) 

in the ViewModel seems wrong.

Cheers,

Steve

4

7 回答 7

2

I personally look at this scenario as one where the main window view model wants to surface a task for the end user to complete.

It should be responsible for creating the task, and initializing it. The view should be responsible for creating and showing the child window, and using the task as the newly instantiated window's view model.

The task can be canceled or committed. It raises a notification when it is completed.

The window uses the notification to close itself. The parent view model uses the notification to do additional work once the task has committed if there is followup work.

I believe this is as close to the natural/intuitive thing people do with their code-behind approach, but refactored to split the UI-independent concerns into a view model, without introducing additional conceptual overhead such as services etc.

I have an implementation of this for Silverlight. See http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspx for more details... I'd love to hear comments/further suggestions on this.

于 2009-09-13T10:26:46.037 回答
1

In the Southridge realty example of Jaime Rodriguez and Karl Shifflet, they are creating the window in the viewmodel, more specifically in the execute part of a bound command:

    protected void OnShowDetails ( object param ) 
    {
        // DetailsWindow window = new DetailsWindow();
        ListingDetailsWindow window = new ListingDetailsWindow();
        window.DataContext = new ListingDetailsViewModel ( param as Listing, this.CurrentProfile ) ; 
        ViewManager.Current.ShowWindow(window, true); 
    } 

Here is the link: http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx

I guess thats not of a big problem. After all, the Viewmodel acts as the 'glue' between the view and the business layer/data layer, so imho it's normal to be coupled to the View (UI)...

于 2009-03-18T07:45:41.647 回答
1

Onyx (http://www.codeplex.com/wpfonyx) will provide a fairly nice solution for this. As an example, look at the ICommonDialogProvider service, which can be used from a ViewModel like this:

ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>();
IOpenFileDialog openDialog = provider.CreateOpenFileDialog();
// configure the IOpenFileDialog here... removed for brevity
openDialog.ShowDialog();

This is very similar to using the concrete OpenFileDialog, but is fully testable. The amount of decoupling you really need would be an implementation detail for you. For instance, in your case you may want a service that entirely hides the fact that you are using a dialog. Something along the lines of:

public interface IRemoveFiles
{
   string[] GetFilesToRemove();
}

IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>();
string[] files = removeFiles.GetFilesToRemove();

You then have to ensure the View has an implementation for the IRemoveFiles service, for which there's several options available to you.

Onyx isn't ready for release yet, but the code is fully working and usable at the very least as a reference point. I hope to release stabilize the V1 interface very shortly, and will release as soon as we have decent documentation and samples.

于 2009-03-19T19:54:48.647 回答
0

I have run into this issue with MVVM as well. My first thought is to try to find a way to not use the dialog. Using WPF it is a lot easier to come up with a slicker way to do things than with a dialog.

When that is not possible, the best option seems to be to have the ViewModel call a Shared class to get the info from the user. The ViewModel should be completely unaware that a dialog is being shown.

So, as a simple example, if you needed the user to confirm a deletion, the ViewModel could call DialogHelper.ConfirmDeletion(), which would return a boolean of whether the user said yes or no. The actual showing of the dialog would be done in the Helper class.

For more advanced dialogs, returning lots of data, the helper method should return an object with all the info from the dialog in it.

I agree it is not the smoothest fit with the rest of MVVM, but I haven't found any better examples yet.

于 2009-03-18T04:00:19.800 回答
0

I'd have to say, Services are the way to go here.

The service interface provides a way of returning the data. Then the actual implementation of that service can show a dialog or whatever to get the information needed in the interface.

That way to test this you can mock the service interface in your tests, and the ViewModel is none the wiser. As far as the ViewModel is concerned, it asked a service for some information and it received what it needed.

于 2009-03-18T04:31:08.120 回答
0

What we are doing is somethng like that, what is described here: http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx

The ViewModel has a property that is called ConfirmDeletionViewModel. As soon as I set the Property the Behavior opens the dialog (modal or not) and uses the ConfirmDeletionViewModel. In addition I am passing a delegate that is executed when the user wants to close the dialog. This is basically a delegate that sets the ConfirmDeletionViewModel property to null.

于 2010-07-19T08:41:56.753 回答
-1

For Dialogs of this sort. I define it as a nested class of the FindFilesCommand. If the basic dialog used among many commands I define it in a module accessible to those commands and have the command configure the dialog accordingly.

The command objects are enough to show how the dialog is interacting with the rest of the software. In my own software the Command objects reside in their own libraries so dialog are hidden from the rest of the system.

To do anything fancier is overkill in my opinion. In addition trying to keep it at the highest level often involving creating a lot of extra interfaces and registration methods. It is a lot of coding for little gain.

Like with any framework slavish devotion will lead you down some strange alleyways. You need to use judgment to see if there are other techniques to use when you get a bad code smell. Again in my opinion dialogs should be tightly bound and defined next to the command that use them. That way five years later I can come back to that section of the code and see everything that command is dealing with.

Again in the few instances that a dialog is useful to multiple commands I define it in a module common to all of them. However in my software maybe 1 out of 20 dialogs is like this. The main exception being the file open/save dialog. If a dialog is used by dozens of commands then I would go the full route of defining a interface, creating a form to implement that interface and registering that form.

If Localization for international use is important to your application you will need to make sure you account for that with this scheme as all the forms are not in one module.

于 2009-03-17T20:06:48.877 回答