Bootstrap

【wpf】05 几种容器动态创建控件的对比

在这里插入图片描述
今天利用一点时间,对wpf中在常用容器中动态创建控件的方法进行了学习和测试,本篇文章用来记录这个过程及一些心得。

1 容器说明

用于对比的wpf常用容器类包括如下七种:

1.1 StackPanel

布局特点:

StackPanel按照垂直(默认)或水平方向堆叠其子元素。
子元素不会自动换行,而是依次排列。

动态添加控件:

可以通过Children.Add方法动态添加控件。
新添加的控件会自动按照StackPanel的排列方向放置在现有控件的后面。

适用场景:

适用于需要简单堆叠控件的场景,如垂直或水平菜单、表单字段等。

1.2 Grid

布局特点:

Grid将布局划分为行和列的网格。
子元素可以放置在特定的单元格中,支持跨行跨列。
提供了更灵活和复杂的布局能力。

动态添加控件:

需要先定义行和列,然后通过Children.Add方法添加控件。
新添加的控件需要指定其所在的行和列,可以使用Grid.RowGrid.Column附加属性。
可以通过RowDefinitionsColumnDefinitions动态添加行和列。

适用场景:

适用于需要复杂布局的场景,如表单、数据网格、自定义用户界面等。

1.3 ScrollViewer

布局特点:

ScrollViewer用于提供滚动功能,使其内容在视图窗口中可见。
它只能包含一个直接子元素,但这个子元素可以是另一个布局容器(如StackPanelGrid等),从而间接包含多个控件。

动态添加控件:

由于ScrollViewer只能有一个直接子元素,因此通常会在其内部放置一个布局容器(如StackPanelGrid)。
然后在这个布局容器中动态添加控件。
当内容超出ScrollViewer的视图范围时,会自动出现滚动条。

适用场景:

适用于需要滚动功能的场景,如长列表、详细报告、大型表单等。

1.4 WrapPanel

布局特点:

WrapPanel按照水平或垂直方向排列其子元素。
当一行或一列的空间不足时,子元素会自动换行到下一行或下一列。

动态添加控件:

可以通过Children.Add方法动态添加控件。
新添加的控件会自动按照WrapPanel的排列方向放置在现有控件的后面,并在必要时换行。

适用场景:

适用于需要自动换行的布局场景,如水平或垂直排列的图标、文本等。

1.5 Canvas

布局特点:

Canvas允许通过绝对坐标来定位其子元素。
子元素可以放置在Canvas的任何位置,不受其他子元素的影响。

动态添加控件:

可以通过Children.Add方法动态添加控件。
新添加的控件需要使用Canvas.LeftCanvas.Top附加属性来指定其位置。

适用场景:

适用于需要精确控制子元素位置的场景,如绘图应用、自定义布局等。

1.6 UniformGrid

布局特点:

UniformGrid将布局划分为多个大小相同的单元格,并自动将子元素分配到这些单元格中。
子元素在UniformGrid中按照行和列的顺序排列。

动态添加控件:

可以通过Children.Add方法动态添加控件。
新添加的控件会自动分配到下一个可用的单元格中。

适用场景:

适用于需要创建均匀网格布局的场景,如图标网格、按钮网格等。

1.7 DockPanel

布局特点:

DockPanel允许其子元素停靠在容器的边缘(顶部、底部、左侧、右侧)或填充剩余的空间。
子元素的停靠顺序和填充方式可以通过Dock属性来指定。

动态添加控件:

可以通过Children.Add方法动态添加控件。
新添加的控件需要设置其Dock属性来指定停靠位置。

适用场景:

适用于需要创建停靠布局的场景,如工具栏、侧边栏等。

2 编码对比效果

在同一个Window中创建多个容器,为保证不同容器可以正常显示,这里我们采用使用框架元素(Framework Element)的Visibility属性,通过动态地改变容器的Visibility属性(设置为Visible或Collapsed),你可以控制哪些容器是可见的。设置为Collapsed的容器将不会占用布局空间,也不会渲染其内容,这有助于确保只有最上层的容器是可见的。

