I wouldn't use the IoC directly in the VM. But other than that, I think the approach is good. I usually inject a Func<T> for creating the VMs or if using MEF, Lazy<T>. Another approach I have used is to build an IResult for this. So you might
have code like this:
var viewModel = mefLazyVM.Value;
yield return Show.Modal(viewModel);
//do something with the view model's result here
If you don't need the result, you can just do something like this:
yield return Show.Modal<MyViewModel>();
Under the covers, the IResult would use the IWindowManager. It would also wire up to the Deactivated event and fire the IResult.Completed event after deactivation. This would cause your method to "pause" until the user dismissed the modal.
This is my preferred technique, since modals are usually initiated by a user. Also, this is pretty easy to test. Simply provide a fake factory and enumerate the results. Do not call execute on the results, because you are not testing them, you are
testing what results are yielded and what are done with them. Even if you are using Caliburn.Micro, it might be worth the time to look through the ShellFramework present in the full version of Caliburn. Some of these pieces are present there and could be easily
ported to CM in as suits your needs. Just have a look in the Results namespace.