简体   繁体   中英

How to close a window from the user control inside?

I've got a WPF program and at some point I open a window:

    public object testCommand()
    {
        Window window = new Window
        {
            Title = "My User Control Dialog",
            Content = new OKMessageBox("Error Message"),
            SizeToContent = SizeToContent.WidthAndHeight,
            ResizeMode = ResizeMode.NoResize
        };
        window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
        window.ShowDialog();

        return null;
    }

User Control XAML:

<UserControl x:Class="SolidX.Base.MessageBoxes.OKMessageBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SolidX.Base.MessageBoxes"
             xmlns:viewProperties="clr-namespace:AppResources.Properties;assembly=AppResources"
             mc:Ignorable="d" 
             d:DesignHeight="150" d:DesignWidth="400">
    <Grid>
        <TextBlock x:Name="textMessage" Margin="10"/>
        <Grid Height="Auto" VerticalAlignment="Bottom">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <CheckBox Content="Don't show this again" HorizontalAlignment="Right" Margin="5,5,10,5"/>
            <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
                <Button x:Name="btnOk" Content="{x:Static viewProperties:Resources.Common_OK}" Height="25" VerticalAlignment="Center" Width="90" Margin="5"/>
            </StackPanel>
        </Grid>
    </Grid>
</UserControl>

User Control Code-behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SolidX.Base.MessageBoxes
{
    /// <summary>
    /// Interaction logic for OKMessageBox.xaml
    /// </summary>
    public partial class OKMessageBox : UserControl
    {
        public OKMessageBox(string Message)
        {
            InitializeComponent();
            textMessage.Text= Message;
        }
    }
}

And in my user control, I am trying to have buttons that close the window (currently, setting Button.IsCancel = true; works, but I want this to be a reusable option - essentially making my own this.Close; ).

I tried this (as suggested by a couple other StackOverflow answers) in the code-behind for my usercontrol but to no avail ( parentWindow is always null):

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

Try this in the UserControl:

xaml

<UserControl .... Loaded="UserControl_Loaded">
    <!--  -->
</UserControl>

cs

public UserControl()
{
    InitializeComponent();
}

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    var window = Window.GetWindow(this);
    window.Close();
}

In case you are using ViewModel class for your Window , you can set the ViewModel class to your Window instance, and the ViewModel can store it's owner.

For example the ViewModel:

public class CloseConfirmViewModel
{
    internal Window Owner { get; set; }

    public ICommand CloseCommand { get; private set; } // ICommand to bind it to a Button

    public CloseConfirmViewModel()
    {
        CloseCommand = new RelayCommand<object>(Close);
    }

    public void Close() // You can make it public in order to call it from codebehind
    {
        if (Owner == null)
            return;

        Owner.Close();
    }
}

In order to get it work, you have to set the ViewModel class to your Window :

public partial class CloseConfirmWindow : Window
{
    public CloseConfirmWindow(CloseConfirmViewModel model)
    {
        DataContext = model;

        InitializeComponent();

        model.Owner = this;
    }
}

And you are creating a new instance this way:

var model = new CloseConfirmViewModel();
var closeWindow = new CloseConfirmWindow(model);
closeWindow.ShowDialog(); // Hopefully you've added a button which has the ICommand binded

You can bind the Window 's CloseCommand to the UserControl 's button this way, or if you are not using commands, call the Close() method when the UC's button is being clicked.

None of those approaches worked for me. Most just closed the parent window. I was using an XAML Popup from my main window. Something like.

<DockPanel/>
   <Popup x:Name="puMyControl"/>
      <Local:UserControl />
   </Popup>
</DockPanel>

Elsewhere in my main window code behind, I added:

puMyControl.IsOpen = true;

Inside the UserControl I had a cancel button. Popup's do not have children, therefore I needed to reference the Popup's parent which was the DockPanel.

private void BtnClose_Click(object sender, RoutedEventArgs e)
{
    Popup pu = Parent as Popup;
    if ( pu != null )
    {
       DockPanel dp = pu.Parent as DockPanel;
       if (dp != null)
       {
          dp.Children.Remove(pu);
       }
    }
}

The aha moment was, that I was removing the Popup, not the UserControl. 'this' would refer to the UserControl. As you can see above, I am removing the Popup from the DockPanel. That led to a simpler and more universal solution.

Popup pu = Parent as Popup;
if (pu != null)
{
   pu.IsOpen = false;
}

要关闭模态对话框,您应该设置DialogResult: DialogResult = false;

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