参考内容如下:

在用户界面设计中,当你需要在不同的容器(如视图、面板或窗口)之间切换,并且希望只有最上层的容器显示其内容,而其他容器则保持背景透明时,你可以采取以下几种方法来实现这一效果:

  1. 使用堆叠布局(Stack Layout):
    如果你使用的是像XAML(在WPF、UWP或Xamarin中)这样的标记语言,你可以使用堆叠布局(如StackPanel在WPF中)来重叠放置容器。通过设置容器的Background属性为透明(或在XAML中使用Transparent关键字),你可以确保它们不会遮挡彼此的内容,除非它们包含非透明的元素。最上层的容器将显示其内容,因为它会覆盖在下层容器的上方。
  2. 使用框架元素(Framework Element)的Visibility属性:
    通过动态地改变容器的Visibility属性(设置为Visible或Collapsed),你可以控制哪些容器是可见的。设置为Collapsed的容器将不会占用布局空间,也不会渲染其内容,这有助于确保只有最上层的容器是可见的。
  3. 使用Z-Index或类似的层级控制:
    在某些UI框架中,你可以通过调整元素的Z-Index来控制它们的堆叠顺序。虽然XAML本身没有直接的Z-Index属性,但你可以通过调整容器在布局中的顺序或使用Canvas布局并设置Canvas.ZIndex属性来实现类似的效果。
  4. 使用弹出窗口(Popup)或模态对话框:
    如果你希望某个容器能够完全覆盖其他容器,并且不希望其他容器的内容干扰到用户交互,你可以使用弹出窗口(如WPF中的Popup控件)或模态对话框。这些元素通常会在其他内容之上显示,并且可以配置为具有透明背景。
  5. 自定义渲染和布局逻辑:
    如果你使用的UI框架没有提供直接支持这种效果的方法,你可能需要自定义渲染和布局逻辑。这通常涉及到对UI元素的深入理解和对框架底层工作原理的掌握。
    使用动画和过渡效果:
    为了提供更平滑的用户体验,你可以在容器之间切换时使用动画和过渡效果。这不仅可以增强视觉效果,还可以帮助用户更好地理解哪些内容是当前活动的。
    请注意,具体实现方法将取决于你使用的UI框架和编程语言。在WPF中,你可以使用上述方法中的任何一种或组合使用它们来实现容器之间的切换效果。在其他UI框架中,虽然具体的属性和方法可能有所不同,但基本原理是相似的。

Xmal代码:

