0

Could you tell me how to in pure MVVM way call (I mean open/show) child window from parent window. Let's say I have two Views:

  1. MainWindow.cs (MainWindow.xaml) - parent window (DataContext = new MainWindowViewModel())
  2. Window.cs (Window.xaml) - child window (DataContext = new WindowViewModel())

And corresponding ViewModel classes:

  1. MainWindowViewModel.cs
  2. WindowViewModel.cs

I would like my window to be opened after button click (button that is on the MainWindow view). Because of that I have defined command binding in MainWindow.xaml:

<Button x:Name="buttonOpenWindow" Content="Open window..." Width="100" Height="20" Command="{Binding OpenWindowCmd}"/>

And MainWindowViewModel.cs piece:

public ICommand OpenWindowCmd { get; set; }

public MainWindowViewModel()
{
    OpenWindowCmd = new RelayCommand(o => OpenWindow());
}

private void OpenWindow()
{
    // What to put here?
}

In Window.xaml I added something like that:

<Window x:Class="Namespace.View.Window"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:vm="clr-namespace:Namespace.ViewModel"
    Title="Title" Height="300" Width="325" Visibility="{Binding IsWindowVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>

(...)

And the WindowViewModel.cs:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using Namespace.Annotations;

namespace Namespace.ViewModel
{
    public class WindowViewModel : INotifyPropertyChanged
    {
        private bool _isWindowVisible;
        public bool IsWindowVisible
        {
            get { return _isWindowVisible; }
            set
            {
                _isWindowVisible = value;
                OnPropertyChanged(nameof(IsWindowVisible));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I am not sure what to do next and if that approach is correct. I found some services implementations in the forum, but I thought of using just Visibility property instead (but not sure if it is possible). I need to somehow change the IsWindowVisible in one of the view models I suppose. Could anyone suggest how to gently handle such sub window opening?

qwert_
  • 23
  • 5
  • You could for example use a window service that is responsible for creating and opening the windows: https://stackoverflow.com/questions/47352870/mvvm-show-new-window-from-vm-when-seperated-projects/47353136#47353136 – mm8 Feb 22 '18 at 15:55
  • Could you please tell me which part in that case is the WindowService class? Model/View/ViewModel? I suppose in that case that service is part of model. If so - model depends on view which sounds like bad design, isn't it? – qwert_ Feb 22 '18 at 16:06
  • Neither. It's a service. The view model uses the window service to instantiate the creation of a new window. It's not supposed to this itself. – mm8 Feb 22 '18 at 16:07
  • I understand. And that is the gentle and really best way of handling such things in WPF/MVVM? I suppose there is no way of handling that using Visibility property, right? – qwert_ Feb 22 '18 at 16:09
  • You need to create the window somehow. Setting the Visibility property won't do this. – mm8 Feb 22 '18 at 16:10
  • That's true. I don't know why but I assumed that window is already instanciated. Thanks for your comments. BTW is it possible to create child window in the same moment as parent window is created, then set datacontext and just manipulate visibility then? Probably not. – qwert_ Feb 22 '18 at 16:48

1 Answers1

0

If I understood well, you need something like this:

private void OpenWindow()
{
    WindowViewModel wvm = new WindowViewModel();
    Window win = new Window()
    {
        DataContext = wvm;
    };
    win.Show();
}

If you don't like this solution then try the one from the comments with IWindowService. In any case it makes no sense to use a Visibility property.

gts13
  • 1,048
  • 1
  • 16
  • 29
  • I used suggestion from comments to completly have view and view model layers separated - so the IWindowService interface in the model + implementation of it in the view. I think it is the most clean solution I've found so far. You're right - there is no way to handle that using just Visibility property. – qwert_ Mar 02 '18 at 08:44