mvvm - UWP ContentDialog Invocation
modal-dialog winrt-xaml (2)
Estoy usando UWP y Template 10 para construir una aplicación GUI siguiendo el patrón MVVM. Como parte de la aplicación, necesito invocar un cuadro de diálogo de contenido presionando el botón en la Página principal. Así que se creó ContentDialog por separado en un archivo .xaml independiente para tal fin:
<ContentDialog
x:Class="UWP1.Views.Speech"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWP1.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Dictate"
PrimaryButtonText="Accept"
SecondaryButtonText="Cancel"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Button Margin="15" Content="Dictate" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch"/>
<Button Margin="15" Content="Clear Text" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" Text="Tap ''Dictate'', and speak" FontSize="12" />
<TextBlock Margin="0 10 0 0" Grid.Row="2" Grid.ColumnSpan="2" Text="Message Dication" HorizontalAlignment="Center" FontSize="24" />
<ScrollViewer Grid.Row="3" Grid.ColumnSpan="2" Height="300">
<TextBox Margin="5 5 5 10" AcceptsReturn="True" />
</ScrollViewer>
</Grid>
</ContentDialog>
¿Cuál es la forma correcta de abrir / invocarlo en mi página principal al presionar el botón (ya que necesito mantener la lógica separada para ver y ver el modelo)?
Cómo lo hago ahora:
Desde la Página principal invoco DictateCommand, que a su vez crea una instancia de ContentDialog y lo muestra:
<AppBarButton Grid.Column="1" Icon="Microphone" IsCompact="True" HorizontalAlignment="Right" Command="{Binding DictateCommand}"/>
public ICommand DictateCommand { get; set; }
public async void Dictate(object obj)
{
var contentDialog = new Speech();
await contentDialog.ShowAsync();
}
Parece una violación de patrón MVVM para mí. ¿Podrías por favor ayudarme a hacerlo de manera correcta?
EDITAR:
Implementé el servicio de diálogo y lo inserté en el modelo de vista principal. Sin embargo, tengo otro obstáculo. Para este cuadro de diálogo, creé un modelo de vista y una propiedad separados que encapsulan el valor del cuadro de texto del diálogo. Cuando presiono el botón ''aceptar'' en el cuadro de diálogo, necesito que este valor se refleje en mi vista principal. Por lo tanto, necesito pasar el valor del cuadro de texto del cuadro de diálogo del modelo de vista al modelo de vista principal. ¿Debo realizar otra inyección de dependencia para manejarlo?
La solución sugerida en MVVM es no crear una instancia de Speech Dialog
de Speech Dialog
directamente en ViewModel, crear SpeechDialogService
.
public interface ISpeechDialogService
{
Task ShowAsync();
}
public class SpeechDialogService : ISpeechDialogService
{
public async Task ShowAsync()
{
var contentDialog = new Speech();
await contentDialog.ShowAsync();
}
}
E inyecte este servicio en su constructor ViewModel
public class AbcViewModel
{
readonly ISpeechDialogService _dialog;
public AbcViewModel(ISpeechDialogService dialog)
{
_dialog = dialog;
}
public async void Dictate(object obj)
{
await _dialog.ShowAsync();
}
}
Tienes cuatro opciones.
ONE El primero es un servicio, al igual que @ Ask-too-much lo explica. De hecho, esta es una hermosa solución si te gusta.
Los beneficios de la primera solución son que es reutilizable. Si no está reutilizando esta interfaz de usuario, un servicio dedicado puede ser excesivo, para ser honesto.
DOS El segundo es un evento de modelo de vista. Es decir, su Página puede suscribirse al evento de su modelo de visualización (llamémoslo ShowContentDialog) y cuando el modelo de vista lo plantea, su Página maneja su presentación.
Los beneficios de este enfoque es que, al igual que el primer enfoque, está descargando el esfuerzo a otra clase. En este caso, está creando lo que probablemente sea una solución única sin necesidad de un servicio, una interfaz de servicio o inyección de ese servicio de alguna manera. Si no está esperando el resultado del evento, entonces creo que esto es una idea para el 99% de los problemas como el suyo.
TRES El tercer enfoque es usar un control diferente que pueda vincularse a una propiedad. Por ejemplo, dado que ya está utilizando la Plantilla 10, puede usar el control ModalDialog que tiene una propiedad IsModal. Una propiedad en su modelo de vista (llamémoslo IsModalVisible) se puede usar para controlar el diálogo sin conectarse a él.
La buena parte de esto es que puedes invocar el diálogo desde la lógica de tu modelo de vista, al igual que los primeros dos enfoques. Pero a diferencia del primero, no necesita un servicio. A diferencia del segundo, no necesita un controlador. Es la manera más "vinculante de datos" para hacerlo, y probablemente lo que yo haría.
CUATRO La cuarta forma de hacerlo es usar mensajes. La mensajería es el mecanismo que usa un modelo de vista para comunicarse con otro. En este caso, podría usar los mensajes de su modelo de visualización (con un mensaje que podríamos llamar ShowDialog) que se escuchan, no en otro modelo de vista, sino en su Página. Esto funcionaría bien, también.
La desventaja de esto es que necesita una solución de mensajería, pero es posible que ya la tenga. El lado positivo es que la lógica para manejar lo visual podría reubicarse en cualquier momento, ya que la mensajería es multidifundida para cualquiera que escuche.
Si fuera tú, consideraría primero el número 3, tal vez. Sin un poco más de comprensión de su escenario de aplicación, no estoy seguro. Sin embargo, eres un desarrollador. Las cuatro de esas opciones son buenas. Solo asegúrese de no caer en la tentación de pasar el UIElement a su modelo de visualización. Eso es inútil innecesario :)
¡La mejor de las suertes!