<Window x:Class="ContainerTestWpfApp.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:ContainerTestWpfApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="768" Width="1024"
        WindowStartupLocation="CenterScreen">
    <Grid x:Name="MainGrid">
        <Button x:Name="BtnStackPanel" Content="StackPanel" HorizontalAlignment="Left" Margin="20,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnStackPanel_Click"/>
        <Button x:Name="BtnGrid" Content="Grid" HorizontalAlignment="Left" Margin="120,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnGrid_Click"/>
        <Button x:Name="BtnScrollViewer" Content="ScrollViewer" HorizontalAlignment="Left" Margin="220,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnScrollViewer_Click"/>
        <Button x:Name="BtnWrapPanel" Content="WrapPanel" HorizontalAlignment="Left" Margin="320,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnWrapPanel_Click"/>
        <Button x:Name="BtnCanvas" Content="Canvas" HorizontalAlignment="Left" Margin="420,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnCanvas_Click"/>
        <Button x:Name="BtnUniformGrid" Content="UniformGrid" HorizontalAlignment="Left" Margin="520,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnUniformGrid_Click"/>
        <Button x:Name="BtnDockPanel" Content="DockPanel" HorizontalAlignment="Left" Margin="620,30,0,0" VerticalAlignment="Top" Width="80" Click="BtnDockPanel_Click"/>
        <!-- 容器StackPanel -->
        <StackPanel x:Name="ContainerStackPanel" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600" >

        </StackPanel>
        <!-- 容器Grid -->
        <Grid x:Name="ContainerGrid" Grid.Column="0" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">

        </Grid>
        <!-- 容器ScrollViewer -->
        <ScrollViewer x:Name="ContainerScrollViewer" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">
            <Grid x:Name="SVGrid">
                
            </Grid>
        </ScrollViewer>
        <!-- 容器WrapPanel -->
        <WrapPanel x:Name="ContainerWrapPanel" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">

        </WrapPanel>
        <!-- 容器Canvas -->
        <Canvas x:Name="ContainerCanvas" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">

        </Canvas>
        <!-- 容器UniformGrid -->
        <UniformGrid x:Name="ContainerUniformGrid" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">

        </UniformGrid>
        <!-- 容器DockPanel -->
        <DockPanel x:Name="ContainerDockPanel" HorizontalAlignment="Left" Margin="20,70,0,0" VerticalAlignment="Top" Width="800" Height="600">

        </DockPanel>
        <Image HorizontalAlignment="Left" Height="100" Margin="880,90,0,0" VerticalAlignment="Top" Width="100" Source="/test.png"/>

    </Grid>
</Window>

用于显示容器效果的CSharp代码:

// 用于切换容器显示
this.ContainerStackPanel.Visibility = Visibility.Visible;
this.ContainerGrid.Visibility = Visibility.Collapsed;
this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
this.ContainerCanvas.Visibility = Visibility.Collapsed;
this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
this.ContainerDockPanel.Visibility = Visibility.Collapsed;

2.1 StackPanel

控制代码:

       /// <summary>
       /// 在容器StackPanel中动态创建控件
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void BtnStackPanel_Click(object sender, RoutedEventArgs e)
       {
           ClearAllItems();
           // 用于切换容器显示
           this.ContainerStackPanel.Visibility = Visibility.Visible;
           this.ContainerGrid.Visibility = Visibility.Collapsed;
           this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
           this.ContainerCanvas.Visibility = Visibility.Collapsed;
           this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
           this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
           this.ContainerDockPanel.Visibility = Visibility.Collapsed;

           this.BtnStackPanel.Background = new SolidColorBrush(Colors.Gray);
           this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
           this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
           this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
           this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
           this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

           int numberOfButtons = 10;

           for (int i = 0; i < numberOfButtons; i++)
           {
               // 添加按钮  
               Button button = new()
               {
                   Content = "Button " + i.ToString(), // 设置按钮内容
                   Tag = i,
               };
               button.Click += Button_Click; // 添加点击事件处理程序 
               ContainerStackPanel.Children.Add(button);

               // 添加文本块  
               TextBlock textBlock = new()
               {
                   Text = "TextBlock " + i,// 设置按钮内容
                   Margin = new Thickness(0, 10, 0, 0) // 添加一些外边距
               };
               ContainerStackPanel.Children.Add(textBlock);

               // 获取当前执行程序集的名称  
               string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

               // 构建 URI 来访问嵌入的资源  
               Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

               // 添加图片
               Image image = new()
               {
                   Source = new BitmapImage(uri),
                   Height = 128, // 设置图片高度 
                   Width = 128,  // 设置图片宽度  
                   Margin = new Thickness(0, 10, 0, 0) // 添加一些外边距 
               };
               ContainerStackPanel.Children.Add(image);

               // 添加列表框  
               ListBox listBox = new();
               listBox.Items.Add("Item 1");
               listBox.Items.Add("Item 2");
               listBox.Items.Add("Item 3");
               listBox.Margin = new Thickness(0, 10, 0, 0); // 添加一些外边距  
               ContainerStackPanel.Children.Add(listBox);
           }
       }

执行效果:
在这里插入图片描述

2.2 Grid

