Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在WPF中使用MVVM从另一个视图打开一个视图_C#_Wpf_Xaml_Mvvm_Valueconverter - Fatal编程技术网

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

C# 如何在WPF中使用MVVM从另一个视图打开一个视图,c#,wpf,xaml,mvvm,valueconverter,C#,Wpf,Xaml,Mvvm,Valueconverter,我是MVVM的新手。很长一段时间以来,我一直无法得到这个问题的答案。我不知道这个问题是这么难还是我解释得不好。我有MainWindow.Xaml,它包含一个textblock和一个从textblock接收数据的按钮,现在当我按下一个按钮时,它应该会打开第二个名为tableView.Xaml的视图(我已经为它/Xaml创建了用户控件) 我现在有两个问题(请注意,我在回答时正在关注MVVM)? (1) 如何通过关闭当前打开的MainWindow.xaml表单(此按钮单击使用MVVM绑定),从按钮单击

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

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

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

我的新表单必须打开的按钮单击代码(通过关闭当前的MainWindow.xaml)在这里(因此我猜打开tableView.xaml的代码只能在这里的某个地方):

此stp必须转到tableView.xaml,并且必须呈现4个stackpanel,每个stackpanel包含textblock

1)您的确切要求仍然不清楚,这使得回答这个问题非常困难。您说要“关闭当前的MainWindow.xaml表单”,但似乎表明tableView是用户控件。您是否试图关闭MainWindow并用完全不同的窗口替换它?如果是这样,那有什么意义呢?如果原始主窗口正在关闭,为什么不更改该窗口的内容

2) 这是一个很重要的话题,您必须再次提供更多关于您正试图做什么的信息,但通常您使用数据模板。首先声明要创建的GUI元素的视图模型,以及包含这些元素列表的父VM:

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:

<ItemsControl ItemsSource="{Binding GuiItems}" Margin="10">

    <ItemsControl.Resources>

        <DataTemplate DataType="{x:Type local:TextBlockVM}">
            <TextBlock Text="This is a TextBlock" />
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:CheckBoxVM}">
            <CheckBox>This is a CheckBox</CheckBox>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:TextBoxVM}">
            <TextBox Width="100" HorizontalAlignment="Left"/>
        </DataTemplate>

    </ItemsControl.Resources>

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

</ItemsControl>

这是一个复选框
结果:


显然,这是一个非常简单的示例,只是为了说明总体思路,在现实世界的应用程序中,您还需要向视图模型添加字段,以指定文本和命令处理程序等。好的,首先,您应该定义应用程序的导航系统。它是主窗口还是子窗口?它是有书页的框架吗?是带标签的主窗口吗?然后创建将覆盖此逻辑的类

例如,要从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原则之一是可测试性。在运行时,将使用打开真实窗口的具体类,但在测试中,我可以轻松创建不会打开窗口的mock

通常,如果要从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:

<StackPanel>
    <TextBlock Text="Rows" />
    <TextBox Text="{Binding NumberOfRows}" />

    <TextBlock Text="Columns" />
    <TextBox Text="{Binding NumberOfColumns}" />

    <Button Content="Save" Click="Save_Click" />
</StackPanel>
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; }
    }
}

通常,应用程序中存在不应关闭的主WinOW。例如,导航系统,如带有框架的主窗口,承载Page1、Page2等,或打开子窗口和对话框的主窗口。我没有使用任何内置的MVVM库,如(MVVM light或Prism)。如何获取此“DialogOptions”和“IDialogService”?请编辑问题。为了我要做的,我也没有使用任何图书馆。我已经创建了自己的IDialogService接口和实现。基本上,它只是一个简单的类,根据指定的参数显示窗口。@DialoService,不是内置的吗?但它提供了未知的接口。。在代码中执行此操作时缺少库或引用。但请阅读编辑部分的代码,即使它适合我的scenaro?IDialogService是我自己的界面。在您的场景中,您可以定义IDialogService.SwitchWindows(..)方法请编辑问题。对于我试图做的事情,TableView.xaml缺失,请解释在何处编写c#代码以生成GUI,该GUI将呈现给TableView.xaml。以及如何编写tableView.xaml,使其能够呈现通过c#代码传递给它的GUI?我无法为您编写整个应用程序。问题是关于打开窗口和传递参数。视图生成可以在TableView.xaml.cs中完成,也可以通过将datagring等控件绑定到viewmodel来完成。如果你不知道如何回答,就提出新问题。
<StackPanel>
    <TextBlock Text="Rows" />
    <TextBox Text="{Binding NumberOfRows}" />

    <TextBlock Text="Columns" />
    <TextBox Text="{Binding NumberOfColumns}" />

    <Button Content="Save" Click="Save_Click" />
</StackPanel>
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();
    }
}
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; }
    }
}