Ok I really would like to know how expert MVVM developers handle an openfile dialog in WPF.
I don't really want to do this in my ViewModel(where 'Browse' is referenced via a DelegateCommand)
void Browse(object param)
{
//Add code here
OpenFileDialog d = new OpenFileDialog();
if (d.ShowDialog() == true)
{
//Do stuff
}
}
Because I believe that goes against MVVM methodology.
What do I do?
The ViewModel should not open dialogs or even know of their existence. If the VM is housed in a separate DLL, the project should not have a reference to PresentationFramework.
I like to use a helper class in the view for common dialogs.
The helper class exposes a command (not an event) which the window binds to in XAML. This implies the use of RelayCommand within the view. The helper class is a DepencyObject so it can bind to the view model.
The helper class needs a reference to the ViewModel instance. See the resource dictionary. Just after construction, the ViewModel property is set (in the same line of XAML). This is when the FileName property on the helper class is bound to the FileName property on the view model.
I have solved it for me this way:
CommandImpl is not implemented in code below.
ViewModel:
View:
XAML:
The best thing to do here is use a service.
A service is just a class that you access from a central repository of services, often an IOC container. The service then implements what you need like the OpenFileDialog.
So, assuming you have an
IFileDialogService
in a Unity container, you could do...I use a service which i for example can pass into the constructor of my viewModel or resolve via dependency injection. e.g.
and a class implementing it, using OpenFileDialog under the hood. In the viewModel, i only use the interface and thus can mock/replace it if needed.
I would have liked to comment on one of the answers, but alas, my reputation is not high enough to do so.
Having a call such as OpenFileDialog() violates the MVVM pattern because it implies a view (dialog) in the view model. The view model can call something like GetFileName() (that is, if simple binding is not sufficient), but it should not care how the file name is obtained.
Having a service is like opening up a view from viewmodel. I have a Dependency property in view, and on the chnage of the property, I open up FileDialog and read the path, update the property and consequently the bound property of the VM