In this article I'll discuss how to develop reusable WPF child window using MVVM designed pattern.

 

Prerequisites :

 

1. Basic Knowledge of MVVM Design Pattern.

2. Basic Knowledge of Action<T> Delegate in C#.

3. Basic Knowledge of XAML development.

4. Visual Studio 2013 (You can use another version of VS).

5. Microsoft PRISM 4.1 - Microsoft.Practices.Prism.dll (We use this prism library to implement the WPF delegate command).

6. Basic knowledge about Singleton design pattern.

 

In this article, I will demonstrate how to pass the parameters from parent window to child window and also from child window to parent window.

 

So now we will start our journey .....  :)

 

1. Create new WPF project called "MVVMChildWindow" using your visual studio IDE.

 

2. Delete "MainWindow.xaml" page your solution. Add new Window (WPF) called "MainView.xaml" to your solution.

 

 

 

3. Open app.xaml file and update StartupUri as "MainView.xaml".

 

 

4. Add new class called "Person" to your project and implement the  class as bellow.

 

Also add another class called "BaseViewModel" and implement that class as bellow.

 

 

5. Add new folder called "ChildWindow" to your solution. After that add another two folder called "View" and "ViewModel" to "ChildWindow" folder. Now your folder hierarchy should be like this.

 

 

 

(Anyway you don't need to follow same hierarchy and naming convention. But as a best practice I encourage you to  follow the similar hierarchy and naming convention.)

 

6. Add new class called "AddUserViewModel" to ViewModel folder. and Implement the class as bellow.

C#
Edit|Remove
using Microsoft.Practices.Prism.Commandsusing System; 
using System.Collections.Genericusing System.Linq; 
 
namespace MVVMChildWindow.ChildWindow.ViewModel 
{ 
    public class AddUserViewModel : BaseViewModel 
    { 
        #region Events 
 
        public event Action<Person> Closed; 
 
        #endregion 
 
        #region Constructor 
        public AddUserViewModel(int personId) 
        { 
            persons = new List<Person>() 
            { 
                new Person(){Id=1,Address="Blk 244/A",Email="email1@gmail.com",FirstName="FirstNameA",LastName="LastNameA"}, 
                new Person(){Id=2,Address="Blk 244/B",Email="email2@gmail.com",FirstName="FirstNameB",LastName="LastNameB"}, 
                new Person(){Id=3,Address="Blk 244/C",Email="email3@gmail.com",FirstName="FirstNameC",LastName="LastNameC"}, 
                new Person(){Id=4,Address="Blk 244/D",Email="email4@gmail.com",FirstName="FirstNameD",LastName="LastNameD"}, 
                new Person(){Id=5,Address="Blk 244/E",Email="email5@gmail.com",FirstName="FirstNameE",LastName="LastNameE"}, 
                new Person(){Id=6,Address="Blk 244/F",Email="email6@gmail.com",FirstName="FirstNameF",LastName="LastNameF"}, 
                new Person(){Id=7,Address="Blk 244/G",Email="email7@gmail.com",FirstName="FirstNameG",LastName="LastNameG"}, 
                new Person(){Id=8,Address="Blk 244/H",Email="email8@gmail.com",FirstName="FirstNameH",LastName="LastNameH"}, 
            }; 
 
            okCommand = new DelegateCommand(SavePerson); 
 
            this.PersonId = personId; 
 
            Init(); 
        }  
        #endregion 
 
        #region Public Properties 
 
        public int PersonId { getset; } 
 
        private string firstName; 
        public string FirstName 
        { 
            get { return firstName; } 
            set  
            {  
                firstName = value; 
                RaisePropertyChanged("FirstName"); 
            } 
        } 
 
        private string lastName; 
        public string LastName 
        { 
            get { return lastName; } 
            set 
            { 
                lastName = value; 
                RaisePropertyChanged("LastName"); 
            } 
        } 
 
        private string address; 
        public string Address 
        { 
            get { return address; } 
            set 
            { 
                address = value; 
                RaisePropertyChanged("Address"); 
            } 
        } 
 
        private string email; 
        public string Email 
        { 
            get { return email; } 
            set 
            { 
                email = value; 
                RaisePropertyChanged("Email"); 
            } 
        } 
 
        private List<Person> persons; 
        public List<Person> Persons 
        { 
            get { return persons; } 
            set { persons = value; } 
        } 
         
 
        #endregion 
 
        #region Command Properties 
 
        private DelegateCommand okCommand; 
        public DelegateCommand OkCommand 
        { 
            get { return okCommand; } 
        } 
 
        #endregion 
 
        #region Private Methods 
        private void SavePerson() 
        { 
            if (Closed != null) 
            { 
                var person = new Person() 
                { 
                    Address = address, 
                    Email = email, 
                    FirstName = firstName, 
                    LastName = lastName, 
                    Id = PersonId 
                }; 
 
                Closed(person); 
            } 
        } 
 
        private void Init() 
        { 
            var person = persons.FirstOrDefault(p => p.Id == PersonId); 
            FirstName = person.FirstName; 
            RaisePropertyChanged("FirstName"); 
            LastName = person.LastName; 
            RaisePropertyChanged("LastName"); 
            Email = person.Email; 
            RaisePropertyChanged("Email"); 
            Address = person.Address; 
            RaisePropertyChanged("Address"); 
        } 
 
        #endregion 
    } 
} 
 

Here you can see that, we have declared event action delegate named by Changed. When SavePerson method called, Changed event action will fire and  all the objects who registered this event will  notified with modified person data..

 

7.  Add new UserControll (WPF) called "AddUserView.xaml" into view folder and implement the view as bellow.

XAML
Edit|Remove
<UserControl x:Class="MVVMChildWindow.ChildWindow.View.AddUserView" 
             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"  
             mc:Ignorable="d"  
             Width="450" 
             Height="200"    <Grid Background="#FFB0D1EC" Margin="10"        <Grid.RowDefinitions            <RowDefinition Height="5"/> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="5"/> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="5"/> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="5"/> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="5"/> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="5"/> 
        </Grid.RowDefinitions> 
         
        <Grid.ColumnDefinitions            <ColumnDefinition Width="150"/> 
            <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 
         
         
        <TextBlock Grid.Row="1" Text="First Name :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding FirstName,Mode=TwoWay}" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
        <TextBlock Grid.Row="3" Text="Last Name :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
        <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding LastName,Mode=TwoWay}" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
        <TextBlock Grid.Row="5" Text="Address :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
        <TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Email,Mode=TwoWay}" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
        <TextBlock Grid.Row="7" Text="Email :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
        <TextBox Grid.Row="7" Grid.Column="1" Text="{Binding Address,Mode=TwoWay}" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
        <Button Grid.Row="9" Grid.Column="1" Width="150" HorizontalAlignment="Left" Content="OK" Command="{Binding OkCommand}"/> 
    </Grid> 
</UserControl> 
 

8. Now add new folder called "Common" to your project and add new class called "ChildWindowManager"  into newly created folder. Implement the class as bellow.

C#
Edit|Remove
using System.Windows; 
 
namespace MVVMChildWindow.Common 
{ 
    public class ChildWindowManager : BaseViewModel 
    { 
        public ChildWindowManager() 
        { 
            WindowVisibility = Visibility.Collapsed; 
            XmlContent = null; 
        } 
 
        //Singleton pattern implementation 
        private static ChildWindowManager instance; 
        public static ChildWindowManager Instance 
        { 
            get 
            { 
                if (instance == null) 
                { 
                    instance = new ChildWindowManager(); 
                } 
                return instance; 
            } 
        } 
 
        #region Public Properties 
 
        private Visibility windowVisibility; 
        public Visibility WindowVisibility 
        { 
            get { return windowVisibility; } 
            set  
            {  
                windowVisibility = value; 
                RaisePropertyChanged("WindowVisibility"); 
            } 
        } 
 
        private FrameworkElement xmlContent; 
        public FrameworkElement XmlContent 
        { 
            get { return xmlContent; } 
            set  
            {  
                xmlContent = value; 
                RaisePropertyChanged("XmlContent"); 
            } 
        } 
         
        #endregion 
 
        #region Public Methods 
 
        public void ShowChildWindow(FrameworkElement content) 
        { 
            XmlContent = content; 
            RaisePropertyChanged("XmlContent"); 
            WindowVisibility = Visibility.Visible; 
            RaisePropertyChanged("WindowVisibility"); 
        } 
 
        public void CloseChildWindow() 
        { 
            WindowVisibility = Visibility.Collapsed; 
            RaisePropertyChanged("WindowVisibility"); 
            XmlContent = null; 
            RaisePropertyChanged("XmlContent"); 
        }  
 
        #endregion 
    } 
} 
 

You can see that, We have used singleton designed pattern to implement this class.

 

9. Now select the ChildWindow folder and add new class called "ChildWindowView". Implement the class as bellow.

C#
Edit|Remove
using MVVMChildWindow.ChildWindow.View; 
using MVVMChildWindow.ChildWindow.ViewModel; 
using MVVMChildWindow.Common; 
using System; 
 
namespace MVVMChildWindow.ChildWindow 
{ 
    public class ChildWindowView:BaseViewModel 
    { 
        public event Action<Person> Closed; 
        public ChildWindowView() 
        { 
 
        }  
 
        public void Show(int personId) 
        { 
            AddUserViewModel vm = new AddUserViewModel(personId); 
            vm.Closed += ChildWindow_Closed; 
            ChildWindowManager.Instance.ShowChildWindow(new AddUserView() { DataContext = vm }); 
        } 
 
        void ChildWindow_Closed(Person person) 
        { 
            if (Closed != null) 
                Closed(person); 
            ChildWindowManager.Instance.CloseChildWindow(); 
        } 
    } 
} 
 

10. Add new class called "MainViewModel" to project. Implement the class as below.

C#
Edit|Remove
using Microsoft.Practices.Prism.Commandsusing MVVMChildWindow.ChildWindow; 
 
