【WPF】03 动态生成控件

说明

今天记录一篇关于动态生成控件的方法,也是反复查了一些资料,逐步完善成自己需要的方法,感觉还是比较好用的。通过这个需求,在网上也找了一些资料,发现了一个开源图形UI组件HandyControl,觉得比较好,虽然暂时还没怎么用上,但安装完成后,确实美化了原来wpf的一些控件形状。

gtiee地址:https://gitee.com/handyorg/HandyControl

Nuget管理包安装

编码实现

直接上代码说明了,文章就不详细描述什么原理什么过程的,将来需要直接问大模型就好了。

动态添加RowDefinitions和ColumnDefinitions

首先,在XAML中,定义一个空的Grid,然后在代码后台(C#)中动态地向这个Grid添加RowDefinitions和ColumnDefinitions,以及相应的子控件(如TextBox)。

XAML部分:

xml 复制代码
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="20,10,0,0" Height="380" Width="750" HorizontalAlignment="Left" VerticalAlignment="Top">
    <Grid x:Name="myDynamicGrid" Margin="5,5,5,5">

        <!-- 初始时不添加任何行,通过代码动态添加 -->

    </Grid>
</ScrollViewer>

C#部分:

生成控件的部分

csharp 复制代码
/// <summary>
/// 动态生成控件
/// </summary>
private void GenerateControls(int iRowsIndex)
{
    for (int i = 0; i < iRowsIndex; i++)
    {
        RowDefinition rowDef = new RowDefinition
        {
            Height = new GridLength(50, GridUnitType.Pixel)
        };
        myDynamicGrid.RowDefinitions.Add(rowDef);

        myDynamicGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(750, GridUnitType.Pixel) });
        // 添加TextBlock
        TextBlock textBlock = new TextBlock
        {
            Text = "我的TextBlock",
            VerticalAlignment = VerticalAlignment.Top,
            HorizontalAlignment = HorizontalAlignment.Left,
            Margin = new Thickness(0,5,0,0)
        };
        Grid.SetRow(textBlock , i);
        Grid.SetColumn(textBlock , 0);
        myDynamicGrid.Children.Add(textBlock );

        // 添加TextBox
        //这里因为安装了HandyControl,所以在选择相关控件的时候,需要做区分,控件对象前增加命名空间索引
        System.Windows.Controls.TextBox textBoxNum = new System.Windows.Controls.TextBox
        {
            Text = "我的TextBox",
            TextAlignment = TextAlignment.Center,
            VerticalAlignment = VerticalAlignment.Top,
            HorizontalAlignment = HorizontalAlignment.Left,
            Background = new SolidColorBrush(Colors.LightGray),
            Margin = new Thickness(520, 0, 0, 0)
        };
        Grid.SetRow(textBoxNum, i);
        Grid.SetColumn(textBoxNum, 0);
        myDynamicGrid.Children.Add(textBoxNum);
		
		// 生成32x32的小图
        string imagePath = "/test.png";
        Image image = new Image
        {
            Height = 30,
            Width = 30,
            Tag = i,
            VerticalAlignment= VerticalAlignment.Top,
            HorizontalAlignment= HorizontalAlignment.Left,
            Source = new BitmapImage(new Uri(imagePath, UriKind.Relative)),
            Margin = new Thickness(600, 0, 0, 0)

        };
        // 图片事件
        image.MouseUp += DynamicImage_MouseUp;
        Grid.SetRow(image, i);
        Grid.SetColumn(image, 0); 
        myDynamicGrid.Children.Add(image);

		// 生成label控件
		Label label = new Label
		{
		    Content = "我的Label",
		    Width = 680, 
		    HorizontalAlignment = HorizontalAlignment.Left,
		    VerticalAlignment = VerticalAlignment.Top,
		    Margin= new Thickness(5, 0, 0, 0),
		    Height = 30,
		    TabIndex = i,
		    HorizontalContentAlignment = HorizontalAlignment.Left,
		    VerticalContentAlignment = VerticalAlignment.Center,
		    FontSize = 14
		};
		Grid.SetRow(label, i);
		Grid.SetColumn(label, 0);
		myDynamicGrid.Children.Add(label);
		
		// 生成Button控件
		Button button = new Button
		{
		    Content = "我的Button",
		    Width = 30,
		    Height = 30,
		    Tag = i,
		    TabIndex= i,
		    VerticalAlignment = VerticalAlignment.Top,
		    HorizontalAlignment = HorizontalAlignment.Right,
		    Background = new SolidColorBrush(Colors.LightGray),
		    BorderBrush = new SolidColorBrush(Colors.LightGray),
		    Margin = new Thickness(0, 0, 70, 0)
		};
		buttons.Add(button);
		// 按钮事件
		button.Click += (sender, e) => ToggleListBoxes(button.TabIndex);
		Grid.SetRow(button, i);
		Grid.SetColumn(button, 0);
		myDynamicGrid.Children.Add(button);
		
		// 生成List控件
		ListBox listBox = new ListBox
		{
		    Name = $"ListBox{i}",
		    Visibility = Visibility.Visible,
		    Width = 680,
		    TabIndex = (int)i,
		    VerticalAlignment = VerticalAlignment.Top,
		    HorizontalAlignment = HorizontalAlignment.Left,
		    BorderBrush = new SolidColorBrush(Colors.White),
		    Margin = new Thickness(5, 30, 0, 0)
		};
		// ListBox 选择变更事件
		listBox.SelectionChanged += ListBox_SelectionChanged; // 可选:为ListBox生成选择变更事件处理器 
		listBoxes.Add(listBox);
		Grid.SetRow(listBox, i);
		Grid.SetColumn(listBox, 0);
		myDynamicGrid.Children.Add(listBox);

        iRows++;
    }

    if (iRows> 0)
    {
        // 这里执行其他相关操作
    }
}

