【WPF】03 动态生成控件

news2024/9/24 7:19:20

在这里插入图片描述

在这里插入图片描述

说明

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

Nuget管理包安装
在这里插入图片描述

编码实现

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

动态添加RowDefinitions和ColumnDefinitions

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

XAML部分:

<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#部分:

生成控件的部分

/// <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)
    {
        // 这里执行其他相关操作
    }
}

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

/// <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的行和列,但它提供了一种更加灵活和可维护的方式来管理动态内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2159776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

统信服务器操作系统【Cron定时任务服务】

Cron定时任务服务服务介绍、服务管理、服务配置 文章目录 一、功能概述二、功能介绍1. Cron 服务管理2.Cron 服务管理3.Cron 服务配置run-parts一、功能概述 cron是一个可以用来根据时间、日期、月份、星期的组合来 调度对周期性任务执行的守护进程。利用 cron 所提供的功能,可…

分布式环境中,接口超时重试带来的的幂等问题如何解决?

目录标题 幂等不能解决接口超时吗&#xff1f;幂等的重要性什么是幂等?为什么需要幂等?接口超时了&#xff0c;到底如何处理&#xff1f; 如何设计幂等?幂等设计的基本流程实现幂等的8种方案1.selectinsert主键/唯一索引冲突&#xff08;常用&#xff09;2.直接insert 主键…

【Oauth2整合gateway网关实现微服务单点登录】

文章目录 一.什么是单点登录&#xff1f;二.Oauth2整合网关实现微服务单点登录三.时序图四.代码实现思路1.基于OAuth2独立一个认证中心服务出来2.网关微服务3产品微服务4.订单微服务5.开始测试单点登录 一.什么是单点登录&#xff1f; 单点登录&#xff08;Single Sign On&…

sql语法学习:关键点和详细解释

学习SQL语法是掌握数据库操作的基础。以下是SQL语法的一些关键点和详细解释&#xff1a; 1. SQL基础 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系型数据库的标准语言。它主要包括以下几个部分&#xff1a; 数据定义语言&#xff08;DDL&…

全栈开发(五):初始化前端项目(nuxt3+vue3+element-plus)+前端代理

1.初始化前端项目 Nuxt3:搭建项目_nuxt3 项目搭建-CSDN博客、 2.配置代理 nuxt.config.ts // https://nuxt.com/docs/api/configuration/nuxt-configexport default defineNuxtConfig({devtools: { enabled: true },modules: ["element-plus/nuxt", "pinia/n…

智能PPT行业赋能用户画像

智能PPT市场在巨大的需求前景下&#xff0c;已吸引一批不同类型的玩家投入参与竞争。从参与玩家类型来看&#xff0c;不乏各类与PPT创作有关的上下游企业逐步向智能PPT赛道转型进入&#xff0c;也包括顺应生成式AI技术热潮所推出的创业企业玩家。当前&#xff0c;智能PPT赛道发…

在虚幻引擎中创建毛发/头发

在虚幻引擎中创建毛发/头发 , 首先开启两个插件 Groom 和 Alembic Groom Importer 打开蒙皮缓存 导出人物模型 将人物导入Blender , 选择需要种植头发的点 指定并选择 点击毛发 这里变成爆炸头了 , 把数量和长度调一下 切换到梳子模式 调整发型 导出为abc , 文件路径不…

基于opencv的车牌检测和识别系统(代码+教程)

车牌检测与识别技术详解 车牌检测和识别&#xff08;License Plate Recognition, LPR&#xff09;是一项重要的计算机视觉任务&#xff0c;它在交通管理、安全监控以及智能门禁系统等多个领域都有着广泛的应用。随着深度学习技术的发展&#xff0c;LPR系统的准确性和鲁棒性得到…

【算法业务】基于Multi-Armed Bandits的个性化push文案自动优选算法实践

1. 背景介绍 该工作属于多年之前的用户增长算法业务项目。在个性化push中&#xff0c;文案扮演非常重要的角色&#xff0c;是用户与push的商品之间的桥梁&#xff0c;文案是用户最直接能感知的信息。应该说在push产品信息之外&#xff0c;最重要的就是文案&#xff0c;直接能…

