简体   繁体   中英

WPF MVVM Close Window

I have created a WPF App using MVVM and I'm having difficulty with closing/opening windows. On my Login Window, I use the following method to close the Login Window and Open the WindowOPHome Window with a button click:

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

Everything works fine and the Login Window closes while the WindowOPHome Window opens. When I try to close the WindowOPHome Window and open the WindowMainAdmin Window with a button click similar to the Login Window/WindowOPHome action, the WindowMainAdmin Window opens for a split second then disappears while the WindowOPHome never leaves sight. Following is code for closing WindowOPHome and opening WindowMainAdmin:

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

Any help would be greatly appreciated! Please let me know if there any other pieces of code you need. Thank you so much!

I'd suggest you explicitly close the window you want to close rather than assuming it's the current main window.

With MVVM there are lots of different ways to do it, you can use an attached behavior or pass the window to the view model via the command parameter like this:

in the button xaml for the view:

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

in the command execute method in the view model:

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

.
Alternatively, you could iterate all windows until you find the one you want.

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

You might want to check on some other property other than just closing the first one of that type if you need to have more than one instance of a window open.

You could even adapt that to be a static close method within each window class.

I think when you create the Admin Window, the program considers your Admin Window to be your Current Main Window and closes it. To avoid this, you can explicitly close the window you want. I suggest implementing a MainViewModel to manage all your windows. This example assumes you only want one window to be open.

In View (Any Window):

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

In 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);
        ...
    }
    ...
}

You can create a MVVM pure solution to this issue using a couple of helper classes

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

In the application, first create a property in the ViewModel

private bool? _viewClosed;

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

then bind to it in the View, using our helper class.

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

All of these are great solutions! I chose cjmurph's solution because it was very simple (for my feeble mind) and I can easily adapt it for future uses. See implemented code below. Thanks again, everyone!

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

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM