【问题标题】:Open another window in View.cs在 View.cs 中打开另一个窗口
【发布时间】:2016-02-18 07:45:52
【问题描述】:

我有一个窗口,其中包含一个按钮AddParameter。 此 Button 有一个名为 Button_Click 的事件。

停留在 MVVM 模式中,是否允许使用简单的 Button_Click 打开一个新窗口?据我了解,View 的代码隐藏仍然算作 View:

private void Button_Click(object sender, RoutedEventArgs e) {
    AddParameterWindow addParamWindow = new AddParameterWindow();
    addParamWindow.Show();
}

用 ICommands 做这件事似乎没有必要,所以我想知道这是否仍然算作一个干净的 MVVM 解决方案。

【问题讨论】:

  • 好吧,如果您使用“Button_Click”,那么您已经不在 MVVM 中了。为什么不用客户端脚本打开窗口?
  • 你可以争论它。 MVVM 的原因是为了拆分逻辑和表示。如果您需要打开一个窗口或显示另一个视图,无论您选择哪种表示机制,我都会说它算作逻辑并且您违反了 MVVM 模式。如果它不是常见的逻辑,您可以使用您的版本。但我喜欢摆脱背后的每一点代码,并尝试使用单独的视图控制器、事件总线等来解决此类问题。但都有缺点
  • @Jurion 客户端脚本?这是wpf先生。
  • 人们可以对 MVVM 非常了解,但我发现没有实际理由不将事件处理程序放在代码隐藏中。我会避免放置您想要为其编写单元测试的任何逻辑,但是对于纯粹与视图相关的东西(如您在示例中所使用的),您并没有违反我定义的模式。不过,我会问,窗户是否是您真正需要的。如果您可以摆脱只是浮动或换出用户控件,您可能会发现它会带来更好的用户体验并且更适合 MVVM 模式。
  • @BoeseB 我明白了。所以基本上它是正确的,但不一定是一个很好的选择。谢谢。

标签: c# wpf mvvm


【解决方案1】:

我认为在 MVVM 中从另一个窗口打开一个窗口没有任何问题。 MVVM 模式是关于在 ViewModel(和底层模型)方面的关注点分离,以任何必要的方式表示,而无需了解有关 View 的任何信息(请参阅 here 以获得良好的介绍)。

但是,我认为您必须问问自己,制作新窗口是否真的是一个好功能。您是否看到应用程序产生另一个窗口,您喜欢这种行为吗?你有没有给弹出窗口一个看起来像 Windows 的想法,并且可以绑定到与它在逻辑上的 Window 或 UserControl 相同的 ViewModel 上?我个人避免实例化新的 Windows,因为我可以集中我想在每个视图中出现的东西,比如样式、超时计时器等。

【讨论】:

  • 从我的角度来看,ViewModel 应该控制程序流程,因此它应该负责打开新窗口。如果不是这样,为新窗口提供必要的信息(例如要显示的数据)会变得非常棘手。
  • @TimPohlmann 您可以让 ViewModel 负责控制程序流程和打开新视图,但它不需要知道视图。我特别喜欢实现this 之类的东西,这样我就可以“打开” ViewModels……在这种情况下,我不必担心要显示什么数据,因为 View 总是绑定到正确的 ViewModel跨度>
  • 通过链接的示例,您更改 ViewModel 属性,然后从后面的代码中打开另一个窗口?
  • 如果您的 ViewModel 绑定在当前窗口的 ContentControl 上,更改 ViewModel 属性应立即更改窗口内的视图
  • 没错,但有时我想打开一个新窗口;)
【解决方案2】:

您当然可以使用事件 Button_Click 来打开一个新窗口,但是现在 MVVM 已经没有了。 这对于 MVVM 来说可能不是正确的或好的做法,但这就是我的做法:

假设你有一个类似这样的 ViewModelBase.cs:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

我有一个扩展 ICommand 的 DelegateCommand.cs:

public class DelegateCommand : ICommand
{
    private readonly Action _action;

    public DelegateCommand(Action action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
        _action();
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

#pragma warning disable 67
    public event EventHandler CanExecuteChanged { add { } remove { } }
#pragma warning restore 67
}

现在在您的 SampleViewModel.cs 中:

public class SampleViewModel : ViewModelBase
{
    public SampleViewModel()
    {

    }

    public ICommand OpenWindowCommand
    {
        get { return new DelegateCommand(OpenSampleWindow); }
    }

    private void OpenSampleWindow()
    {
        var sampleWindow = new SampleWindow();
        sampleWindow.Show();
    }
}

现在在您的视图中,您现在可以将命令绑定到您的按钮:

<Button Command="{Binding OpenWindowCommand}"/>

【讨论】:

  • 很好的例子。我也是这样做的。对 jomsk1e 示例的一个小评论:OpenWindowCommand 应该返回一个私有 DelegateCommand 字段,该字段被实例化一次(通常在第一次被引用时在 OpenWindowCommand.get{ } 内)。现在,每次按下按钮时都会创建一个新命令。
  • 这行得通,但这不违反 MVVM 原则吗?在您的OpenSampleWindow() 中,您创建了一个我要打开的 Window 的新实例,但这是对视图的直接访问,不是吗?
  • 直到 OpenSampleWindow() 它仍然是 mvvm,之后 - 它不是。您必须将窗口创建过程委托给 viewmodel (click)。
  • @Sinatr 我在您的链接答案中看到的唯一问题是,您在哪里注入了该接口。如果您在另一个 VM 中创建 ViewModel 并实例化具体的 ProductionWindowFactory 类以传递给新创建的 VM,那么您只是将问题传递给了另一个 VM。我想说的是,您必须小心使用这种方法创建 VM 的位置。一个 DependencyInjection 框架可以解决这个问题,但我不会为了这个用途在我的项目中添加一个
  • MVVM 的关键是将您的 ViewModel 与 UI 框架隔离开来。如果你必须添加对 WPF 或 Winforms 库的引用,如果你把你的 ViewModels 放在他们自己的程序集中,那么你的 MVVM 实现中就会有一些异味
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 2018-05-11
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多