C#ListView的单元格支持添加基本及自定义任意控件

功能说明

使用ListView时,希望可以在单元格显示图片或其他控件,发现原生的ListView不支持,于是通过拓展,实现ListView可以显示任意控件的功能,效果如下:
在这里插入图片描述

实现方法

本来想着在单元格里面实现控件的自绘的,但是没找到办法,最后是通过在单元格的表面显示对应控件的,浮于表面达到目的。
实现要点如下:

  • ListView需要设置OwnerDraw=true,并重载自绘函数OnDrawColumnHeaderOnDrawItemOnDrawSubItem
  • 支持按单元格添加对应的控件,其Parent设置为列表ListView
  • 列表界面调整后,包括大小、列表头、滚动等,需重新绘制单元格的控件

实现源码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace MyListView.Ui
{#region ListViewExpublic class ListViewEx : ListView{#region 内部属性/// <summary>/// 存放单元格控件/// </summary>List<Control> _CellControls = new List<Control>();/// <summary>/// 界面是否发生变化/// </summary>bool IsViewChanged { get; set; }#endregion#region 方法/// <summary>/// 构造函数/// </summary>public ListViewEx(){#region 初始化#endregion#region 事件this.ColumnReordered += ColumnWidthChangedHandler;this.ColumnWidthChanged += ColumnWidthChangedHandler;#endregion}/// <summary>/// 添加控件/// </summary>/// <typeparam name="T"></typeparam>/// <param name="row"></param>/// <param name="col"></param>/// <param name="c"></param>/// <returns></returns>public T Add<T>(int row, int col, T c) where T : Control{if(row >= this.Items.Count || col >= this.Columns.Count){return null;}var index = (row * this.Columns.Count) + col;for (var i = _CellControls.Count; i <= index; i++){_CellControls.Add(null);}var oc = _CellControls[index];if (oc != null){oc.Dispose();}OwnerDraw = true;IsViewChanged = true;c.Parent = this;_CellControls[index] = c;return c;}/// <summary>/// 设置行高度/// </summary>/// <param name="height"></param>public void SetItemHeight(int height){if(this.SmallImageList == null){this.SmallImageList = new ImageList();}this.SmallImageList.ImageSize = new Size(1, height);}#endregion#region 内部函数void ColumnWidthChangedHandler(object s, EventArgs e){IsViewChanged = true;}/// <summary>/// 显示控件到目标单元格/// </summary>/// <param name="c"></param>/// <param name="item"></param>void ShowCellControl(Control c, ListViewItem.ListViewSubItem item){int margin = 2;c.Text = item.Text;c.Visible = true;c.Bounds = new Rectangle(item.Bounds.X + margin,item.Bounds.Top + margin,item.Bounds.Width - 2 * margin,item.Bounds.Height - 2 * margin);}/// <summary>/// 显示单元格控件/// </summary>/// <param name="e"></param>/// <returns></returns>Control GetCellControl(DrawListViewSubItemEventArgs e){Control c = null;#region 获取控件var index = (e.ItemIndex * this.Columns.Count) + e.ColumnIndex;if (index >= _CellControls.Count){return null;}c = _CellControls[index];#endregionreturn c;}protected override void WndProc(ref Message m){#region 事件定义const int WM_SIZE = 0x0005;const int WM_PAINT = 0x000F;const int WM_HSCROLL = 0x114;const int WM_VSCROLL = 0x115;const int WM_MOUSEWHEEL = 0x020A;#endregion#region 重绘显示控件if (m.Msg == WM_PAINT && IsViewChanged){if(this.Columns.Count > 0){for (var i = 0; i < _CellControls.Count; i++){var cell_control = _CellControls[i];if (cell_control == null){continue;}cell_control.Visible = false;var row = i / this.Columns.Count;var col = i % this.Columns.Count;if(row >= Items.Count || col >= this.Columns.Count){continue;}var item = this.Items[row];if(item.Bounds.Y < 0 || item.Bounds.Y >= this.Height){continue;}if(item.SubItems[col].Bounds.X < 0 || item.SubItems[col].Bounds.X >= this.Width){continue;}ShowCellControl(cell_control, item.SubItems[col]);}IsViewChanged = false;}}else if(m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_SIZE){IsViewChanged = true;}#endregionbase.WndProc(ref m);}protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e){e.DrawDefault = true;}protected override void OnDrawItem(DrawListViewItemEventArgs e){// 已经在OnDrawSubItem处理过了// e.DrawText(TextFormatFlags.Default);}protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e){if(GetCellControl(e) != null){return;}else{e.DrawDefault = true;}}#endregion}#endregion
}