namespace MVVMChildWindow 
{ 
    public class MainViewModel:BaseViewModel 
    { 
        #region Construction 
        public MainViewModel() 
        { 
            showChildWindowCommand = new DelegateCommand(ShowChildWindow); 
        }  
 
        #endregion 
 
        #region Public Properties 
 
        public int PersonId { getset; } 
 
        private string firstName; 
        public string FirstName 
        { 
            get { return firstName; } 
            set 
            { 
                firstName = value; 
                RaisePropertyChanged("FirstName"); 
            } 
        } 
 
        private string lastName; 
        public string LastName 
        { 
            get { return lastName; } 
            set 
            { 
                lastName = value; 
                RaisePropertyChanged("LastName"); 
            } 
        } 
 
        private string address; 
        public string Address 
        { 
            get { return address; } 
            set 
            { 
                address = value; 
                RaisePropertyChanged("Address"); 
            } 
        } 
 
        private string email; 
        public string Email 
        { 
            get { return email; } 
            set 
            { 
                email = value; 
                RaisePropertyChanged("Email"); 
            } 
        } 
 
        private DelegateCommand showChildWindowCommand; 
        public DelegateCommand ShowChildWindowCommand 
        { 
            get { return showChildWindowCommand; } 
        }  
 
        #endregion 
 
        #region Private Methods 
 
        private void ShowChildWindow() 
        { 
            var childWindow = new ChildWindowView(); 
            childWindow.Closed += (r => 
                { 
                    FirstName = r.FirstName; 
                    RaisePropertyChanged("FirstName"); 
 
                    LastName = r.LastName; 
                    RaisePropertyChanged("LastName"); 
 
                    Email = r.Email; 
                    RaisePropertyChanged("Email"); 
 
                    Address = r.Address; 
                    RaisePropertyChanged("Address"); 
                }); 
            childWindow.Show(1); 
        }  
 
        #endregion    
    } 
} 
 

11. Add following XAML code to MainView.xaml.

XAML
Edit|Remove
<Window x:Class="MVVMChildWindow.MainView" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainView"    <Grid Margin="5" 
        <ContentControl 
            VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Transparent" 
            VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"            <Grid                <Grid.RowDefinitions                    <RowDefinition Height="50"/> 
                    <RowDefinition Height="*"/> 
                </Grid.RowDefinitions> 
 
                <Grid Grid.Row="0" Margin="0,20,0,0"                    <Button Content="Search Person" Command="{Binding ShowChildWindowCommand}" Width="150"/> 
                </Grid> 
                <Grid Grid.Row="1" Margin="0,20,0,0"                    <Grid.RowDefinitions                        <RowDefinition Height="5"/> 
                        <RowDefinition Height="30"/> 
                        <RowDefinition Height="5"/> 
                        <RowDefinition Height="30"/> 
                        <RowDefinition Height="5"/> 
                        <RowDefinition Height="30"/> 
                        <RowDefinition Height="5"/> 
                        <RowDefinition Height="30"/> 
                        <RowDefinition Height="5"/> 
                    </Grid.RowDefinitions> 
 
                    <Grid.ColumnDefinitions                        <ColumnDefinition Width="150"/> 
                        <ColumnDefinition Width="*"/> 
                    </Grid.ColumnDefinitions> 
 
                    <TextBlock Grid.Row="1" Text="First Name :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
                    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding FirstName,Mode=TwoWay}" Width="300" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
                    <TextBlock Grid.Row="3" Text="Last Name :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
                    <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding LastName,Mode=TwoWay}" Width="300" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
                    <TextBlock Grid.Row="5" Text="Address :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
                    <TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Email,Mode=TwoWay}" Width="300" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
                    <TextBlock Grid.Row="7" Text="Email :" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15,0,0,0"/> 
                    <TextBox Grid.Row="7" Grid.Column="1" Text="{Binding Address,Mode=TwoWay}" Width="300" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
 
                </Grid> 
            </Grid> 
        </ContentControl> 
 
        <Border Name="childWindow" Visibility="{Binding WindowVisibility}" Background="#88000000"             <ContentControl Content="{Binding XmlContent}" HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"></ContentControl> 
        </Border> 
         
    </Grid> 
</Window> 


12. Go to MainView.xaml.cs class and add following code to class constructor.

C#
Edit|Remove
using MVVMChildWindow.Common; 
using System.Windows; 
 
namespace MVVMChildWindow 
{ 
    /// <summary> 
    /// Interaction logic for MainView.xaml 
    /// </summary> 
    public partial class MainView : Window 
    { 
        public MainView() 
        { 
            InitializeComponent();   
            childWindow.DataContext = ChildWindowManager.Instance; 
            this.DataContext = new MainViewModel();      
        } 
    } 
} 
 

13. Now build your project and run the application.If everything is going fine , you will see the following interface.

 

14. Click on Search Person button. Then child window will be opened.

 

15. You can edit person detail if you want and click on OK button. Then child window will be closed and person data will be appeared in main window.

 

 

Happy Codding !!!!!!!!!!!!!!!!!!!!!!