这里需要说明一下,因为在创建项目的时候,已经存在一个主Grid了,这个Grid容器需要设置在主Grid内部,为了保证其正常显示,需要在Xmal的代码中对它在主Grid中的网格归属进行定义,不然就不会正常显示了。如上面代码中的这个 Grid.Column="0"属性。
控制代码:

        /// <summary>
        /// 在容器Grid中动态创建控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnGrid_Click(object sender, RoutedEventArgs e)
        {
            ClearAllItems();
            // 用于切换容器显示
            this.ContainerStackPanel.Visibility = Visibility.Collapsed;
            this.ContainerGrid.Visibility = Visibility.Visible;
            this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
            this.ContainerCanvas.Visibility = Visibility.Collapsed;
            this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
            this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
            this.ContainerDockPanel.Visibility = Visibility.Collapsed;

            this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnGrid.Background = new SolidColorBrush(Colors.Gray);
            this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
            this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
            this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

            int numberOfButtons = 10;

            for (int i = 0; i < numberOfButtons; i++)
            {
                RowDefinition rowDef = new RowDefinition
                {
                    Height = new GridLength(130, GridUnitType.Pixel)
                };
                ContainerGrid.RowDefinitions.Add(rowDef);

                // 添加按钮  
                Button button = new()
                {
                    Content = "Button " + i.ToString(), // 设置按钮内容
                    Tag = i,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin=new Thickness(10, 0, 0, 0)
                };
                button.Click += Button_Click; // 添加点击事件处理程序 
                Grid.SetRow(button, i); 
                ContainerGrid.Children.Add(button);

                // 添加文本块  
                TextBlock textBlock = new()
                {
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Text = "TextBlock " + i,// 设置按钮内容
                    Margin = new Thickness(200, 0, 0, 0) // 添加一些外边距
                };
                Grid.SetRow(textBlock, i); 
                ContainerGrid.Children.Add(textBlock);

                // 获取当前执行程序集的名称  
                string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

                // 构建 URI 来访问嵌入的资源  
                Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

                // 添加图片
                Image image = new()
                {
                    Source = new BitmapImage(uri),
                    Height = 128, // 设置图片高度 
                    Width = 128,  // 设置图片宽度  
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(500, 0, 0, 0) // 添加一些外边距 
                };
                Grid.SetRow(image, i); 
                ContainerGrid.Children.Add(image);
            }
        }

执行效果:
在这里插入图片描述

2.3 ScrollViewer

控制代码:

        /// <summary>
        /// 在容器ScrollViewer中动态创建控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnScrollViewer_Click(object sender, RoutedEventArgs e)
        {
            ClearAllItems();
            // 用于切换容器显示
            this.ContainerStackPanel.Visibility = Visibility.Collapsed;
            this.ContainerGrid.Visibility = Visibility.Collapsed;
            this.ContainerScrollViewer.Visibility = Visibility.Visible;
            this.ContainerCanvas.Visibility = Visibility.Collapsed;
            this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
            this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
            this.ContainerDockPanel.Visibility = Visibility.Collapsed;

            this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Gray);
            this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
            this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

            int numberOfButtons = 10;

            for (int i = 0; i < numberOfButtons; i++)
            {
                RowDefinition rowDef = new RowDefinition
                {
                    Height = new GridLength(150, GridUnitType.Pixel)
                };
                SVGrid.RowDefinitions.Add(rowDef);

                SVGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(800, GridUnitType.Pixel) });

                // 添加按钮  
                Button button = new()
                {
                    Content = "Button " + i.ToString(), // 设置按钮内容
                    Tag = i,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(50, 0, 0, 0)
                };
                button.Click += Button_Click; // 添加点击事件处理程序 
                Grid.SetRow(button, i);
                Grid.SetColumn(button, 0);
                SVGrid.Children.Add(button);

                // 添加文本块  
                TextBlock textBlock = new()
                {
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Text = "TextBlock " + i,// 设置按钮内容
                    Margin = new Thickness(200, 0, 0, 0) // 添加一些外边距
                };
                Grid.SetRow(textBlock, i);
                Grid.SetColumn(textBlock, 0);
                SVGrid.Children.Add(textBlock);

                // 获取当前执行程序集的名称  
                string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

                // 构建 URI 来访问嵌入的资源  
                Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

                // 添加图片
                Image image = new()
                {
                    Source = new BitmapImage(uri),
                    Height = 128, // 设置图片高度 
                    Width = 128,  // 设置图片宽度  
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(500, 0, 0, 0) // 添加一些外边距 
                };
                Grid.SetRow(image, i);
                Grid.SetColumn(image, 0);
                SVGrid.Children.Add(image);

                // 生成Rectangle控件
                Rectangle rectangle = new()
                {
                    Width = 750,
                    Height = 140,
                    Stroke = Brushes.Gray,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(20, 0, 0, 0)
                };
                Grid.SetRow(rectangle, i);
                Grid.SetColumn(rectangle, 0);
                SVGrid.Children.Add(rectangle);
            }
        }