测试代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace MyListView
{public partial class Form1 : Form{#region 函数public Form1(){#region 布局初始化InitializeComponent();var lv = new Ui.ListViewEx(){Dock = DockStyle.Fill,View = View.Details,GridLines = true,};this.Controls.Add(lv);var headers = new string[] { "序号", "名称", "年龄", "住址", "荣誉", "岗位", "头像" };foreach(var v in headers){lv.Columns.Add(v, 100, HorizontalAlignment.Center);}lv.SetItemHeight(40);for(var i=0; i<50; i++){var lvi = lv.Items.Add($"数据{i + 1}");for(var j=1; j<lv.Columns.Count; j++){lvi.SubItems.Add($"数据{i + 1}-{j}");switch(j){case 1:lv.Add(i, j, new Label());break;case 2:lv.Add(i, j, new Button());break;case 3:lv.Add(i, j, new TextBox(){Font = new Font("宋体", 18)});break;case 4:lv.Add(i, j, new ComboBox(){Font = new Font("宋体", 18)});break;case 6:{var pic = lv.Add(i, j, new PictureBox());pic.Image = LoadImage($"logo{i%7}.jpg");pic.SizeMode = PictureBoxSizeMode.StretchImage;}break;}}}#endregion}Image LoadImage(string name){var file = Path.GetFullPath(Path.Combine(@"..\..\Data\IMG", name));if(!File.Exists(file)){return null;}return Image.FromFile(file);}#endregion}
}

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

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

相关文章

20240621在飞凌的OK3588-C开发板的Buildroot系统中集成i2ctool工具

20240621在飞凌的OK3588-C开发板中打开i2ctool工具 2024/6/21 17:44 默认继承的i2c工具&#xff1a; rootrk3588-buildroot:/# rootrk3588-buildroot:/# i2c i2c-stub-from-dump i2cdump i2cset i2cdetect i2cget i2ctransfer rootrk3588-…

史上最全的整合Harbor安装教程,哈哈哈哈

一、安装docker 下载地址&#xff1a;https://download.docker.com/linux/static/stable/x86_64/docker-23.0.4.tgz 1.1 解压二进制包 wget https://download.docker.com/linux/static/stable/x86_64/docker-23.0.4.tgz tar zxvf docker-23.0.4.tgz mv docker/* /usr/bin1.2…

Flutter 实现软鼠标

文章目录 前言一、如何实现&#xff1f;1、记录鼠标偏移2、MouseRegion获取偏移3、Transform移动图标 二、完整代码三、使用示例总结 前言 flutter在嵌入式系统中运行时&#xff0c;有可能遇到drm鼠标无法使用的情况&#xff0c;但鼠标事件却可以正常接收&#xff0c;此时如果…

用Vite基于Vue3+ts+DataV+ECharts开发数据可视化大屏,即能快速开发又能保证屏幕适配

数据可视化大屏 基于 Vue3、Typescript、DataV、ECharts5 框架的大数据可视化&#xff08;大屏展示&#xff09;开发。此项目vue3实现界面&#xff0c;采用新版动态屏幕适配方案&#xff0c;全局渲染组件封装&#xff0c;支持数据动态刷新渲染、内部DataV、ECharts图表都支持自…

SQLite扩展插件终极集合

作为一个嵌入式数据库引擎&#xff0c;SQLite 与其他数据库管理系统相比&#xff0c;缺少了一些功能。不过 SQLite 提供了一个扩展机制&#xff0c;因此我们可以在网络上找到大量的 SQLite 插件。 今天我们介绍的这个插件叫做 sqlean&#xff0c;它打包了许多流行的 SQLite 扩…

消息队列kafka中间件详解:案例解析(第10天)

系列文章目录 1- 消息队列&#xff08;熟悉&#xff09;2- Kafka的基本介绍&#xff08;掌握架构&#xff0c;其他了解&#xff09;3- Kafka的相关使用&#xff08;掌握kafka常用shell命令&#xff09;4- Kafka的Python API的操作&#xff08;熟悉&#xff09; 文章目录 系列文…

kafka的基本模型

kafka官网 线程和线程之间的数据交互 在jvm里不同的线程有自己的栈内存&#xff0c;但彼此之间交互可以在共享的内存中进行&#xff0c;即堆内存&#xff0c;堆内存会将这些消息放到队列中&#xff0c;具体实现jvm见&#xff0c;栈内存各自维护&#xff0c;堆内存大家共享 进…

微信小程序UI组件库合集

文章目录 前言参考地址推荐组件库1.官方WeUI&#xff08;建议使用☆☆☆☆&#xff09;2.ColorUI&#xff08;广告很多&#xff0c;不建议使用&#xff09;3.vantUI又名&#xff1a;ZanUI&#xff08;操作简单&#xff0c;建议使用☆☆☆☆&#xff09;4.MinUI&#xff08;比较…

STM32---SPI通信协议(小白入、含源码)

写在前面&#xff1a;在单片机的学习过程中&#xff0c;各种通信协议的学习是必不可少的&#xff0c;在前面我们学习了串口通信、IIC通信&#xff0c;本节我们来认识一下SPI通信协议。包括其SPI基本概念、NORFLASH芯片的介绍以及相关的例程实验。 目录 一、SPI介绍 1.1什么是…

【小白专用24.6.18】C# SqlSugar:连接数据库实现简单的,增、删、改、查

【小白专用 已验证24.6.18】C# SqlSugar操作MySQL数据库实现增删改查-CSDN博客 通过NuGet包管理器搜索SqlSugar&#xff08;MySql还要安装MySql.Data、Newtonsoft.Json&#xff09;包并安装 SqlSugarClient db new SqlSugarClient(new ConnectionConfig(){ConnectionString …

中国信通院专访镜舟科技:开源商业化走了多远?

据《2023 中国开源发展蓝皮书》显示&#xff0c;随着数字化转型的深入&#xff0c;开源生态在去年快速发展&#xff0c;开源商业化的模式也逐渐成型。镜舟科技作为开源商业化的先行者&#xff0c;也在技术创新和商业拓展中稳步增长。 日前&#xff0c;中国信息通信研究院&…

Python基础教程(二十八):pip模块

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

NGINX_十二 nginx 地址重写 rewrite

十二 nginx 地址重写 rewrite 1 什么是Rewrite Rewrite对称URL Rewrite&#xff0c;即URL重写&#xff0c;就是把传入Web的请求重定向到其他URL的过程。URL Rewrite最常见的应用是URL伪静态化&#xff0c;是将动态页面显示为静态页面方式的一种技术。比如 http://www.123.com…

2024097期传足14场胜负前瞻

2024097期售止时间为6月22日&#xff08;周六&#xff09;20点30分&#xff0c;敬请留意&#xff1a; 本期14场由欧洲杯、美洲杯、美职联组成&#xff0c;1.5以下赔率2场&#xff0c;1.5-2.0赔率10场&#xff0c;其他场次是平半盘、平盘。本期14场难度中等。以下为基础盘前瞻&a…

docker将容器打包提交为镜像,再打包成tar包

将容器打包成镜像可以通过以下步骤来实现。这里以 Docker 为例&#xff0c;假设你已经安装了 Docker 并且有一个正在运行的容器。 1. 找到正在运行的容器 首先&#xff0c;你需要找到你想要打包成镜像的容器的 ID 或者名字。可以使用以下命令查看所有正在运行的容器&#xff…

【0-1系列】从0-1快速了解搜索引擎是什么以及怎么用(上)

友情链接 社区开发版安装部署与使用教程社区版家族V2024.5版本更新说明 START>>1.快速了解搜索引擎 什么是搜索引擎数据库 搜索引擎数据库是一类专门用于数据内容搜索的NoSQL数据库&#xff0c;是非结构化大数据处理分析领域中重要的基础支撑软件。 伴随互联网、移动…

DSP应用市场的大蛋糕,国产厂商能吃下多少?

DSP是数字信号处理器&#xff08;Digital Signal Processor&#xff09;的简称&#xff0c;是一种专门用于高速数学运算的微处理器。DSP能够快速且准确地处理数字信号&#xff0c;同时具备可编程和低功耗等特点&#xff0c;如今在各个领域发挥着越来越重要的作用。 &#xff08…

【目标检测】图解 DETR 系统框图

简略版本 Backbone&#xff1a;CNN backbone 学习图像的 2D 特征Positional Encoding&#xff1a;将 2D 特征展平&#xff0c;并对其使用位置编码&#xff08;positional encoding&#xff09;Encoder&#xff1a;经过 Transformer 的 encoderDecoder&#xff1a;encoder 的输出…

spring-gateway配置说明

在开发过程中遇到的一些配置问题&#xff0c;记录下来以供参考 spring-gateway版本是2.2.9-release,使用的spring cloud dependence 是 Hoxton.SR12 在依赖eureka 服务发现并自动将发现服务器加入到router中的时候&#xff0c;需要指定对应的服务进行添加&#xff0c;根据文档…

技术分享 | 基于 API 解析的 Python 爬虫

最近各大高校纷纷翻拍 Coincidence 抖肩舞&#xff0c;需要对这种流行现象进行数据分析。数据分析首先需要有数据&#xff0c;本文介绍了爬取 B 站相应视频的评论、弹幕、播放量、点赞数等数据的方法。爬虫有多种实现方法&#xff0c;大型的网络爬虫多基于成熟的爬虫框架&#…