相关参考事件,来自于大模型的生成代码。

csharp 复制代码
/// <summary>
/// 动态图片控件的鼠标抬起事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DynamicImage_MouseUp(object sender, MouseButtonEventArgs e)
{
    //throw new NotImplementedException();
    Image mouseUP = sender as Image;
    if (mouseUP != null)
    {
        int imgIndex = (int)mouseUP.Tag;
        for (int i = imgIndex; i < iRows; i++)
        {
            strBarcode[i] = strBarcode[i + 1];
            strProName[i] = strProName[i + 1];
            strBat[i] = strBat[i + 1];
            strNum[i] = strNum[i + 1];
        }
        // 删除生成控件
        DeleteControls(iRows);
        // 删除grid容器的所有行
        myDynamicGrid.RowDefinitions.RemoveRange(0, iDetailsRows);
        // 整体行数减一
        iRows--;
        // 临时将全局的行数复制给变量iRowsAdd 
        int iRowsAdd = iDetailsRows;
        
        if (iReAddDetails == 0)
        {
            // 其他操作
        }
        else
        {
            iRows = 0;
        }
        // 删除一条数据后再次生成控件
        GenerateControls(iRowsAdd);
    }
}

/// <summary>
/// 删除动态控件
/// </summary>
private void DeleteControls(int rowsToDelete)
{
    for (int i = InDetails.Children.Count - 1; i >= 0; i--)
    {
        UIElement child = InDetails.Children[i];
        for (int j = 0; j < rowsToDelete; j++)
        {
            if (Grid.GetRow(child) == j)
            {
                InDetails.Children.Remove(child);
            }
        }
    }
}
/// <summary>
/// 按钮状态显示事件
/// </summary>
/// <param name="selectedIndex"></param>
private void ToggleListBoxes(int selectedIndex)
{
    foreach (var button in buttons)
    {
        button.Content = button == buttons[selectedIndex] ? "▼" : "▲";
    }
}

/// <summary>
/// ListBox事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox listBox = sender as ListBox;
    if (listBox != null && listBox.SelectedItem != null)
    {
        string listBoxName = listBox.Name;
        string selectedItem = listBox.SelectedItem.ToString();
        char[] delimiters = { ':' };
        string[] parts = selectedItem.Split(delimiters, StringSplitOptions.None);

        if (parts.Length > 1)
        {
            strInputPostionRet = parts[1]; // 符号后面的内容  
            // 处理选中项  
            System.Windows.MessageBox.Show($"{strInputPostionRet}");
        }
        else
        {
            Console.WriteLine("No content after delimiter.");
        }
    }
}

以上就是 动态添加RowDefinitions和ColumnDefinitions的方式实现动态生成控件的方法,这种方式比较简单,也容易实现。 还有其他推荐方法,虽然没有尝试,但这里也写出来,留待以后参考。

使用ItemsControl和DataTemplate

ItemsControl是一个强大的控件,它可以用来显示一个集合中的项,并且每个项都可以通过DataTemplate来定义其呈现方式。你可以将ItemsControl的ItemsPanel设置为Grid,但通常我们会使用UniformGrid(如果行和列数量相同且自动分配)或保持默认的StackPanel/WrapPanel等,并通过DataTemplate来定义每个项的布局,间接实现类似Grid的效果。

然而,如果你确实需要一个标准的Grid布局,并且想要动态控制行和列,你可能需要结合使用ItemsControl和自定义的Panel或者通过代码动态添加Grid的RowDefinitions和ColumnDefinitions。

使用MVVM模式

在更复杂的应用程序中,你可能会想使用MVVM(Model-View-ViewModel)模式来管理你的UI逻辑。在这种情况下,你可以在ViewModel中定义一个集合,该集合表示你想要在Grid中显示的数据项。然后,在View(XAML)中,你可以使用ItemsControl绑定到这个集合,并通过DataTemplate定义每个项的布局。虽然这种方法不直接在XAML中定义Grid的行和列,但它提供了一种更加灵活和可维护的方式来管理动态内容。

相关推荐
晚安苏州8 小时前
WPF DataTemplate 数据模板
wpf
甜甜不吃芥末1 天前
WPF依赖属性详解
wpf
Hat_man_1 天前
WPF制作图片闪烁的自定义控件
wpf
晚安苏州3 天前
WPF Binding 绑定
wpf·wpf binding·wpf 绑定
wangnaisheng3 天前
【WPF】RenderTargetBitmap的使用
wpf
dotent·3 天前
WPF 完美解决改变指示灯的颜色
wpf
orangapple5 天前
WPF 用Vlc.DotNet.Wpf实现视频播放、停止、暂停功能
wpf·音视频
ysdysyn5 天前
wpf mvvm 数据绑定数据(按钮文字表头都可以),根据长度进行换行,并把换行的文字居中
c#·wpf·mvvm
orangapple5 天前
WPF 使用LibVLCSharp.WPF实现视频播放、停止、暂停功能
wpf
晚安苏州5 天前
WPF ControlTemplate 控件模板
wpf