Question

I am just wondering is this the way to show dialogs in MVVM?

public ICommand OpenFileCommand
{
    get
    {
        if (_openFileCommand == null) {
            _openFileCommand = new RelayCommand(delegate
            {
                var strArr = DialogsViewModel.GetOpenFileDialog("Open a file ...", "Text files|*.txt | All Files|*.*");
                foreach (string s in strArr) {
                    // do something with file
                }
            });
        }
        return _openFileCommand;
    }
}

public class DialogsViewModel {
    public static string[] GetOpenFileDialog(string title, string filter)
    {
        var dialog = new OpenFileDialog();
        dialog.Title = title;
        dialog.Filter = filter;
        dialog.CheckFileExists = true;
        dialog.CheckPathExists = true;
        dialog.Multiselect = true;
        if ((bool)dialog.ShowDialog()) {
            return dialog.SafeFileNames;
        }
        return new string[0];
    }
}

If so how should I allow myself to say modify the options on dialogs I am showing. Example, I want another dialog to have different dialog options dialog.something = something_else without adding alot of arguments to my method

Was it helpful?

Solution

Showing the dialog itself should not happen in a ViewModel. I usually provide a dialog service interface IDialogServices, with appropriate Dialog method calls. I then have one of the View classes (typically the MainWindow) implement this interface and perform the actual Show logic. This isolates your ViewModel logic from the specific View and, for instance, allows you to unit test code that wants to open a dialog.

The main task then is injecting the service interface into the ViewModel that needs it. This is easiest if you have a dependency-injection framework, but you can also do this with a service-locator (a static class where you can register interface implementations) or pass the interface to the ViewModel through its constructor (depends on how your ViewModels are constructed.)

OTHER TIPS

I think using a DialogService is a heavy-weight approach. I like using Actions/Lambdas to handle this problem.

Your view model might have this as a declaration:

public Func<string, string, dynamic> OpenFileDialog { get; set; }

The caller then would create your view model like so:

var myViewModel = new MyViewModel();
myViewModel.OpenFileDialog = (title, filter) =>
{
    var dialog = new OpenFileDialog();
    dialog.Filter = filter;
    dialog.Title = title;

    dynamic result = new ExpandoObject();
    if (dialog.ShowDialog() == DialogResult.Ok) {
        result.Success = true;
        result.Files = dialog.SafeFileNames;
    }
    else {
        result.Success = false;
        result.Files = new string[0];
    }

    return result;
};

You could then call it like:

dynamic res = myViewModel.OpenFileDialog("Select a file", "All files (*.*)|*.*");
var wasSuccess = res.Success;

This type of approach really pays off for testing. Because your tests can define the return on your view model to be whatever they like:

 myViewModelToTest.OpenFileDialog = (title, filter) =>
{
    dynamic result = new ExpandoObject();
    result.Success = true;
    result.Files = new string[1];
    result.Files[0] = "myexpectedfile.txt";

    return result;
};

Personally, I find this approach to be the most simplistic. I would love other's thoughts.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top