如何在WPF中从ViewModel设置窗口所有者

3

我该如何将从ViewModel声明、初始化和打开的窗口设置为所有者?

以下是代码:

public class ViewModel : INotifyPropertyChanged

{
  // declaration
  static nextWindow nw;
  ...

  public ICommand OpenNextWindow { get { return new RelayCommand(OpenNextWindowExecute, CanOpenNextWindowExecute); } }

  bool CanOpenNextWindowExecute(object parameter)
  {
      return true;
  }

  void OpenNextWindowExecute(object parameter)
  {
      nw = new nextWindow();
      nw.WindowStartupLocation = WindowStartupLocation.CenterScreen;
      // Set this window as owner before showing it...
      nw.Show();
  }
 }

在 nextWindow 的代码后台文件中,我可以使用以下代码将 nextWindow 设置为所有者:
nw.Owner = this;

我该如何从视图模型实现它?

你可以尝试将它绑定到 ViewModel 中的一个窗口,然后从 VM 中将窗口设置为相关内容。但是通常情况下,你不希望 ViewModel 知道你的 View,所以我不确定这是否是一种干净的方式。 - Belterius
3个回答

4

说实话,我不会在ViewModel中处理与显示窗口相关的任何内容。但你可以发送消息(例如使用MVVMLight的Messenger服务)到View,然后在View中进行显示并设置所有者。


2
MVVM的整个思想在于你需要一个干净的视图和业务逻辑之间的分离,这样可以实现更好的维护、可扩展性、测试等。因此,你的视图模型几乎总是不知道任何视图的存在。
因此,利用一个信使服务来监听视图或某些视图处理程序,然后决定是否要处理消息。这样留给视图处理程序来决定调用哪个其他视图或显示什么消息框。
有很多选择,但正如@Oyiwai所说,MVVMLight的Messenger服务快速且易于使用。
在你的Package Manager Console中运行install-package MvvmLightLibs。MvvmLightLibs还有一个额外的好处是它已经有了INotifyPropertyChanged的实现,我看到你已经实现了它。
请注意,这只是一个快速的例子。我不建议像我这样使用case语句硬编码视图名称。
创建一个WindowMessage类...
public class RaiseWindowMessage
{
    public string WindowName { get; set; }
    public bool ShowAsDialog { get; set; }
}

在你的视图模型中

public class ViewModel : ViewModelBase
{
    public RelayCommand<string> RaiseWindow => new RelayCommand<string>(raiseWindow, canRaiseWindow);

    private bool canRaiseWindow(string nextWindowName)
    {
        // some logic
        return true;
    }

    private void raiseWindow(string nextWindowName)
    {
        RaiseWindowMessage message = new RaiseWindowMessage();
        message.WindowName = nextWindowName;
        message.ShowAsDialog = true;

        MessengerInstance.Send<RaiseWindowMessage>(message);
    }
}

在你的视图或者最好是在某个视图处理器类中...
public class ViewHandler
{
    public ViewHandler()
    {
        Messenger.Default.Register<RaiseWindowMessage>(this, raiseNextWindow);
    }        

    private void raiseNextWindow(RaiseWindowMessage obj)
    {
        // determine which window to raise and show it
        switch (obj.WindowName)
        {
            case "NextWindow":
                NextWindow view = new NextWindow();
                if (obj.ShowAsDialog)
                    view.ShowDialog();
                else
                    view.Show();
                break;
            // some other case here...
            default:
                break;
        }
    }
}

我不知道ViewHandler在哪里,你会在哪里实例化它? - IngoB
我猜这取决于你的应用程序布局。你可能会在主视图的cs类中实例化它。如果你想的话,你可以在那里注入它。只要确保不要在每个视图中都包含它,否则它可能会尝试弹出几个窗口,这取决于你如何注入它。 - Bracher

-4
nw.Owner = Application.Current.MainWindow;

欢迎来到 Stack Overflow。请在您的回答中添加更多细节。您可以在此处找到撰写良好答案的指南: https://stackoverflow.com/help/how-to-answer - SENya
从ViewModel访问视图(对话框)在MVVM中是不可行的,因此这不是符合MVVM模式的解决方案。 - Kux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接