【问题标题】:WPF MVVM Close WindowWPF MVVM 关闭窗口
【发布时间】:2017-11-25 05:00:00
【问题描述】:

我使用 MVVM 创建了一个 WPF 应用程序,但在关闭/打开窗口时遇到了困难。在我的登录窗口上,我使用以下方法关闭登录窗口并单击按钮打开 WindowOPHome 窗口:

            WindowOPHome dashboard = new WindowOPHome();
            dashboard.Show();
            Application.Current.MainWindow.Close();

一切正常,登录窗口关闭,同时 WindowOPHome 窗口打开。当我尝试关闭 WindowOPHome 窗口并通过单击类似于登录窗口/WindowOPHome 操作的按钮打开 WindowMainAdmin 窗口时,WindowMainAdmin 窗口会打开一瞬间然后消失,而 WindowOPHome 永远不会离开视线。以下是关闭WindowOPHome和打开WindowMainAdmin的代码:

        WindowMainAdmin dashboard = new WindowMainAdmin();
        dashboard.Show();
        Application.Current.MainWindow.Close();

任何帮助将不胜感激!如果您需要任何其他代码,请告诉我。非常感谢!

【问题讨论】:

    标签: c# wpf windows mvvm


    【解决方案1】:

    我建议您明确关闭要关闭的窗口,而不是假设它是当前主窗口。

    使用 MVVM 有很多不同的方法可以做到这一点,您可以使用附加行为或通过命令参数将窗口传递给视图模型,如下所示:

    在视图的按钮 xaml 中:

    CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
    

    在视图模型的命令执行方法中:

    if (parameter is System.Windows.Window)
    {
        WindowMainAdmin dashboard = new WindowMainAdmin();
        dashboard.Show();
        (parameter as System.Windows.Window).Close();
    }
    

    .
    或者,您可以迭代所有窗口,直到找到所需的窗口。

    foreach( Window window in Application.Current.Windows ) {
        if(window is WindowOPHome)
        {
            window.Close();
            break;
        }  
    }
    

    如果您需要打开多个窗口实例,您可能需要检查其他一些属性,而不仅仅是关闭该类型的第一个。

    您甚至可以将其调整为每个窗口类中的静态关闭方法。

    【讨论】:

    • 完美!这很简单,我可以适应未来的使用,就像你说的,当我需要保持其他窗口打开并选择我需要关闭的窗口时。谢谢!
    • 这是整个StackOverFlow中最简单可行的方案。谢谢@cjmurph
    【解决方案2】:

    我认为当您创建管理窗口时,程序会将您的管理窗口视为您当前的主窗口并关闭它。为避免这种情况,您可以显式关闭所需的窗口。我建议实施 MainViewModel 来管理所有窗口。此示例假设您只希望打开一个窗口。

    在视图中(任何窗口):

    private void OnClose(object sender, RoutedEventArgs e)
    {
        //ICommand Implemnation that informs MainViewModel of UserInput 
        //In this case, the command ShowOPHome is an Enum
        inputhandler.Execute(MyCommands.ShowOPHome);
    }
    

    在 ViewModel 中:

    BaseWindow dashboard;
    ....
    public void ShowWindow(MyCommands Param)
    {
        //Verify Parameter
        ....
        if(!(dashboard is null))
            dashboard.Close();
        switch(Param)
        {
            case MyCommands.ShowOPHome:
                dashboard = new WindowOPHome();
                break;
            case MyCommands.ShowMainAdmin:
                dashboard = new WindowMainAdmin();
                break;
        } 
        dashboard.Show();
    
    }
    

    输入处理程序:

    public class Inputhandler : ICommand
    {
        ...
        public class Execute(object Data)
        {
            ...
                mainViewModel.ShowWindow(MyCommands.ShowOPHome);
            ...
        }
        ...
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用几个帮助类创建一个 MVVM 纯解决方案来解决这个问题

      public static class ViewCloser
      {
          public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached(
              "DialogResult",
              typeof(bool?),
              typeof(ViewCloser),
              new PropertyMetadata(DialogResultChanged));
      
          private static void DialogResultChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
          {
              var view = target as Window;
      
              if (view == null)
                  return;
      
              if (view.IsModal())
                  view.DialogResult = args.NewValue as bool?;
              else
                  view.Close();
          }
      
          public static void SetDialogResult(Window target, bool? value)
          {
              target.SetValue(DialogResultProperty, value);
          }
      }
      
      
      public static class WindowExtender
      {
          public static bool IsModal(this Window window)
          {
              var fieldInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
              return fieldInfo != null && (bool)fieldInfo.GetValue(window);
          }
      }
      

      在应用程序中,首先在ViewModel中创建一个属性

      private bool? _viewClosed;
      
      public bool? ViewClosed
      {
          get { return _viewClosed; }
          set { 
                  _viewClosed = value);
                  RaisePropertyChanged("ViewClosed");
              }
      }
      

      然后使用我们的帮助类在视图中绑定到它。

      <Window x:Class="
              ...
              vhelpers:ViewCloser.DialogResult="{Binding ViewClosed}"
              ...
              >
      

      【讨论】:

        【解决方案4】:

        所有这些都是很好的解决方案!我选择了 cjmurph 的解决方案,因为它非常简单(对我的弱智而言),而且我可以很容易地调整它以备将来使用。请参阅下面的实现代码。再次感谢大家!

        XAML

        Command="{Binding BtnMainAdminPageGO}"
        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
        

        WindowOPMainViewModel

            private ICommand _btnMainAdminPage;
        
            public ICommand BtnMainAdminPageGO
            {
                get
                {
                    if (_btnMainAdminPage == null)
                    {
                        _btnMainAdminPage = new RelayCommand(param => this.BtnMainAdminPage(), null);
                    }
        
                    return _btnMainAdminPage;
                }
            }
        
            private void BtnMainAdminPage()
            {
                WindowMainAdmin dashboard = new WindowMainAdmin();
                dashboard.Show();
                foreach(Window window in Application.Current.Windows)
                {
                    if (window is WindowOPHome)
                    {
                        window.Close();
                        break;
                    }
                }
        
            }
        

        【讨论】:

        • 站长!你混淆了我给你的两个选项。将参数传递给您的命令执行方法,您不需要迭代 windows 集合。声明中继命令时,请执行以下操作: new RelayCommand(param => BtnMainAdminPage(param), null);然后将执行方法更改为私有 void BtnMainAdminPage(object param){ WindowMainAdmin dashboard = new WindowMainAdmin();仪表板.show(); if(param is System.windows.Window) (param as System.Windows.Window).Close();}
        猜你喜欢
        • 2020-09-04
        • 1970-01-01
        • 2016-09-04
        • 2015-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多