执行效果:
在这里插入图片描述

2.4 WrapPanel

控制代码:

        /// <summary>
        /// 在容器WrapPanel中动态创建控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnWrapPanel_Click(object sender, RoutedEventArgs e)
        {
            ClearAllItems();
            // 用于切换容器显示
            this.ContainerStackPanel.Visibility = Visibility.Collapsed;
            this.ContainerGrid.Visibility = Visibility.Collapsed;
            this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
            this.ContainerCanvas.Visibility = Visibility.Collapsed;
            this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
            this.ContainerWrapPanel.Visibility = Visibility.Visible;
            this.ContainerDockPanel.Visibility = Visibility.Collapsed;

            this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
            this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
            this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Gray);
            this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

            int numberOfButtons = 10;

            for (int i = 0; i < numberOfButtons; i++)
            {
                // 添加按钮  
                Button button = new()
                {
                    Content = "Button " + i.ToString(), // 设置按钮内容
                    Tag = i,
                    Width = 80,
                    Height = 50,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(0,0,0,0)
                };
                button.Click += Button_Click; // 添加点击事件处理程序 
                ContainerWrapPanel.Children.Add(button);

                // 添加文本块  
                TextBlock textBlock = new()
                {
                    Text = "TextBlock " + i,// 设置按钮内容
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(0, 0, 0, 0) // 添加一些外边距
                };
                ContainerWrapPanel.Children.Add(textBlock);

                // 获取当前执行程序集的名称  
                string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

                // 构建 URI 来访问嵌入的资源  
                Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

                // 添加图片
                Image image = new()
                {
                    Source = new BitmapImage(uri),
                    Height = 128, // 设置图片高度 
                    Width = 128,  // 设置图片宽度  
                    Margin = new Thickness(0, 0, 0, 0) // 添加一些外边距 
                };
                ContainerWrapPanel.Children.Add(image);

                // 添加列表框  
                ListBox listBox = new();
                listBox.Items.Add("Item 1");
                listBox.Items.Add("Item 2");
                listBox.Items.Add("Item 3");
                listBox.Margin = new Thickness(0, 0, 0, 0); // 添加一些外边距  
                ContainerWrapPanel.Children.Add(listBox);
            }
        }

执行效果:
在这里插入图片描述

2.5 Canvas

