Aqui estão duas formas elegantes que você pode usar para tratar diálogos WPF a partir do ViewModel. Vou demonstrar os dois exemplos fechando um diálogo de janela WPF a partir do ViewModel, dependendo de alguma lógica.
Usando eventos
A primeira solução é usar um evento que notifica o diálogo da janela para fechar. Considere o seguinte exemplo:
public class DialogViewModel
{
public event EventHandler Saved;
public DialogViewModel()
{
SaveCommand = new DelegateCommand(OnSave);
}
public ICommand SaveCommand { get; }
public void Save()
{
//
// SOME LOGIC TO SAVE GOES HERE
//
Saved?.Invoke(this, EventArgs.Empty);
}
}
A janela de diálogo pode escutar esse evento e se fechar de acordo.
public class SaveDialog : Window
{
public SaveDialog(DialogViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
viewModel.Saved += (s, e) => Close();
}
}
Usando a propriedade DialogResult
Outra forma de fechar um diálogo em WPF é definindo a propriedade DialogResult. Toda vez que definimos o DialogResult como true ou false, o WPF fecha o diálogo automaticamente para nós. Podemos usar isso a nosso favor vinculando essa propriedade à propriedade Result do nosso ViewModel.
public class DialogViewModel : BaseViewModel
{
private bool? _result;
public DialogViewModel()
{
SaveCommand = new DelegateCommand(OnSave);
}
public bool? Result
{
get => _result;
set
{
if (_result != value)
{
_result = value;
RaisePropertyChanged();
}
}
}
public ICommand SaveCommand { get; }
public void OnSave(object parameter)
{
//
// SOME SAVE LOGIC GOES HERE
//
Result = true;
}
}
Em nosso diálogo, Poderíamos simplesmente vincular a propriedade Result ao DialogResult. Isso fecharia o diálogo automaticamente quando definíssemos o resultado como true ou false. Assim:
<Window
...
DialogResult={Binding Result} />
Infelizmente, NÃO PODEMOS. A propriedade DialogResult não é uma Dependency Property e não podemos vincular nada a ela. Para contornar isso, podemos usar uma Attached Property.
public static class DialogExtension
{
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached(
"DialogResult",
typeof(bool?),
typeof(DialogExtension),
new PropertyMetadata(DialogResultChanged));
private static void DialogResultChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window != null && window.IsVisible)
{
window.DialogResult = e.NewValue as bool?;
}
}
public static object GetDialogResult(Window target)
{
bool? bReturn = null;
try
{
if (target != null)
{
bReturn =
target.GetValue(DialogResultProperty) as bool?;
}
}
catch { }
return bReturn;
}
public static void SetDialogResult(Window target, bool? value)
{
if (target != null)
{
target.SetValue(DialogResultProperty, value);
}
}
}
E agora:
<Window
...
local:DialogExtension.DialogResult={Binding Result} />
Conclusão
Provavelmente existem muitas formas de fazer isso; essas duas são as que considero mais elegantes.