机器学习 | Scikit Learn中的普通最小二乘法和岭回归

在统计建模中&#xff0c;普通最小二乘法&#xff08;OLS&#xff09;和岭回归是两种广泛使用的线性回归分析技术。OLS是一种传统的方法&#xff0c;它通过最小化预测值和实际值之间的平方误差之和来找到数据的最佳拟合线。然而&#xff0c;OLS可以遭受高方差和过拟合时&#x…

Unreal Engine 5 C++: 插件编写03 | MessageDialog

在虚幻引擎编辑器中编写Warning弹窗 准备工作 FMessageDialog These functions open a message dialog and display the specified informations there. EAppReturnType::Type 是 Unreal Engine 中用于表示应用程序对话框&#xff08;如消息对话框&#xff09;返回结果的枚举…

vue.js 展示树状结构数据,动态生成 HTML 内容

展示树状结构数据&#xff1a; 从 jsonData 读取树状结构的 JSON 数据&#xff0c;将其解析并生成 HTML 列表来展示。树状结构数据根据 id 和 label 属性组织&#xff0c;节点可以包含子节点 children。 展示评级信息&#xff1a; 从预定义的表单字段 form 中读取 arRateFlag 和…

GS-SLAM论文阅读笔记--GLC-SLAM

前言 最近GS-SLAM回环检测的工作已经逐步发展了&#xff0c;看一下这篇新文章。 文章目录 前言1.背景介绍2.关键内容2.1 tracking2.2 local mapping2.3 Loop Closing2.4总体流程 3.文章贡献 1.背景介绍 现有的基于3dgs的SLAM方法往往存在累积的跟踪误差和地图漂移&#xff0c…

三菱FX5U CPU模块的初始化“(格式化PLC)”

1、连接FX5U PLC 1、使用以太网电缆连接计算机与CPU模块。 2、从工程工具的菜单选择[在线]中[当前连接目标]。 3、在“简易连接目标设置 Connection”画面中&#xff0c;在与CPU模块的直接连接方法中选择[以太网]。点击[通信测试]按钮&#xff0c;确认能否与CPU模块连接。 FX5…

小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(1)数字电路基础

目录 一、信号特征 二、组合逻辑电路和时序逻辑电路 1、组合逻辑电路 2、时序逻辑线路 三、信号转换 1、数字集成电路的分类 2、常用电平接口技术 四、可编程逻辑器件 flechazohttps://www.zhihu.com/people/jiu_sheng 小柴冲刺嵌入式系统设计师系列总目录https://blo…

[vulnhub] Prime 1

https://www.vulnhub.com/entry/prime-1,358/ 主机发现端口扫描 探测存活主机&#xff0c;137是靶机 nmap -sP 192.168.75.0/24 // Starting Nmap 7.93 ( https://nmap.org ) at 2024-09-22 16:25 CST Nmap scan report for 192.168.75.1 Host is up (…

Rust - 字符串:str 与 String

在其他语言中&#xff0c;字符串通常都会比较简单&#xff0c;例如 “hello, world” 就是字符串章节的几乎全部内容了。 但是Rust中的字符串与其他语言有所不同&#xff0c;若带着其他语言的习惯来学习Rust字符串&#xff0c;将会波折不断。 所以最好先忘记脑中已有的关于字…

MMD模型一键完美导入UE5-VRM4U插件方案(一)

1、下载pmx模型 1、去模之屋官网下载MMD模型,模之屋 2、下载完成得到pmx和Texture文件 2、下载并启用VRM4U插件 1、下载VRM4U插件, VRM4U,点击Latest下载对应引擎版本 2、将插件放到Plugins目录,然后

GB28181语音对讲协议详解

GB28181-2016语音对讲流程如下图1所示&#xff1a; 图1.语音对讲流程。 其中, 信令 1 、2 、 3 、 4 为语音广播通知、 语音广播应答消息流程; 信令 5 、 1 2 、 1 3 、 1 4 、 1 5 、 1 6 为 S I P 服务器接收到客户端的呼叫请求通过 B 2 B UA 代理方式建立语音流接收者与媒…

DevExpress WPF中文教程:如何解决行焦点、选择的常见问题?

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…