控制代码:

        /// <summary>
        /// 在容器Canvas中动态创建控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnCanvas_Click(object sender, RoutedEventArgs e)
        {
            ClearAllItems();
            // 用于切换容器显示
            this.ContainerStackPanel.Visibility = Visibility.Collapsed;
            this.ContainerGrid.Visibility = Visibility.Collapsed;
            this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
            this.ContainerCanvas.Visibility = Visibility.Visible;
            this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
            this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
            this.ContainerDockPanel.Visibility = Visibility.Collapsed;

            this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
            this.BtnCanvas.Background = new SolidColorBrush(Colors.Gray);
            this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

            int numberOfButtons = 10;

            for (int i = 0; i < numberOfButtons; i++)
            {
                // 添加按钮  
                Button button = new()
                {
                    Content = "Button " + i.ToString(), // 设置按钮内容
                    Tag = i,
                    Width = 80,
                    Height = 50,
                    VerticalAlignment = VerticalAlignment.Center
                };
                button.Click += Button_Click; // 添加点击事件处理程序 
                // 设置按钮在 Canvas 上的位置  
                Canvas.SetLeft(button, 10); // 每个按钮间隔 10 像素加上按钮宽度 100 像素  
                Canvas.SetTop(button, i*130);       // 所有按钮都在 Canvas 的顶部开始,距离顶部 10 像素  

                ContainerCanvas.Children.Add(button);

                // 添加文本块  
                TextBlock textBlock = new()
                {
                    Text = "TextBlock " + i,// 设置按钮内容
                    VerticalAlignment = VerticalAlignment.Center
                };
                Canvas.SetLeft(textBlock, 300);  
                Canvas.SetTop(textBlock, i * 130);
                ContainerCanvas.Children.Add(textBlock);

                // 获取当前执行程序集的名称  
                string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

                // 构建 URI 来访问嵌入的资源  
                Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

                // 添加图片
                Image image = new()
                {
                    Source = new BitmapImage(uri),
                    Height = 128, // 设置图片高度 
                    Width = 128,  // 设置图片宽度  
                };
                Canvas.SetLeft(image, 500);
                Canvas.SetTop(image, i * 130);
                ContainerCanvas.Children.Add(image);

                // 添加列表框  
                ListBox listBox = new();
                listBox.Items.Add("Item 1");
                listBox.Items.Add("Item 2");
                listBox.Items.Add("Item 3");
                Canvas.SetLeft(listBox, 700);
                Canvas.SetTop(listBox, i * 130);
                ContainerCanvas.Children.Add(listBox);
            }
        }

执行效果:
在这里插入图片描述

2.6 UniformGrid

控制代码:

        /// <summary>
        /// 在容器UniformGrid中动态创建控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnUniformGrid_Click(object sender, RoutedEventArgs e)
        {
            ClearAllItems();
            // 用于切换容器显示
            this.ContainerStackPanel.Visibility = Visibility.Collapsed;
            this.ContainerGrid.Visibility = Visibility.Collapsed;
            this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
            this.ContainerCanvas.Visibility = Visibility.Collapsed;
            this.ContainerUniformGrid.Visibility = Visibility.Visible;
            this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
            this.ContainerDockPanel.Visibility = Visibility.Collapsed;

            this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnGrid.Background = new SolidColorBrush(Colors.Blue);
            this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
            this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
            this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Gray);
            this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
            this.BtnDockPanel.Background = new SolidColorBrush(Colors.Blue);

            int numberOfButtons = 10;

            for (int i = 0; i < numberOfButtons; i++)
            {
                // 添加按钮  
                Button button = new()
                {
                    Content = "Button " + i.ToString(), // 设置按钮内容
                    Tag = i,
                    Width = 80,
                    Height = 50,
                };
                button.Click += Button_Click; // 添加点击事件处理程序 
                ContainerUniformGrid.Children.Add(button);

                // 添加文本块  
                TextBlock textBlock = new()
                {
                    Text = "TextBlock " + i,// 设置按钮内容
                };
                ContainerUniformGrid.Children.Add(textBlock);

                // 获取当前执行程序集的名称  
                string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

                // 构建 URI 来访问嵌入的资源  
                Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

                // 添加图片
                Image image = new()
                {
                    Source = new BitmapImage(uri),
                    Height = 64, // 设置图片高度 
                    Width = 64,  // 设置图片宽度  
                };

                ContainerUniformGrid.Children.Add(image);

                // 添加列表框  
                ListBox listBox = new();
                listBox.Items.Add("Item 1");
                listBox.Items.Add("Item 2");
                listBox.Items.Add("Item 3");
                ContainerUniformGrid.Children.Add(listBox);
            }
        }

