UWP ContentDialog Invocation
Я использую UWP и Template 10 для создания приложения с графическим интерфейсом, следуя шаблону MVVM. Как часть приложения мне нужно вызвать диалог содержимого, нажав кнопку на главной странице. Поэтому для этой цели был создан отдельный ContentDialog в отдельном файле.xaml:
<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>
Как правильно открыть / вызвать его на моей главной странице, нажав кнопку (так как мне нужно разделить логику для представления и модели представления)?
Как я это делаю сейчас:
На главной странице я вызываю DictateCommand, которая, в свою очередь, создает экземпляр ContentDialog и показывает его:
<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();
}
Похоже, нарушение шаблона MVVM для меня. Не могли бы вы помочь мне сделать это правильно?
РЕДАКТИРОВАТЬ:
Я реализовал сервис диалога и внедрил его в модель основного вида. Однако я получил еще одно препятствие. Для этого диалога я создал отдельную модель представления и свойство, которое инкапсулирует значение текстового поля диалога. Когда я нажимаю кнопку "принять" в диалоговом окне - мне нужно, чтобы это значение было отражено в моем главном окне. Поэтому мне нужно передать значение текстового поля диалога из модели вида диалога в модель основного вида. Должен ли я выполнить еще одно внедрение зависимости, чтобы справиться с этим?
2 ответа
У вас есть четыре варианта.
ОДИН Первый - это сервис, как объясняет @Ask-too-much. На самом деле, это прекрасное решение, если вам это нравится.
Преимущества первого решения заключаются в том, что его можно использовать повторно. Если вы не используете этот пользовательский интерфейс повторно, то, честно говоря, выделенная служба может оказаться излишней.
ВТОРОЕ Второе - это модельное событие. То есть ваша страница может подписаться на событие вашей модели представления (назовем его ShowContentDialog), и когда оно вызывается моделью представления, ваша страница обрабатывает его представление.
Преимущества этого подхода в том, что, как и в первом подходе, вы перекладываете усилия на другой класс. В этом случае вы создаете одноразовое решение, не требуя службы, интерфейса службы или внедрения этой службы каким-либо образом. Если вы не ждете результатов мероприятия, то я думаю, что это идея для 99% вопросов, подобных вашей.
Третий Третий подход заключается в использовании другого элемента управления, который может быть привязан к свойству. Например, поскольку вы уже используете Шаблон 10, вы можете использовать элемент управления ModalDialog, который имеет свойство IsModal. Свойство в вашей view-модели (назовем его IsModalVisible) можно использовать для управления диалогом без привязки к нему.
Хорошая часть этого в том, что вы получаете возможность вызывать диалог из логики вашей модели представления, как и первые два подхода. Но в отличие от первого, вам не нужен сервис. В отличие от второго, вам не нужен обработчик. Это самый "привязанный к данным" способ сделать это, и, вероятно, то, что я бы сделал.
ЧЕТВЕРТЫЙ Четвертый способ сделать это - использовать обмен сообщениями. Обмен сообщениями - это механизм, который одна модель представления использует для связи с другим. В этом случае вы можете использовать сообщения из вашей модели представления (с сообщением, которое мы могли бы назвать ShowDialog), который прослушивается не в другой модели представления, а на вашей странице. Это тоже будет работать нормально.
Недостатком является то, что вам нужно решение для обмена сообщениями, но у вас уже может быть это. Положительным моментом является то, что логика обработки визуала может быть перемещена в любое время, так как обмен сообщениями многоадресно передается любому слушающему.
Если бы я был тобой, я бы сначала рассмотрел номер 3, возможно. Без большего понимания сценария вашего приложения, я не могу быть уверен. Вы разработчик, хотя. Все четыре варианта хороши. Только будьте уверены, что вы не захотите передать UIElement в вашу модель представления. Это ненужная гадость:)
Удачи!
Предлагаемое решение в MVVM - не создавать экземпляр Speech Dialog
непосредственно в ViewModel, создать SpeechDialogService
,
public interface ISpeechDialogService
{
Task ShowAsync();
}
public class SpeechDialogService : ISpeechDialogService
{
public async Task ShowAsync()
{
var contentDialog = new Speech();
await contentDialog.ShowAsync();
}
}
И внедрить этот сервис в свой ViewModel
конструктор
public class AbcViewModel
{
readonly ISpeechDialogService _dialog;
public AbcViewModel(ISpeechDialogService dialog)
{
_dialog = dialog;
}
public async void Dictate(object obj)
{
await _dialog.ShowAsync();
}
}