4

I've read through discussions on opening a dialog using mvvm pattern. I've seen several examples that say to use a service, but I'm not understanding how all the pieces fit together. I'm posting this question asking for guidance in what I should read up on to better understand what I'm missing. I'll post what I have below, and it does work, but from what I'm seeing in these posts i'm not doing it right, or maybe not doing efficiently. I see where a dialog interface is created, then a class that uses the interface to do the actual work. Then in the ViewModel a constructor passes in this interface, this is the part that really confuses me, not sure what's passing it in, don't have enough information to connect the dots and not sure what i'm missing.

Here is one post I looked at: https://stackoverflow.com/a/1044304/4593652 I kind of see what they are suggesting, but it's not enough information for someone learning. I'm not asking anyone to write this for me, just hoping for some advice on what I should read up on to understand how these pieces fit together.

In my code I have a class like this: (This works, I just feel like i'm missing something from what I'm reading on other posts)

public class OpenDialogService
    {
    public string GetOpenDialog(string title)
    {
        CommonOpenFileDialog dlg = new CommonOpenFileDialog();
        dlg.Title = title;
        dlg.IsFolderPicker = true;
        dlg.AddToMostRecentlyUsedList = true;
        dlg.AllowNonFileSystemItems = false;
        dlg.EnsureFileExists = false;
        dlg.EnsurePathExists = true;
        dlg.EnsureReadOnly = false;
        dlg.EnsureValidNames = true;
        dlg.Multiselect = false;
        dlg.ShowPlacesList = true;

        if (dlg.ShowDialog() == CommonFileDialogResult.Ok)
        {
            return dlg.FileName;
        }
        return null;
    }
}

Then I use this in my ViewModel when my command is called.

path = new OpenDialogService().GetOpenDialog("...");
Community
  • 1
  • 1
gwm
  • 141
  • 10
  • 1
    Answers will be all kinda opinionated.. If it works for you, stick with it until you find a better way. It's part of the learning process. There's no single "right way" of doing things in programming. – walther Feb 24 '15 at 21:55
  • @walther I'm not sure about that. While there is no single way to program correctly, there are patterns that if you don't implement correctly are no longer that pattern, they're something else. In this case he hasn't implemented the service pattern correctly. – Cameron MacFarland Feb 25 '15 at 02:53

2 Answers2

4

Walther is basicly right.

The other post says that he could change his service implementation via IOC Container. IOC means the "Inversion of Control"-Pattern, you could read this article to get a basic overview. I think "Service" comes also from that Pattern. Another buzzword is Dependency Injection you can look for.

devmb
  • 805
  • 6
  • 18
  • Thanks ec8or. I've read up on IOC and watching some teaching on it. Still a ways to go but I have a much better handling of it now and understand how how the pieces fit together much better than before. – gwm Feb 25 '15 at 16:52
3

Ok, there's a couple of problems here.

As @ec8or pointed out, you should read up on "Inversion of Control" (IoC) as almost all MVVM frameworks use it. The service pattern also relies on IoC so that testing is easier.

The bits missing from your code is an interface for the service, and using the IoC to inject that code into your ViewModels.

public interface IOpenDialogService
{
    string GetOpenDialog(string title);
}

public class OpenDialogService : IOpenDialogService ...

And then to use it in a ViewModel

public class MyViewModel
{
    private IOpenDialogService openDialogService;

    // service injected by the IoC
    public MyViewModel(IOpenDialogService openDialogService)
    {
        this.openDialogService = openDialogService;
    }

    public void DoCommand()
    {
        var path = openDialogService.GetOpenDialog("...");
    }
}

So why do this?

When you test the ViewModel you don't want open dialogs to suddenly pop up, causing the test to fail or hang. So during testing we can change the implementation of IOpenDialogService to something that returns a constant, for example. Then when you test the ViewModel instead of a dialog opening the code will just get the constant and continue running, allowing the test to complete.

This way you don't need to modify the ViewModel code just to get it working during testing.

Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133
  • Thanks, this helped me understand better how the pieces fit together regarding testing my code. I appreciate the guidance. – gwm Feb 25 '15 at 16:53
  • I set my datacontext in my main view like the following, would I still handle that in my xaml now that my viewmodel constructor takes in arguments or is it better to take care of this in code? – gwm Feb 25 '15 at 17:51