如何在WPF中使用MVVM从另一个视图打开一个视图

我是MVVM的新手。 很长一段时间以来,我无法得到这个问题的答案。 我不知道问题是否如此困难,或者我没有正确解释。 我有MainWindow.Xaml,它包含一个文本块和一个从textblock接收数据的按钮,现在当我按下一个按钮时,它应该打开第二个名为tableView.xaml的视图(我已经为它创建了用户控件/ Xaml)。

我现在有两个问题(请注意我在回答时关注MVVM)?

(1)如何通过关闭当前打开的MainWindow.xaml表单从按钮单击打开此视图“tableView.xaml”(此按钮单击是否使用MVVM绑定)?

这个新表单必须打开的按钮单击的代码(通过关闭当前的MainWindow.xaml)就在这里(所以我想打开tableView.xaml的代码必须只在这里的某处):

public void SaveExecuted() //some where here i have to open "tableView.Xaml" { System.Windows.MessageBox.Show(string.Format("Saved: {0} {1} ", DB_Col.DbName, DB_Col.NumTables)); } public ICommand SavePersonCommand { get { if (savePersonCommand == null) savePersonCommand = new DelegateCommand(new Action(SaveExecuted), new Func(SaveCanExecute)); return savePersonCommand; } } 

但是怎么做呢?

(2)“tableView.Xaml”必须包含GUI,它将根据前一个MainWindow.xaml在“保存按钮”上单击时收到的输入动态写入c#,并且必须将它们添加到tableView.Xaml中。 那么如何以及在何处编写C#代码以便这个c#代码生成的GUI将在tableView.Xaml上呈现?

简介:有人可以让我知道如何从Button单击打开tableView.Xaml以及如何在tableView.Xaml上追加/呈现GUI(我知道如何编写c#代码来生成GUI但是在哪里写代码如此它将在tableView.Xaml中呈现GUI,尊重MVVM规则)。

编辑:我觉得仍然亲爱的帮助者无法理解我想要做什么,所以请看更详细的信息:

我要做的是:我有MainWindow.xaml,它包含文本框“输入表格数”,它接收来自用户的输入(作为他想要创建的表的数量)。输入此输入后,用户将单击保存按钮。 现在保存按钮必须关闭MainWindow.xaml并启动新的usercontrol,即“tableView.xaml”。 假设他输入4并保存。 现在在新启动的tableView.xaml中,我必须显示文本框,它将收到“表的名称”,“列的Nmbr”,如果他为列数输入3,那么应该有3个文本框来接收每个的名称列和数据类型以及主键和保存按钮。

此GUI现在必须重复4次,因为在Mainwondow.xaml中,用户在启动时动态地在“Number of tables”选项中输入4。 因此,我们必须为“tableView.xaml”中的每个表条目重复此GUI 4次,这就是我在c#中编写用于GUI生成的代码的原因,并且在GUI生成之后,我将从C#代码获取的GUI呈现给tableView.xaml。 现在你明白了吗? 如果您知道使用MVVM执行此操作的任何其他方式,那么欢迎您给我一些示例。 通过使用C#代码动态生成GUI意味着我必须执行以下操作:

现在当我从MainWindow.xaml中的用户输入4作为4时,我在GUI下面重复4次(在一个大容器内循环)并将其渲染到tableView.Xaml(我在c#中这样做,因为我必须动态地重复它根据用户在MainWindow.xaml表单中的选择)。

 StackPanel stp = new StackPanel(); TextBlock txt1 = new TextBlock(); stp.Children.Add(txt1); 

这个stp必须转到tableView.xaml,并且必须渲染4个包含textblock的stackpanel。

1)你仍然不是很清楚你的确切要求,这使得回答这个问题变得非常困难。 你说你想“关闭当前的MainWindow.xaml表单”但你似乎表明你的tableView是一个UserControl。 您是否正在尝试关闭MainWindow并使用完全不同的窗口完全替换它? 如果是这样那么重点是什么? 如果原始MainWindow正在关闭,为什么不直接更改该窗口的内容?

2)这是一个很大的话题,你将不得不提供更多关于你正在尝试做什么的信息,但一般来说你使用DataTemplating。 首先声明要创建的GUI元素的视图模型,以及包含它们列表的父虚拟机:

 public abstract class GuiItem { } // base class public class TextBlockVM : GuiItem { } public class CheckBoxVM : GuiItem { } public class TextBoxVM : GuiItem { } public class CustomViewModel : ViewModelBase { private GuiItem[] _GuiItems = new GuiItem[] { new TextBlockVM{}, new CheckBoxVM{}, new TextBoxVM{} }; public GuiItem[] GuiItems { get { return this._GuiItems; } } } 

