I am using UWP and Template 10 to build a GUI app by following MVVM pattern. As a part of application I need to invoke a content dialog by pressing button on Main Page. So separate ContentDialog was created in standalone .xaml file for that purpose:
<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>
What is the proper way to open/invoke it in my Main Page by pressing button (as I need to keep logic separated for view and viewmodel)?
How I do it now:
From Main Page I invoke DictateCommand, which in turn creates an instance of ContentDialog and shows it:
<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();
}
It looks like a MVVM pattern breach for me. Could you please help me to do it in a right way?
EDIT:
I have implemented dialog service and injected it in the main view model. However, I got another obstacle. For this dialog I created separate view model and property which encapsulates dialog text box value. When I press 'accept' button on the dialog - I need this value to be reflected on my Main View. So I need to pass dialog's text box value from dialog's view model to main view model. Should I perform another dependency injection to deal with it?
You have four options.
ONE The first is a service, just like @Ask-too-much explains. In fact, this is a beautiful solution if you like it.
TWO The second is a view-model event. That is to say, your Page can subscribe to your view-model's event (let's call it ShowContentDialog) and when it is raised by the view-model, your Page handle its presentation.
THREE The third approach is to use a different control that can be bound to a property. For example, since you are already using Template 10, you can use the ModalDialog control which has an IsModal property. A property in your view-model (let's call it IsModalVisible) can be used to control the dialog without coupling to it.
FOUR The fourth way to do it is to use messaging. Messaging is the mechanism one view-model uses to communicate with another. IN this case you could use messaging from your view-model (with a message we might call ShowDialog) that is listened for, not in another view-model, but in your Page. This would work fine, too.
If I were you, I would consider number 3 first, perhaps. Without a little more understanding of your app scenario, I can't be sure. You are a developer, though. All four of those options are good. Just be sure not to be tempted into passing the UIElement into your view-model. That's needless nastiness :)
Best of luck!
Suggested solution in MVVM is don't create instance of
Speech Dialog
directly in ViewModel, createSpeechDialogService
.And inject this service in your
ViewModel
constructor