执行效果:
在这里插入图片描述

2.7 DockPanel

这里测试了几种布局,但考虑到多种控件在这个容器中生成,会很混乱,就选择其中一种作为对比实验。
控制代码:

       /// <summary>
       /// 在容器DockPanel中动态创建控件
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void BtnDockPanel_Click(object sender, RoutedEventArgs e)
       {
           ClearAllItems();
           // 用于切换容器显示
           this.ContainerStackPanel.Visibility = Visibility.Collapsed;
           this.ContainerGrid.Visibility = Visibility.Collapsed;
           this.ContainerScrollViewer.Visibility = Visibility.Collapsed;
           this.ContainerCanvas.Visibility = Visibility.Collapsed;
           this.ContainerUniformGrid.Visibility = Visibility.Collapsed;
           this.ContainerWrapPanel.Visibility = Visibility.Collapsed;
           this.ContainerDockPanel.Visibility = Visibility.Visible;

           this.BtnStackPanel.Background = new SolidColorBrush(Colors.Blue);
           this.BtnGrid.Background = new SolidColorBrush(Colors.Blue);
           this.BtnScrollViewer.Background = new SolidColorBrush(Colors.Blue);
           this.BtnCanvas.Background = new SolidColorBrush(Colors.Blue);
           this.BtnUniformGrid.Background = new SolidColorBrush(Colors.Blue);
           this.BtnWrapPanel.Background = new SolidColorBrush(Colors.Blue);
           this.BtnDockPanel.Background = new SolidColorBrush(Colors.Gray);

           int numberOfButtons = 10;

           for (int i = 0; i < numberOfButtons; i++)
           {
               // 添加按钮  
               Button button = new()
               {
                   Content = "Button " + i.ToString(), // 设置按钮内容
                   Tag = i,
                   Width = 80,
                   Height = 50,
               };
               button.Click += Button_Click; // 添加点击事件处理程序 
               DockPanel.SetDock(button, Dock.Top);
               ContainerDockPanel.Children.Add(button);

               // 添加文本块  
               TextBlock textBlock = new()
               {
                   Text = "TextBlock " + i,// 设置按钮内容
               };
               DockPanel.SetDock(textBlock, Dock.Left);
               ContainerDockPanel.Children.Add(textBlock);

               // 获取当前执行程序集的名称  
               string? assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

               // 构建 URI 来访问嵌入的资源  
               Uri uri = new($"pack://application:,,,/{assemblyName};component/test.png");

               // 添加图片
               Image image = new()
               {
                   Source = new BitmapImage(uri),
                   Height = 64, // 设置图片高度 
                   Width = 64,  // 设置图片宽度  
               };
               DockPanel.SetDock(textBlock, Dock.Top);
               ContainerDockPanel.Children.Add(image);

                添加列表框  
               //ListBox listBox = new();
               //listBox.Items.Add("Item 1");
               //listBox.Items.Add("Item 2");
               //listBox.Items.Add("Item 3");
               //DockPanel.SetDock(textBlock, Dock.Top);
               //ContainerDockPanel.Children.Add(listBox);
           }
       }

执行效果:
在这里插入图片描述

3 总结

从上面代码实现的效果来看,对于动态生成的控件可以分成两种可能性:
一是固定数量和种类的控件生成;
二是不固定数量和种类的控件生成。

从上面的实现效果可以明显看出,不固定数量的控件生成很容易超出容器范围,从而无法看到,那这里能够胜任此功能的只有使用ScrollViewer和其他容器的组合实现,效果是比较好的。

如下:
在这里插入图片描述
wpf中控件的灵活组合,还有很多值得深入学习的地方,在使用的过程中,逐渐进步。

;