Dynamically Render And Bind One User Control In Another User Control Using MVVM Pattern In WPF

Let us have a scenario where we need to render any User Control in Main UserControl on the basis of items present in a list.
  • Main UserControl  and MainViewModel
  • Child UserControl and ChildViewModel.
XAML for ChildUserControl
  1. <UserControl x:Class="DynaUserControlFromAnotherUsercontrolMVVM.ChildUserControl"  
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
  5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  6.              mc:Ignorable="d"   
  7.              d:DesignHeight="100" d:DesignWidth="100">  
  8.     <Grid>  
  9.         <Grid.RowDefinitions>  
  10.             <RowDefinition></RowDefinition>  
  11.             <RowDefinition Height="auto"></RowDefinition>  
  12.         </Grid.RowDefinitions>  
  13.         <Border x:Name="BlockService" Grid.Column="0"   
  14.             BorderThickness="0"   
  15.             BorderBrush="#406E7B"   
  16.             Padding="5"              
  17.             Height="auto" Cursor="Hand"  
  18.             Margin="0"   
  19.             CornerRadius="30">  
  20.             <Border x:Name="MainBlock" Grid.Column="0"   
  21.                 BorderThickness="1"   
  22.                 BorderBrush="Transparent"   
  23.                 Padding="0"    
  24.                 Margin="0"   
  25.                 CornerRadius="30">  
  26.   
  27.                 <Grid>  
  28.                     <Grid.RowDefinitions>  
  29.                         <RowDefinition Height="auto"></RowDefinition>  
  30.                         <RowDefinition></RowDefinition>  
  31.                         <RowDefinition Height="auto"></RowDefinition>  
  32.                     </Grid.RowDefinitions>  
  33.                      
  34.                     <Border Name="ImageControlBlock"  
  35.                         Visibility="Hidden"  
  36.                         Grid.RowSpan="3"   Grid.Column="0"                          
  37.                         BorderBrush="Transparent"     
  38.                         Margin="0">  
  39.                         <Image Name="imageControl" Stretch="Fill"     
  40.                                    />  
  41.                     </Border>  
  42.                    
  43.                  
  44.                 
  45.                     <Border x:Name="BlockInside"  
  46.                         Grid.Column="0"   
  47.                         VerticalAlignment="Stretch"   
  48.                         BorderThickness="1"    
  49.                         Grid.Row="1"   
  50.                           
  51.                     BorderBrush="Transparent"   Margin="0" CornerRadius="30">  
  52.                         <StackPanel>  
  53.                             <Border Name="ServiceNameBlock" Grid.Column="0" VerticalAlignment="Top" BorderThickness="1" Grid.Row="1" Opacity=".5" Background="Black"  
  54.                     BorderBrush="Transparent"   Margin="10" CornerRadius="10" >  
  55.                                 <TextBlock x:Name="LabelServiceName" Text="{Binding ServiceName}"  Foreground="White" HorizontalAlignment="Center" FontSize="19" Padding="0 5"></TextBlock>  
  56.                             </Border>  
  57.                             
  58.                         </StackPanel>  
  59.                     </Border>  
  60.                      
  61.                 </Grid>  
  62.             </Border>  
  63.         </Border>         
  64.     </Grid>  
  65. </UserControl>  
ChildViewModel: In the beggining, ChildViewModel should look like below.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using System.Windows;  
  7.   
  8. namespace DynaUserControlFromAnotherUsercontrolMVVM  
  9. {  
  10.    public class ChildViewModel  
  11.     {  
  12.        private string serviceName;  
  13.   
  14.   
  15.        public string ServiceName  
  16.        {  
  17.            get  
  18.            {  
  19.                return serviceName;  
  20.            }  
  21.            set  
  22.            {  
  23.                if (serviceName != value)  
  24.                {  
  25.                    serviceName = value;  
  26.                    RaisePropertyChanged("ServiceName");  
  27.                }  
  28.            }  
  29.        }  
  30.         
  31.     }  
  32. }  
Main UserControl should be as below.
  1. <UserControl x:Class="DynaUserControlFromAnotherUsercontrolMVVM.MainUserControl"  
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
  5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  6.              mc:Ignorable="d"   
  7.              d:DesignHeight="300" d:DesignWidth="300">  
  8.     <Grid>  
  9.               
  10.     </Grid>  
  11. </UserControl>  
Now, let's have a list of records in MainViewModel according to which we need to display the child User Control in main UserControl and pass the datacontext for child control. We need to use ChildViewModel as the property of our MainViewModel and then, bind the ChildUserControl directly from XAML.

