在 WPF 的 xaml 视图中打开另一个窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20987282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Open another window in xaml view in WPF
提问by Rahul W
I am new to Wpf and following the MVVM pattern to design my application. I have a ViewModel and an View. By the design, my View knows about my ViewModel and the reverse is not. If i want to open another window upon click of a button, i could use a command and when user clicks, that command will be routed to my ViewModel.
我是 Wpf 的新手,并遵循 MVVM 模式来设计我的应用程序。我有一个 ViewModel 和一个视图。根据设计,我的 View 知道我的 ViewModel,反之则不然。如果我想在单击按钮时打开另一个窗口,我可以使用一个命令,当用户单击时,该命令将被路由到我的 ViewModel。
But how would i create a window that will have it's own view and ViewModel. I am kind of confused in this. I want to invoke the new window from Xaml itself as my ViewModel does not know about the another view and probably it's viewmodel.
但是我将如何创建一个具有自己的视图和 ViewModel 的窗口。我对此有些困惑。我想从 Xaml 本身调用新窗口,因为我的 ViewModel 不知道另一个视图,可能它是视图模型。
To keep it simple,
为了简单起见,
View1 -> (bound to) ViewModel1
View1 -> Button1.Click -> Command(bound to) ViewModel1
---- how to open View2 -> (bound to) ViewModel2------
Show View2.
Thanks
谢谢
采纳答案by Xcalibur37
I would just call Showfrom the code-behind of View 1 to open View 2. The ViewModel from View 1 should not be involved.
我只是从视图 1 的代码隐藏中调用Show来打开视图 2。不应涉及来自视图 1 的 ViewModel。
Like this:
像这样:
private void Button_Click(object sender, RoutedEventArgs e)
{
new View2().Show();
}
Your next thought might be "isn't this violating MVVM?" No, I wouldn't say so. The ViewModel should not have any direct control of UI elements if it is to be considered a clean implementation of MVVM. If you want something in the ViewModel to trigger the Window to open you can always use events or a 3rd party library like Caliburn to easily implement this without worrying about coupling.
你的下一个想法可能是“这不是违反了 MVVM 吗?” 不,我不会这么说。如果要认为 ViewModel 是 MVVM 的干净实现,则它不应直接控制 UI 元素。如果您希望 ViewModel 中的某些内容触发 Window 打开,您可以随时使用事件或像 Caliburn 这样的 3rd 方库来轻松实现这一点,而无需担心耦合。
回答by Thilina H
This is what i suggest to do that.because of there are no dependancy with view in another view model .simply you can write a dialog services to open any of view as popup(window).
normaly Show()method use the System.Windowsdependancy so better to use as service and then we can Unit test our application.
这就是我建议这样做的。因为在另一个视图模型中没有与视图的依赖关系。只需编写一个对话框服务来打开任何视图作为弹出窗口(窗口)。正常Show()方法使用System.Windows依赖关系更好地用作服务,然后我们可以对我们的应用程序进行单元测试。
public interface IDialogService
{
BaseViewModel ShowTitleDialog(BaseViewModel viewModel, UserControl view, string windowTitle);
}
public class DialogService : IDialogService
{
public BaseViewModel ShowTitleDialog(BaseViewModel viewModel, UserControl view, string windowTitle)
{
if (view == null && viewModel == null)
{
throw new ArgumentNullException("view is null");
}
RegisterTemplate(viewModel.GetType(), view.GetType());
return ShowTitleDialog(viewModel, windowTitle);
}
private void RegisterTemplate(Type viewModelType, Type viewType)
{
const string xamlTemplate = "<DataTemplate DataType=\"{{x:Type vm:{0}}}\"><v:{1} /></DataTemplate>";
var xaml = String.Format(System.Globalization.CultureInfo.InvariantCulture, xamlTemplate, viewModelType.Name, viewType.Name, viewModelType.Namespace, viewType.Namespace);
var context = new ParserContext();
context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
context.XamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace, viewModelType.Assembly.FullName);
context.XamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace, viewType.Assembly.FullName);
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
context.XmlnsDictionary.Add("vm", "vm");
context.XmlnsDictionary.Add("v", "v");
var template = (DataTemplate)System.Windows.Markup.XamlReader.Parse(xaml, context);
var key = template.DataTemplateKey;
Application.Current.Resources[key] = template;
}
public BaseViewModel ShowTitleDialog(BaseViewModel viewModel, string windowTitle, bool isEnableScrollBars = false)
{
Window window = new Window();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
ContentControl contentControl = new ContentControl();
contentControl.Content = viewModel;
if (!isEnableScrollBars)
{
window.Content = contentControl;
window.SizeToContent = SizeToContent.WidthAndHeight; window.SizeToContent = SizeToContent.WidthAndHeight;
}
else
{
ScrollViewer scrollViewver = new ScrollViewer();
scrollViewver.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
scrollViewver.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
scrollViewver.Content = contentControl;
window.Height = 600;
window.MaxHeight = 600;
window.Content = scrollViewver;
}
window.Title = windowTitle;
window.WindowStyle = WindowStyle.None;
window.Owner = Application.Current.Windows.OfType<System.Windows.Window>().FirstOrDefault(x => x.IsMouseOver);
window.ShowInTaskbar = false;
window.ShowDialog();
return viewModel;
}
}
Usage..
用法..
class TestAViewModel
{
public void ClickEvent()
{
TestBViewModel viewModel = new TestBViewModel();
viewModel.ShowThisView();
}
}
class TestBViewModel
{
public void ShowThisView()
{
TestBViewModel viewModel = new TestBViewModel();
TestBView view = new TestBView();
view.DataContext = viewModel;
IDialogService dialogCheckIn = new DialogService();
dialogCheckIn.ShowTitleDialog(viewModel, view, "Title");
}
}

