Há duas boas maneiras de fazer isso: 1) um serviço de diálogo (fácil, limpo) e 2) visualização assistida. A exibição assistida fornece alguns recursos interessantes, mas geralmente não vale a pena.
SERVIÇO DE DIÁLOGO
a) uma interface de serviço de diálogo como via construtor ou algum contêiner de dependência:
interface IDialogService
{
Task ShowDialogAsync(DialogViewModel dlgVm);
}
b) Sua implementação do IDialogService deve abrir uma janela (ou injetar algum controle na janela ativa), criar uma exibição correspondente ao nome do tipo dlgVm fornecido (use convenção ou registro de contêiner ou um ContentPresenter com o DataTemplates associados ao tipo). ShowDialogAsync deve criar um TaskCompletionSource e retornar sua propriedade .Task. A própria classe DialogViewModel precisa de um evento que você possa chamar na classe derivada quando desejar fechar e observe na exibição da caixa de diálogo para realmente fechar / ocultar a caixa de diálogo e concluir o TaskCompletionSource.
b) Para usar, basta ligar para aguardar this.DialogService.ShowDialog (myDlgVm) em sua instância de alguma classe derivada de DialogViewModel. Depois de aguardar retorno, consulte as propriedades que você adicionou na sua VM de diálogo para determinar o que aconteceu; você nem precisa de um retorno de chamada.
VIEW ASSISTED
Isso faz com que sua visualização ouça um evento no modelo de visualização. Tudo isso pode ser envolvido em um Blend Behavior para evitar o código por trás e o uso de recursos, se você quiser (FMI, subclasse a classe "Behavior" para ver uma espécie de propriedade anexada ao Blendable em esteróides). Por enquanto, faremos isso manualmente em cada visualização:
a) Crie um OpenXXXXXDialogEvent com uma carga útil personalizada (uma classe derivada de DialogViewModel).
b) Faça com que a visualização assine o evento em seu evento OnDataContextChanged. Certifique-se de ocultar e cancelar a assinatura se o valor antigo! = Null e no evento Descarregado da Janela.
c) Quando o evento for disparado, abra a visualização, que pode estar em um recurso da sua página, ou você poderá localizá-lo por convenção em outro local (como na abordagem do serviço de diálogo).
Essa abordagem é mais flexível, mas requer mais trabalho para usar. Eu não uso muito. A única vantagem interessante é a capacidade de colocar a visualização fisicamente dentro de uma guia, por exemplo. Eu usei um algoritmo para colocá-lo nos limites do controle de usuário atual ou, se não for grande o suficiente, percorrer a árvore visual até encontrar um contêiner grande o suficiente.
Isso permite que as caixas de diálogo fiquem próximas ao local em que são realmente usadas, apenas diminua a parte do aplicativo relacionada à atividade atual e permita que o usuário se mova dentro do aplicativo sem ter que empurrar manualmente as caixas de diálogo, mesmo tendo várias diálogos modais são abertos em diferentes guias ou sub-visualizações.