简体   繁体   中英

How do I close a window from its user control view model?

I have a window which hosts various UserControl's as pages. Is it possible to close the window which I have no reference to from within the usercontrol's datacontext? Simplified details:

SetupWindow

    public SetupWindow()
    {
        InitializeComponent();
        Switcher.SetupWindow = this;
        Switcher.Switch(new SetupStart());  
    }

    public void Navigate(UserControl nextPage)
    {
        this.Content = nextPage;
    }

SetupStart UserControl

<UserControl x:Class="...">
 <UserControl.DataContext>
    <local:SetupStartViewModel/>
 </UserControl.DataContext>
 <Grid>
    <Button Content="Continue" Command="{Binding ContinueCommand}"/>
 </Grid>
</UserControl>

SetupStartViewModel

    public SetupStartViewModel()
    {
    }

    private bool canContinueCommandExecute() { return true; }

    private void continueCommandExectue()
    {
        Switcher.Switch(new SetupFinish());
    }

    public ICommand ContinueCommand
    {
        get { return new RelayCommand(continueCommandExectue, canContinueCommandExecute); }
    }

I do this by having a RequestClose event in my ViewModel that it can raise when it wants the view to close.

This is then hooked up to the window's Close() command by the code that creates the window. eg

var window    = new Window();
var viewModel = new MyViewModel();

window.Content = viewModel;
viewModel.RequestClose += window.Close;

window.Show()

This way all the stuff to do with window creation is handled in one place. Neither the view, or the viewmodel know about windows.

I managed to find a solution from an answer here: How to bind Close command to a button

View-Model:

public ICommand CloseCommand
{
    get { return new RelayCommand<object>((o) => ((Window)o).Close(), (o) => true); }
}

View:

<Button Command="{Binding CloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Content="Close"/>

Inside your user control you can find a reference to the window that's hosting it with a static method on the Window class.

var targetWindow = Window.GetWindow(this);
targetWindow.Close();

Edit:

If you have no reference to the user control that the data context is being used in you don't have a huge amount of options, if there is just 1 application window you can get away with

Application.Current.MainWindow.Close()

If there are many windows in your application and the one you want to close is in focus you could find that with something like

public Window GetFocusWindow()
{
    Window results = null;
    for (int i = 0; i < Application.Current.Windows.Count; i ++)
        if (Application.Current.Windows[i].IsFocused)
        {
            results = Application.Current.Windows[i];
            break;
        }
    return results;
}

Finally I guess (though this is pretty out there) you could loop through the applications window classes, checking the data context of every object in the visual tree until you find the reference you're after, the window can be closed from there.

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