MainViewModel
  1. public class MainViewModel  
  2.    {  
  3.   
  4.        private List<Service> serviceList;  
  5.   
  6.   
  7.        public string ServiceList  
  8.        {  
  9.            get  
  10.            {  
  11.                return serviceList;  
  12.            }  
  13.            set  
  14.            {  
  15.                if (serviceList != value)  
  16.                {  
  17.                    serviceList = value;  
  18.                    RaisePropertyChanged("ServiceList");  
  19.                }  
  20.            }  
  21.        }  
  22.   
  23.     

  24.   
  25.    }  
Now, let's render ChildUserControl  in MainUserControl.
  1. <Grid>  
  2.        <ItemsControl Name="ControlCanvas"  ItemsSource="{Binding ServiceList}">  
  3.            <ItemsControl.ItemsPanel>  
  4.                <ItemsPanelTemplate>  
  5.                    <Canvas/>  
  6.                </ItemsPanelTemplate>  
  7.            </ItemsControl.ItemsPanel>  
  8.            <ItemsControl.ItemTemplate>  
  9.                <DataTemplate>  
  10.                    <local:ChildUserControl DataContext="{Binding chilViewModel}"/>  
  11.                </DataTemplate>  
  12.            </ItemsControl.ItemTemplate>  
  13.            <ItemsControl.ItemContainerStyle>  
  14.                <Style TargetType="ContentPresenter">  
  15.                    <Setter Property="Canvas.Height" Value="{Binding Anyproperty}"/>  
  16.                    <Setter Property="Canvas.Width" Value="{Binding Anyproperty}"/>  
  17.                    <Setter Property="Canvas.Left" Value="{Binding Anyproperty}"/>  
  18.                    <Setter Property="Canvas.Top" Value="{Binding Anyproperty}"/>  
  19.                </Style>  
  20.            </ItemsControl.ItemContainerStyle>  
  21.            
  22.        </ItemsControl>  
  23.    </Grid>  
Now, as you can see in above block that we used childViewModel property to bind the ChildUserControl, so how do we  get it in ViewModel? The MainViewModel should look like below.
  1. public class MainViewModel  
  2.   {  
  3.   
  4.       private List<Service> serviceList;  
  5.   
  6.   
  7.       public List<Service> ServiceList  
  8.       {  
  9.           get  
  10.           {  
  11.               return serviceList;  
  12.           }  
  13.           set  
  14.           {  
  15.               if (serviceList != value)  
  16.               {  
  17.                   serviceList = value;  
  18.                   RaisePropertyChanged("ServiceList");  
  19.               }  
  20.           }  
  21.       }  
  22.   
  23.       public class Service  
  24.       {  
  25.           public string Anyproperty { getset; }  
  26.           public string serviceName { getset; }  
  27.           public ChildViewModel chilViewModel { getset; }  
  28.       }  
  29.   
  30.       public void BindProperties()  
  31.       {  
  32.           Service serviceControl = new Service();  
  33.           serviceControl.Anyproperty = "1";  
  34.           serviceControl.serviceName = "test";  
  35.           serviceControl.chilViewModel = new ChildViewModel(serviceControl);  
  36.           ServiceList.Add(serviceControl);  
  37.       }  
  38.   
  39.   }  
And the childViewModel will be changed to,
  1. public class ChildViewModel  
  2.     {  
  3.        private string serviceName;  
  4.        private MainViewModel.Service serviceControl;  
  5.   
  6.        public ChildViewModel(MainViewModel.Service serviceControl)  
  7.        {  
  8.            // TODO: Complete member initialization  
  9.            this.serviceControl = serviceControl;  
  10.            BindProperty();  
  11.        }  
  12.   
  13.   
  14.        public string ServiceName  
  15.        {  
  16.            get  
  17.            {  
  18.                return serviceName;  
  19.            }  
  20.            set  
  21.            {  
  22.                if (serviceName != value)  
  23.                {  
  24.                    serviceName = value;  
  25.                    RaisePropertyChanged("ServiceName");  
  26.                }  
  27.            }  
  28.        }  
  29.   
  30.        public void BindProperty()  
  31.        {  
  32.            ServiceName = serviceControl.serviceName;  
  33.   
  34.        }  
  35.         
  36.     }  
We do not need to do anything in ChildUserControl.cs page. And in mainUsercontrol.cs page, directly bind the datacontext using main ViewModel as below.
  1. public partial class MainUserControl : UserControl  
  2.    {  
  3.        public MainUserControl()  
  4.        {  
  5.            InitializeComponent();  
  6.            this.DataContext = new MainViewModel();  
  7.        }  
  8.    }  
Feel free to ask questions on MVVM.

Thank you.
X

Build smarter apps with Machine Learning, Bots, Cognitive Services - Start free.

Start Learning Now