我找到了一个使用MVVM Light向用户显示消息的小例子。我猜测它是如何使用MVVM Light的,它尊重MVVM模式。
背后的观察代码:
namespace DialogosPruebas
{
/// <summary>
/// Lógica de interacción para MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Messenger.Default.Register<DialogMessage>(
this,
msg =>
{
var result = MessageBox.Show(
msg.Content,
msg.Caption,
msg.Button);
// Send callback
msg.ProcessCallback(result);
});
}
}
}
而ViewModel
是:
using System;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
namespace DialogosPruebas.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// You can also use Blend to data bind with the tool's support.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
private const string Login = "abcd1234";
public RelayCommand<string> CheckLoginCommand
{
get;
private set;
}
/// <summary>
/// The <see cref="Message" /> property's name.
/// </summary>
public const string MessagePropertyName = "Message";
private string _message = "Login";
/// <summary>
/// Gets the Message property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string Message
{
get
{
return _message;
}
set
{
if (_message == value)
{
return;
}
_message = value;
RaisePropertyChanged(MessagePropertyName);
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
CheckLoginCommand = new RelayCommand<string>(CheckLogin);
}
private void CheckLogin(string text)
{
if (text == Login)
{
var message = new DialogMessage("Login confirmed, do you want to continue", DialogMessageCallback)
{
Button = MessageBoxButton.OKCancel,
Caption = "Continue?"
};
Messenger.Default.Send(message);
}
}
private void DialogMessageCallback(MessageBoxResult result)
{
if (result == MessageBoxResult.OK)
{
Message = "Continue";
}
else
{
Message = "Stop";
}
}
}
}
AXML:
<Window x:Class="DialogosPruebas.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}"/>
</Window.DataContext>
<Grid>
<StackPanel x:Name="LayoutRoot" Background="Black">
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding Message}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" Margin="0,10" />
<TextBox x:Name="LoginTextBox" TextWrapping="Wrap" Margin="10,0" FontSize="21.333" Text="Enter login">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<cmd:EventToCommand Command="{Binding CheckLoginCommand, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=LoginTextBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBlock TextWrapping="Wrap" Text="(Enter abcd1234 to trigger the message)" HorizontalAlignment="Center" Margin="0,10,0,0" FontSize="16" Foreground="White"/>
</StackPanel>
</Grid>
</Window>
嗯,我的疑问是,在视图背后的代码中我们使用MessageBox
而ViewModel
包含此代码:
var message = new DialogMessage("Login confirmed, do you want to continue", DialogMessageCallback)
{
Button = MessageBoxButton.OKCancel,
Caption = "Continue?"
};
Messenger.Default.Send(message);
这会向视图发送请求,然后向后面的代码发送请求,然后使用MessageBox
。
为什么这比直接在MessageBox
使用ViewModel
的此解决方案更好,如下所示:
private void CheckLogin(string text)
{
if (text == Login)
{
MessageBox.Show("Login correct");
}
}
有什么区别?在这两种情况下,我都使用MessageBox
,我必须等待用户的回复。
我已经读过在MessageBox
使用viewModel
并不是一个好主意,但我不知道在这种情况下有什么区别。
答案 0 :(得分:6)
我认为可能需要采用这种方法的两个原因是:
1 - 您的ViewModel需要进行单元测试。
提出模式对话框(例如MessageBox
)会导致单元测试中出现各种问题。解耦Messenger
方法是安全的,因为在单元测试中,没有人正在监听消息,或者有一个模拟的监听器只对所有面向用户的提示返回“是”。
2 - 您的ViewModel应该在其他平台上重复使用。
如果您仅针对Windows(WPF),请不要过于担心。
导致与UI完全分离的主要问题是,您是否会在其他平台中重复使用ViewModel。
例如,Android中没有MessageBox.Show()
,因此,如果您打算重用ViewModel的“应用程序逻辑”,则需要将该代码抽象出来并在每种情况下提供特定于平台的代码。
如果这些对您来说都不重要,那么IMO完全可以在ViewModel中提升MessageBox,以及其他特定于View的问题(例如Window关闭),考虑到MVVM所需的抽象,这些问题可能过于复杂,没有收获。
答案 1 :(得分:2)
不同之处在于,通过发送消息(DialogMessage),您的ViewModel会要求View显示消息。消息的实际显示方式取决于视图。在这种情况下,View将显示一个简单的MessageBox,但它可以使用UserControl来显示自定义对话框。
使用消息,ViewModel不需要知道消息将如何显示,因此它仍然与视图分离。