Close/Hide Window from UserControl

I develop a wpf application on which I interact with a huge grid of buttons (built with an ItemsControl).

When I click on one button, the app displays a new window. This new window displays an UserControl. I use a service to show the new window :

public class WindowService
{
    #region Variable
    #endregion Variable

    #region Constructor
    public WindowService()
    {

    }
    #endregion Constructor

    #region Properties
    #endregion Properties

    #region Public Method

    public void ShowWindow(object viewModel)
    {
        var win = new WindowView();
        //win.Content = viewModel; <-- not the best way, go to see in comment why (thanks @Ndubuisi Jr)
        win.DataContext = viewModel;
        win.Show();
    }

    #endregion Public Method

    #region Private Method
    #endregion Private Method

}

And the code to call this method :

public void display_InfoPoste(object commandParameter)
    {
        windowPoste = new WindowService();
        windowPoste.ShowWindowCommandParameter(new InfoPosteViewModel(commandParameter));
    }

No Problem with that. (The window displayed is only a content to receive different UserControl)

Now, I have a button "close" on the user control, but I don't find any way to close the window. I work with MVVM pattern, that's why I don't find yet how to do that.

Could you help me? (I can share a screenshot with you if you need)

Thanks a lot

Picture : Part of the project's arborescence


Just below, the requested code of the "InfoPosteViewModel.cs"

#region Variable
    private string _commandParameter;   
    #endregion Variable

    #region Constructor

    public InfoPosteViewModel()
    {
        //FermerCommand = new RelayCommand(Action_FermerWindow);
    }

    public InfoPosteViewModel(object commandParameter)
    {
        SelectedViewModel = new InfoPosteViewModel();
        _commandParameter = (string)commandParameter;
        ID = _commandParameter;
    }

    #endregion Constructor

    #region Properties

    public ICommand FermerCommand { get; set; }

    private static string _id;
    public string ID
    {
        get { return _id; }
        set
        {
            _id = value;
            OnPropertyChanged("ID");
        }
    }

    private object _selectedViewModel;
    public object SelectedViewModel
    {
        get
        {
            return _selectedViewModel;
        }
        set
        {
            _selectedViewModel = value;
            OnPropertyChanged("SelectedViewModel");
        }
    }

    #endregion Properties

    #region Public Method

    public void Action_FermerWindow(object commandParameter)
    {

    }

    #endregion Public Method

2 answers

  • answered 2020-03-31 11:45 Phoenix Stoneham

    Try passing the close command to the VM that is being displayed in the Dialog. Then link that to the close button or action. Because it's the close command of the VM that opened the dialog you can then close the dialog using the reference in that VM and continue with any clean up or follow up code you need.

    Oh, and you'll need to make the window an instance variable rather than a local variable.

  • answered 2020-03-31 13:41 Peregrine

    The cleanest way to close a Window from its ViewModel in MVVM is using an attached property.

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

    This can be used in the View's xaml file

    <Window
        ....    
        vhelp:perWindowHelper.CloseWindow="{Binding ViewClosed}" />
    

    bound against the ViewClosed property (of type bool?) from the ViewModel. Setting this property value will close the View.

    More details on my blog post