Dialogo Modal en MVVM
Los Diálogos
Modales están entre los elementos más complejos de usar en el patrón MVVM
principalmente por la necesidad de separación de ocupaciones que se debe de
cumplir.
Nuestro siguiente
paso será crear la Vista, como se vio en la imagen superior en el XAML,
enlazaremos nuestra Vista con el ViewModel:
Y por último en el Code-BeHind completaremos el enlace:
Suerte!
Codigo Fuente: Aqui
Ciertamente se
puede manejar de una manera fácil el manejo de los Diálogos Modales desde la
vista y en el caso que deseemos hacer la llamada desde el ViewModel, podemos
usar eventos, pero ciertamente no es lo recomendable.
Para solucionar
el problema se tiene las siguientes opciones:
-
Usar
el patrón Mediador
-
Implementar
el dialogo como un servicio
En el presente
post voy a usar la segunda opción pero omitiendo más que todo el uso del
Inversor de Control, ciertamente no es una solución al 100% completa por que se
genera tiene un ratio mayor de acoplabilidad, pero hay que tomar en cuenta que en
la mayoría de los proyectos no es primordial tal característica y la inversión de
tiempo requerida (más que todo en proyectos que poseen mucho código legado o
que han sido desarrollados sin tomar en cuenta MVVM y se desea migrar al patrón)
es por demás alta; en otras palabras la relación costo - beneficio no es la óptima.
El proyecto que
vamos a crear es sencillo, es un formulario con una TextBox y un botón,
pulsando el botón se abrirá un dialogo para guardar en un archivo de texto el
contenido del TextBox:
De tal manera que
primero vamos a crear el ViewModel, donde definiremos una propiedad que se
enlace con el TextBox que será del tipo String, luego crearemos un comando que
se encargue de escuchar el evento de clic sobre el botón:
private string _text; public string Text { get { return _text; } set { _text = value; NotifyPropertyChanged( ( ) => this.Text ); } } #region SaveText Command public DelegateCommand SaveTextCommand { get; private set; } void SaveText_Execute( object parameters ) { } bool SaveText_CanExecute( object parameters ) { return true; } #endregion
No hay que
olvidar que nuestro ViewModel debe implementar la interface “INotifyPropertyChanged”:
#region INotifyPropertyChanged Implementation public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged( string propertyName ) { if ( this.PropertyChanged != null ) this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) ); } public void NotifyPropertyChanged( Expression<Func<object>> property ) { MemberExpression memberExpression; if ( property.Body is UnaryExpression ) memberExpression = ( property.Body as UnaryExpression ).Operand as MemberExpression; else memberExpression = property.Body as MemberExpression; if ( memberExpression == null ) Debug.Assert( false, "It must not happen" ); var propertyInfo = memberExpression.Member as PropertyInfo; if ( propertyInfo == null ) Debug.Assert( false, "It must not happen" ); this.NotifyPropertyChanged( propertyInfo.Name ); } #endregion
<Button Content="Save in a File" Height="52" HorizontalAlignment="Left" Margin="12,115,0,0" Name="btnSave" VerticalAlignment="Top" Width="306" Command="{Binding SaveTextCommand}" /> <TextBox Height="90" HorizontalAlignment="Left" Margin="68,19,0,0" Name="txtText" VerticalAlignment="Top" Width="250" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Text="{Binding Text}" /> <Label Content="Text:" Height="28" HorizontalAlignment="Left" Margin="12,19,0,0" Name="lblText" VerticalAlignment="Top" />
Y por último en el Code-BeHind completaremos el enlace:
private ViewModel viewModel; public MainWindow( ) { InitializeComponent( ); viewModel = new ViewModel( ); this.DataContext = viewModel; }
Ya con la aplicación
montada, procederemos a crear el servicio del Dialogo Modal, para lo que
crearemos una Interface denominada “IModalDialogService” que será como sigue:
public interface IModalDialogService { string Show( string fileExportName, string message, string filter = "All files (*.*)|*.*", bool restoreDirectory = true ); }
El siguiente paso
será crear la implementación de la Interface, creando una clase que lo
implemente, para nuestro caso la llamaremos “ModalDialogService” que será como
sigue:
public class ModalDialogService : IModalDialogService { private static SaveFileDialog saveDialog = new SaveFileDialog( ); private bool WriteFile( string fileName, string message ) { try { System.IO.File.WriteAllText( fileName, message ); return true; } catch ( UnauthorizedAccessException e ) { MessageBox.Show( e.Message, "Unauthorized Access Exception", MessageBoxButton.OK, MessageBoxImage.Error ); return false; } catch ( IOException e ) { MessageBox.Show( e.Message, "I/O Exception", MessageBoxButton.OK, MessageBoxImage.Error ); return false; } } public string Show( string fileExportName, string message, string filter = "All files (*.*)|*.*", bool restoreDirectory = true ) { string fileName = string.Empty; saveDialog.FileName = fileExportName; saveDialog.Filter = filter; saveDialog.RestoreDirectory = restoreDirectory; bool? dialogResult = saveDialog.ShowDialog( ); if ( dialogResult == true ) fileName = saveDialog.FileName; if ( fileName == string.Empty ) return ""; WriteFile( fileName, message ); return fileName; } }
Ahora analicemos
un poco del código que acabamos de escribir; lo primero a ponerse a pensar es porque
hemos creado una interface cuando podíamos haber creado de plano solo la clase
que maneje el dialogo, y la respuesta es que al crear una interface obtenemos
la flexibilidad necesaria para poder crear más de un tipo de dialogo fácilmente
que pueda ser usado a lo largo de toda
la aplicación disminuyendo la acoplacion entre componentes , además es una previsión para el momento que deseemos
usar un Inversor de Control.
El siguiente
lugar a analizar es en la clase que implementa la interface, donde se realizan
las acciones de crear el SaveFileDialog, establecer sus opciones básicas y
realizar la acción de escribir el archivo de texto en disco.
Con el servicio
de Dialogo listo, procedemos a crear el dialogo en el ViewModel, para lo cual
vamos a agregar las siguientes líneas de código al ViewModel:
private readonly IModalDialogService messageBoxService; ////// Constructor /// public ViewModel( ) { messageBoxService = new ModalDialogService( ); SaveTextCommand = new DelegateCommand( SaveText_Execute, SaveText_CanExecute ); }
Por ultimo
agregamos la llamada al método show en el método SaveText_Execute de la
siguiente manera:
this.messageBoxService.Show( "TestFileName", this.Text, "Text files (*.txt)|*.txt;|All files (*.*)|*.*" );
Ahora si lanzamos
la aplicación podremos ver cómo funciona:
Codigo Fuente: Aqui
Comentarios
Publicar un comentario