MVVM

MessageBox dal ViewModel senza violare il pattern MVVM

Nel momento in cui decidiamo di realizzare un’applicazione, ad esempio per WP7, utilizzando il pattern MVVM ma senza adottare uno dei framework a disposizione (vedi MVVMLight,Caliburn Micro, …) ci dobbiamo aspettare di dover risolvere alcuni problemi per garantire sempre e comunque il disaccoppiamento tra UI e logica di presentazione e di business che il pattern stesso ci permette di ottenere.

Uno di questi problemi può essere ad esempio la necessità di visualizzare una MessageBox, quindi un componente della UI, a partire da un metodo del ViewModel corrispondente alla pagina nella quale ci troviamo. Tala problematica può essere risolta implementando un servizio che verrà “iniettato” nel ViewModel e che avrà il compito di visualizzare la MessageBox su richiesta.

Poiché dobbiamo garantire che non ci siano dipendenza strette tra il ViewModel e l’implementazione del servizio in questione, bisogna ragionare in termini di interfacce. Possiamo definire, quindi, un’interfaccia per tale servizio in modo da dare la possibilità di implementarla di volta in volta in maniera diversa; nel nostro caso l’implementazione che realizzeremo farà uso della MessageBox dalla quale prendiamo spunto per definire i metodi dell’interfaccia.

public interface IDialogService
{
    DialogResult Show(string messageText);

    DialogResult Show(string messageText, string caption, DialogButton button);
}

L’interfaccia IDialogService espone gli stessi metodi della classe MessageBox (nella quale però sono statici) mentre DialogResult e DialogButton, definiscono rispettivamente i possibili valori restituiti dalla dialog box a seguito dell’interazione con l’utente ed i bottoni che vogliamo visualizzare al suo interno. Per semplicità, sono stati definiti con due enumerativi uguali a quelli corrispondenti per la classe MessageBox (MessageBoxResult e MessageBoxButton).

public class DialogService : IDialogService
{
    #region IDialogService...

    public DialogResult Show(string messageText)
    {
        MessageBox.Show(messageText);
        return DialogResult.OK;
    }

    public DialogResult Show(string messageText, string caption, DialogButton button)
    {
        return this.MessageBoxToDialogResult(MessageBox.Show(messageText, caption, this.DialogToMessageBoxButton(button)));
    }

    private DialogResult MessageBoxToDialogResult(MessageBoxResult messageBoxResult)
    {
        return (DialogResult)messageBoxResult;
    }

    private MessageBoxButton DialogToMessageBoxButton(DialogButton dialogButton)
    {
        return (MessageBoxButton)dialogButton;
    }

    #endregion
}

L’implementazione DialogService non solo implementa i metodi esposti dall’interfaccia ma utilizza due metodi privati per mappare i DialogResult e DialogButton sui corrispondenti MessageBoxResult e MessageBoxButton. In questo caso, la mappatura è banalmente un cast per come abbiamo definito gli enumerativi; in altri casi potrebbe essere più complessa.

L’utilizzo di questo servizio sarà possibile iniettandolo nel ViewModel attraverso il costruttore.

private IDialogService dialogService;

public ViewModel(IDialogService dialogService)
{
    this.dialogService = dialogService;
}

Infine, sarà utilizzabile direttamente in un qualsiasi metodo del ViewModel.

this.dialogService.Show("Messaggio da visualizzare");