我正在使用UWP和Template 10通过遵循MVVM模式来构建GUI应用程序。作为应用程序的一部分,我需要通过按主页面上的按钮来调用内容对话框。因此,为了这个目的,在独立的.xaml文件中创建了单独的ContentDialog:
<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模式。能帮助我以正确的方式做到吗?
编辑:
我已经实现了对话服务并将其注入主视图模型中。 但是,我遇到了另一个障碍。对于此对话框,我创建了单独的视图模型和属性,它封装了对话框文本框值。当我按下对话框上的“接受”按钮时 - 我需要将此值反映在我的主视图上。所以我需要将对话框的视图模型中的对话框文本框值传递给主视图模型。我应该执行另一个依赖注入来处理它吗?
答案 0 :(得分:11)
您有四种选择。
ONE 第一个是服务,就像@ Ask-too-much-explain。事实上,如果你喜欢它,这是一个很好的解决方案。
第一种解决方案的好处是它可以重复使用。如果您没有重复使用此UI,说实话,专用服务可能会过度。
TWO 第二个是视图模型事件。也就是说,您的Page可以订阅您的视图模型的事件(让我们称之为ShowContentDialog),当它被视图模型引发时,您的Page会处理它的演示文稿。
这种方法的好处在于,就像第一种方法一样,您将努力转移到另一个类。在这种情况下,您正在创建可能是一次性解决方案而无需服务,服务接口或以某种方式注入该服务。如果你不等待事件的结果,那么我认为这是99%像你这样的问题的想法。
THREE 第三种方法是使用可以绑定到属性的不同控件。例如,由于您已在使用模板10,因此可以使用具有IsModal属性的ModalDialog控件。视图模型中的属性(让我们称之为IsModalVisible)可用于控制对话框而不与其耦合。
这很好的部分是你可以从视图模型的逻辑中调用对话框,就像前两种方法一样。但与第一个不同,您不需要服务。与第二个不同,您不需要处理程序。这是最“数据绑定”的方式,而且可能是我要做的。
四第四种方法是使用消息传递。消息传递是视图模型用于与另一个视图模型通信的机制。在这种情况下,您可以使用来自您的视图模型(我们可能称之为ShowDialog的消息)的消息,而不是在另一个视图模型中,而是在您的Page中。这也可以。
缺点是你需要一个消息传递解决方案,但你可能已经拥有了它。从好的方面来说,处理视觉的逻辑可以随时重新定位,因为Messaging会被任何人监听。
如果我是你,我可能会先考虑3号。如果不了解您的应用场景,我无法确定。不过,您是开发人员。所有这四个选项都很好。请确保不要试图将UIElement传递给您的视图模型。这是不必要的肮脏:)
祝你好运!
答案 1 :(得分:5)
MVVM中的建议解决方案是不要直接在ViewModel中创建Speech Dialog
的实例,创建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();
}
}