MVVM issues with the concept of IResult with OpenFileDialog etc

Topics: Actions & Coroutines
Jul 28, 2013 at 9:20 AM
I am new to Caliburn.Micro and usually if you are new to MVVM you tend to ask those questions like how should I display an OpenFileDialog with MVVM.

After reading about IResults I have some issues with them. The docs about IResult and Coroutines state that they can be used to implement OpenFileDialog.

I may not fully grasp the concept but for me this does totally kills the "no view logic in view model" as such an OpenFileDialog coroutine would be executed in view model popping up some dialog when run with unit tests.

In my point of view the view itself is responsible to provide the OpenFileDialog and simply return the file or whatever needed to the view model. How the view implements this, by OpenFileDialog or some self made browser, web service, guessing etc is completely irrelevant for the view model.
This is where I usually break MVVM and execute logic in code behind to do view related code and then execute a command with the value.

With IResult I would the view model require knowledge about the view and also need boiler plate code to mock the particular coroutine away which requires some additional logic as this coroutine must be provided by a service or dependency injection.

Am I getting this wrong?
Jul 29, 2013 at 8:20 AM
I suppose that many people tend to consider co-routines (and IResult) as part of the view-model domain (maybe because of the fact that you instantiate an object directly in the view-model code), while they are actually part of the 'service' domain. They are neither view, nor view-model, and just like a pseudo-conductor (such as the one used in the WindowManager), they can be used to 'bind' view and view-model without creating and hard dependency between them.

Regarding the fact that an IResult used to display a file dialog cannot be really unit-tested, I must say that it's just a matter of how you write your code. I would probably use a combination of IoC and IResult (e.g. provide a delegate used to create an ISelectPathResult implementing IResult, and two implementations of ISelectPathResult, one used to display the actual dialog, and a mockup used in tests):
public interface ISelectPathResult : IResult
{
      ...
}

public class SelectPathResult : ISelectPathResult
{
      ...
}

public class TestSelectPathResult : ISelectPathResult
{
      ...
}

//The actual ISelectPathResult depends on which type is registered in the IoC
var selectPathResult = IoC.Get<ISelectPathResult>();
Coroutine.BeginExecute(new [] { selectPathResult });     //The actual code may vary depending on the context where the ISelectPathResult is used...
That said, I mostly don't use co-routines, since I prefer a more explicit service-based design (in my case I use an actual ISelectPathDialog, that can be handled by a service extending IWindowManager, so that the view/view-model linking is performed by a pseudo-conductor), but it's just a matter of tastes.