MVVM Passing data to dialog View Model
I'm looking into using MVVM and while I understand it for the most part, there is one thing I can't get my head around.
Imagine I have a View and ViewModel combination that show a list of foobars. When the user selects a foobar in the list and clicks the edit button I want the foobar to be shown in a popup dialog window so it can be edited. This dialog window (the view) will have its own associated ViewModel.
I understand that the button can be bound to a command on the list ViewModel, but from here how do I instantiate the foobar editor?
1) Do I have to send a message back to the View, which will open the dialog window? If so, doesn't this defeat the purpose of having the command?
2) How does the foobar get passed into the ViewModel for the editor? If it is by its constructor, doesn't this make it hard to declare the ViewModel开发者_如何转开发 in XAML?
I feel that this is the last piece of the puzzle that is preventing me from using MVVM and I'd really like to get a nice decoupled solution to this.
Thanks Matt
I would perhaps do it in the following way:
- The command attached to the edit button starts edit dialog, creating a custom ViewModel (VM) for it. The command itself should be perhaps either in the list's VM or in the Model (not quite sure).
- Foobar edit dialog's VM gets a reference to the Foobar at its constructor.
- The foobar is cloned and the clone is edited.
- As soon as the user presses OK in the foobar edit dialog, the clone's values are written back to the original foobar in the VM (and the dialog is closed).
The need for a clone comes from the fact that the user doesn't want to see the changes in the foobar list until he accepts the changes in the edit dialog. If however online editing is okay, the clone is not needed.
The changes are propagated automatically.
PS: although I am MVVM's proponent, I am not sure that my solution is an orthodox one from pure MVVM point of view.
This article from codeproject shows a WPF Dialog control that does exactly what you need. The reason this implementation is necessary is that you can't put a Window inside the visual tree of any other control. Which means out of the box WPF doesn't let you create a dialog inside a window. So the above article creates a subclass ContentControl that creates a window.
Anyways, you put this in your FooBarList View
<dialog:Dialog Content="{Binding Path=DialogViewModel}" />
You make sure you have something like this in a resource dictionary somewhere:
<Style TargetType="{x:Type dialog:Dialog}">
<Style.Triggers>
<Trigger Property="HasContent" Value="True">
<Setter Property="Showing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
and just write something like this(For WPF to work you need to implement INotifyPropertyChanged):
public Class FooBarListViewModel
{
IList<FooBar> FooBarList {get;set;}
FooBar SelectedFooBar {get;set;}
ViewModelBase DialogViewModel {get;set;}
public EditFooBar(object param)
{
DialogViewModel = FooBar;
}
}
To link the View to edit the FooBar to the FooBar ViewModel just do something like this(preferably in the Application.Resources so it's global)
<DataTemplate DataType={x:Type vm:FooBarViewModel}>
<vw:FooBarView/>
</DataTemplate>
(Or optionally: Use an IValueConverter to Convert get your View from a ViewModel like this post shows)
And then you're set. May sound like a lot, but it really frees you up a lot.
What’s missing is a Controller which is responsible for the workflow of the ViewModels. The Controller creates the ViewModels and it passes the necessary data between the ViewModels.
The WPF Application Framework (WAF) project contains sample applications that show how this might work.
精彩评论