What is a more effective way to load a number of user controls?

jennyliu835 221 Reputation points
2020-09-23T05:47:28.657+00:00

Hi Peter + Daisy,
It seems that "Swich" can be used for several user controls (Here is my initial coding), but it is certainly not a good solution when the number goes up. So what is a more effective way to load a number of user controls?
Thanks

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,699 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,306 Reputation points
    2020-09-24T05:11:06.517+00:00

    Hi Jenny,
    another approach can be this code:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using WpfApp2.UserControls;
    
    namespace WpfApp2
    {
      /// <summary>
      /// Interaction logic for MainWindow.xaml
      /// </summary>
      public partial class MainWindow : Window
      {
        public MainWindow()
        {
          InitializeComponent();
          LoadListOfUserControls();
        }
    
        private Dictionary<int, UserControl> list;
        private void LoadListOfUserControls()
        {
          list = new Dictionary<int, UserControl>();
          list.Add(1, new UserControl1());
          list.Add(2, new UserControl2());
          list.Add(3, new UserControl3());
          list.Add(4, new UserControl4());
          list.Add(5, new UserControl5());
          list.Add(6, new UserControl6());
        }
    
        private void MenuItem_Click(object sender, RoutedEventArgs e)
    
        {
          int _num = new Random().Next(1,7);
    
          grid2.Children.Clear();
          grid2.Children.Add(list[_num]);
        }
      }
    }
    
    0 comments No comments

3 additional answers

Sort by: Most helpful
  1. DaisyTian-1203 11,616 Reputation points
    2020-09-24T01:59:47.99+00:00

    How about using list to add UserControls then load them one by one. I make a workaround base on making some change in your demo for you in bleow:

            List<UserControl> usersList = new List<UserControl>() { new UserControl1(), new UserControl2(), new UserControl3(), new UserControl4()};  
            int m = new Random().Next(4);  
            private void MenuItem_Click(object sender, RoutedEventArgs e)  
            {  
                if(m<usersList.Count)  
                {  
                    grid2.Children.Clear();  
                    grid2.Children.Add(usersList[m]);  
                    m ++;  
                }else if(m== usersList.Count)  
                {  
                    m = 0;  
                }  
            }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

  2. Peter Fleischer (former MVP) 19,306 Reputation points
    2020-09-24T05:47:39.827+00:00

    Hi Jenny,
    another MVVM approach can be this code:

    <Window x:Class="WpfApp2.MainWindow"  
            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"  
            xmlns:local="clr-namespace:WpfApp2"  
            mc:Ignorable="d"  
            Title="MainWindow"  Height="558" Width="718" Background="AliceBlue">  
      <Window.Resources>  
        <local:ViewModel x:Key="vm"/>  
      </Window.Resources>  
      
      <Grid DataContext="{StaticResource vm}">  
        <Menu Name="menu1" Width="343" Margin="76,110,0,0"   
              HorizontalAlignment="Left" VerticalAlignment="Top"  
              FontFamily="Times New Roman" FontSize="20"   
              Background="#FF00F500"  
              ItemsSource="{Binding ListOfControls}">  
          <Menu.ItemContainerStyle>  
            <Style TargetType="MenuItem">  
              <Setter Property="Header" Value="{Binding Key}" />  
              <Setter Property="Command" Value="{Binding Source={StaticResource vm}}" />  
              <Setter Property="CommandParameter" Value="{Binding}" />  
            </Style>  
          </Menu.ItemContainerStyle>  
        </Menu>  
        <UserControl Height="190" Width="490" Margin="74,184,118,133"   
                     Background="Aqua">  
          <Grid Name="grid2" Height="185" Width="485"   
                Background="#FFFDD293">  
            <TextBlock Name="textBlock1"   
                       Text="User Control Area"  
                       Height="30" Width="180"   
                       HorizontalAlignment="Left" VerticalAlignment="Top"  
                       FontFamily="Times New Roman" FontSize="22"     
                       Background="#FFFFCD00"/>  
            <ContentControl Content="{Binding ActualUserControl}"/>  
          </Grid>  
        </UserControl>  
      </Grid>  
    </Window>  
    

    And ViewModel:

    27834-x.png

    Buggy forum software don't show code, see attached file 27850-x.txt.

    Result:

    27942-x.gif

    1 person found this answer helpful.

  3. Andy ONeill 361 Reputation points
    2020-09-25T09:56:15.297+00:00

    It is bad practice to include any instance of a control in a viewmodel.
    This is a black vs white area.
    Freezables are arguably in a grey area but any uielement is not.

    You should instead use datatemplating or instantiating the usercontrol in the view.
    Although not aimed at this particular topic, you can see a quick and dirty version here:

    https://social.technet.microsoft.com/wiki/contents/articles/52485.wpf-tips-and-tricks-using-contentcontrol-instead-of-frame-and-page-for-navigation.aspx

    This uses types to avoid the viewmodel instantiating UI.
    The reason best practice insists viewmodels do not reference UI directly is twofold:

    1) Separation of concerns.
    The viewmodel here only "knows" about a viewmodel type.
    If you decide later to change the view to some other then this is "just" a change in your resources associate datatemplate with viewmodel type.

    2) Testability
    When you instantiate any UI control this introduces an overhead and the possibility you will slip into working with UI events and suchlike in your viewmodels.
    If you have no UI instance at all then you can't do that and your lead will be happier as he does your code reviews.

    1 person found this answer helpful.