然后创建一个ItemsControl,将ItemsSource绑定到数组,指定要在其上绘制的面板类型,并包含指定如何在GUI中模拟每个VM的DataTemplates:

       This is a CheckBox            

结果:

在此处输入图像描述

显然这是一个非常简单的例子,只是为了展示一般的想法,在现实世界的应用程序中,你还要在视图模型中添加字段来指定文本和命令处理程序等

好的,首先,您应该定义应用程序的导航系统。 它是带有儿童窗户的主窗户吗? 是页面框架? 它是带标签的主窗口吗? 然后创建将涵盖此逻辑的类。

例如,要从viewmodel显示子窗口并将一些输入传递给它,您可以执行以下操作:

 public class MainWindowViewModel { private IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { _dialogService = dialogService; SaveCommand = new DelegateCommand(Save); } //implement PropertyChanged if needed public string SomeInput { get; set; } public DelegateCommand SaveCommand { get; private set; } private void Save() { var tableViewModel = new TableViewModel(); tableViewModel.SomeInput = this.SomeInput; _dialogService.ShowModal(new DialogOptions { Title = "Table view", Content = tableViewModel }); } } 

如果您需要导航到另一个页面而不是打开新窗口,则可以轻松创建NavigationService而不是DialogService。 想法是一样的。

为什么我不直接在viewmodel中创建子窗口? 因为窗口是视图,我想保持关注点的分离。

为什么我使用IDialogService而不是具体的类? MVVM原则之一是可测试性。 在运行时,将使用打开真实窗口的具体类,但在测试中我可以轻松创建模拟,不会打开窗口。

通常,如果要从viewmodel关闭窗口,则在viewmodel中创建并调用一些事件(例如CloseRequested),窗口应该监听事件:

 public class MainWindowViewModel { public event EventHandler CloseRequested; private void Close() { var closeRequested = CloseRequested; if (closeRequested != null) closeRequested (this, EventArgs.Empty); } } //mainwinow.xaml.cs public MainWindow() { InitializeComponent(); var viewModel = new MainWindowViewModel(); viewModel.CloseRequested += (sender, args) => this.Close(); DataContext = viewModel; } 

我相信纯粹的MVVM对你来说有点过于困难和过度设计。 你可能无法充分利用它。

让我们尝试通过结合MVVM和经典方法来简化它:

创建MainWindow.xaml,MainWindowViewModel,TableView.xaml和TableViewModel:

 public class MainWindowViewModel { //implement INotifyPropertyChanged if needed public int NumberOfRows { get; set; } public int NumberOfColumns { get; set; } public void Save() { //do something if needed } } 

MainWindow.xaml:

        

MainWindow.xaml.cs:

 public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainWindowViewModel(); } MainWindowViewModel ViewModel { get { return (MainWindowViewModel)DataContext; } } private void Save_Click(object sender, RoutedEventArgs e) { ViewModel.Save(); var tableViewWindow = new TableView(ViewModel.NumberOfRows, ViewModel.NumberOfColumns); this.Close(); tableViewWindow.Show(); } } 

TableView.xaml.cs

 public partial class TableView: Window { public TableView(int rows, int colums) { InitializeComponent(); DataContext = new TableViewModel(); //do whatever needed with rows and columns parameters. //You will probably need then in TableViewModel } TableViewModel ViewModel { get { return (TableViewModel )DataContext; } } }