WPF MVVM关闭窗口

时间:2017-11-25 05:00:00

标签: c# wpf windows mvvm

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

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

在WindowOPHome窗口打开时,一切正常,登录窗口关闭。当我尝试关闭WindowOPHome窗口并使用类似于Login Window / WindowOPHome操作的按钮单击打开WindowMainAdmin窗口时,WindowMainAdmin窗口会在一瞬间打开,然后在WindowOPHome永远不会出现时消失。以下是关闭WindowOPHome并打开WindowMainAdmin的代码:

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

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

4 个答案:

答案 0 :(得分:4)

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

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

按钮xaml中的视图:

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

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

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;
    }  
}

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

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

答案 1 :(得分:1)

我认为在创建管理员窗口时,程序会将您的管理员窗口视为当前主窗口并关闭它。为避免这种情况,您可以显式关闭所需的窗口。我建议实现一个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();

}

InputHandler:

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

答案 2 :(得分:1)

您可以使用几个辅助类

为此问题创建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");
        }
}

然后使用我们的助手类在View中绑定它。

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

答案 3 :(得分:0)

所有这些都是很好的解决方案!我选择了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;
            }
        }

    }