我创建了我的第一个MVVMLight项目,我有一个问题:
我有一个按钮,上面有一个命令。在不同的用例中,当命令执行时,我必须获取/向enduser提供信息,例如:
我知道我可以做MessageBox.Show/..。但在哪呢?因为关于关注点的分离,我想应该是在ViewModel中吗?那么,我应该在这里使用什么麦加主义呢?
我的ViewModel基本上是这样的:
public class MainViewModel : BaseViewModel
{
private static readonly Logger m_logger = LoggerProvider.GetLogger("MyPath.MainViewModel");
private ISerializationService m_serializationService;
public ICommand TrySaveCommand { get; set; }
//Lot of other fields here
public MainViewModel()
{
m_serializationService = ServiceLocator.Current.GetInstance<ISerializationService>();
TrySaveCommand = new RelayCommand(TrySave);
}
private void TrySave()
{
DispatcherHelper.RunAsync(() =>
{
//Here I need to get the path where I save on some condition
m_serializationService.SaveProject(pathIGotFromTheUser);
//Give a feedback that everything has been correctly saved(for test purpose, a MessageBox.Show() )
});
}
}那么,我应该如何从文件上的用户获取要保存的信息呢?(使用SaveFileDialog )并显示它已被正确保存(使用MessageBox.Show)
谢谢
发布于 2015-02-01 13:57:16
Laurent在他的mvvmlight库中引入了一个非常方便的助手类Messenger,您可以使用它在视图模型、视图或视图/视图之间发送和接收通知和/或信息。在这里它是如何工作的
Messenger.Default.Send<..>(..)视图模型广播一条消息,Messenger.Default.Register<>(..)),并根据该通知执行适当的逻辑(例如显示消息或对话框)。要将此应用于您的情况,您必须在代码后面添加一些与视图相关的逻辑,以显示DialogueBox和确认消息。MainWndow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
Messenger.Default.Register<NotificationMessage>(this, (m) =>
{
switch (m.Notification)
{
case "SaveFile":
var dlg = new SaveFileDialog();
if (dlg.ShowDialog() == true)
{
var filename = dlg.FileName;
Messenger.Default.Send<String>( filename,"FileSaved");
}
break;
case "WentWell":
MessageBox.Show("Everything went well Wohoo");
break;
}
});
}
}在这里,该视图将显示基于广播ed ViewModel通知的对话框或确认消息框。
在MainWindowViewModel中
public class MainViewModel : ViewModelBase
{
private static readonly Logger m_logger = LoggerProvider.GetLogger("MyPath.MainViewModel");
private ISerializationService m_serializationService;
private RelayCommand _trySaveCommand;
public RelayCommand TrySaveCommand
{
get
{
return _trySaveCommand
?? (_trySaveCommand = new RelayCommand(
() =>
{
Messenger.Default.Send(new NotificationMessage("SaveFile"));
}));
}
}
public MainViewModel()
{
m_serializationService = ServiceLocator.Current.GetInstance<ISerializationService>();
Messenger.Default.Register<string>(this, "FileSaved", (pathIGotFromTheUser) =>
{
m_serializationService.SaveProject(pathIGotFromTheUser);
//Give a feedback that everything has been correctly saved(for test purpose, a MessageBox.Show() )
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("WentWell"));
});
}与按钮或其他相关的TrySaveCommand将触发视图。
**在您说之前,我不认为您违反了任何mvvm规则,因为这样做,显示消息框或对话是与表示相关的逻辑,应该在解决方案的视图部分进行处理;通过发送消息的视图模型实际上不知道视图的任何想法,他只是做了一些工作并广播了一条状态消息,最后这里有一些关于Messenger类这里的深入信息。
发布于 2015-02-01 11:43:46
关于SoC的问题本质上有两个方面: 1.如何从视图模型(它是免费的)触发UI交互(例如显示消息框)。2.你如何区分你当前需求的不同化身,例如在一个地方,而不是在另一个地方显示一个确认。
第一个问题归结为“隐藏界面后面的UI交互”。其他评论者也提到过这个问题,所以我不想在这里详述。
关于第二个问题:您当然可以将实际的调用放到messagebox中(即相应的接口调用,但让我们保持简单),并使用一些条件来决定是否调用。通常,这种方法有两个可能的问题:-命令“增加权重”,因为它必须在每个上下文中运行,从而积累代码和逻辑依赖关系。-你的“显示确认”和其他东西的逻辑在其他情况下也可能有用,但你不能重复使用它。
解决这些问题的一个可能的答案是“命令链”。例如,有一个"ConfirmationCommand“(对象或方法),用于接收消息和委托或命令,用于后续活动。它显示一个消息框,并根据单击按钮调用一个委托或另一个委托。在一种情况下,您可以简单地使用您的SaveCommand,而在另一种情况下,您可以使用您的ConfirmationComand和附加到它的SaveCommand。通过这种方式,您可以从较小的命令链构建您的acuall命令逻辑,而这些命令又变得更加通用,不依赖于上下文,因此更可重用。当然还有更多,比如传递参数的问题,但是这应该足以让你对这个方法有一个大致的了解,
HIH,
发布于 2015-01-28 11:55:18
创建一个具有公共ShowMessage方法的"Dialog“类,该方法显示一个MessageBox。
然后,从该类中提取一个接口,并将其作为视图模型中的成员使用。使用依赖注入,您可以将它注入,甚至更好的是,让诸如统一这样的IOC容器将它注入您的视图模型。这样,对话服务将实例化消息框。如果要创建单元测试,则可以通过从单元测试实例化新的对话服务来模拟对话服务。
编辑
示例:
private RelayCommand<Window> doSomethingCommand;
public RelayCommand<Window> DoSomethingCommand
{
get
{
return doSomethingCommand
?? (doSomethingCommand= new RelayCommand<Window>(
window =>
{
dialogService.SaveFileDialog.ShowDialog(window);
// save the file
}));
}
}窗口参数应该在XAML中作为commandParameter绑定到Element窗口,如下所示:
<Button Content="" Command="{Binding DoSomethingCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=window, Mode=OneWay}"/>第二版编辑
下面是如何从UserControl绑定到窗口的方法
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"https://stackoverflow.com/questions/28105391
复制相似问题