• 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 ListViewEx
        public class ListViewEx : ListView
        {
            #region 内部属性
            /// 
            /// 存放单元格控件
            /// 
            List _CellControls = new List();
            /// 
            /// 界面是否发生变化
            /// 
            bool IsViewChanged { get; set; }
            #endregion
    
            #region 方法
            /// 
            /// 构造函数
            /// 
            public ListViewEx()
            {
                #region 初始化
                #endregion
    
                #region 事件
                this.ColumnReordered += ColumnWidthChangedHandler;
                this.ColumnWidthChanged += ColumnWidthChangedHandler;
                #endregion
            }
    
            /// 
            /// 添加控件
            /// 
            /// 
            /// 
            /// 
            /// 
            /// 
            public T Add(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;
            }
    
            /// 
            /// 设置行高度
            /// 
            /// 
            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;
            }
            /// 
            /// 显示控件到目标单元格
            /// 
            /// 
            /// 
            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);
            }
    
            /// 
            /// 显示单元格控件
            /// 
            /// 
            /// 
            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];
                #endregion
                return 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;
                }
                #endregion
                base.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
  • 相关阅读:
    软件设计师 下午题第6题
    Github使用指南
    kotlin flow sample的用法
    LeetCode 75. 颜色分类
    HCIA 笔记(1)
    【C++】平衡二叉搜索树的模拟实现
    【pygame】01 pygame制作游戏的最小系统
    前端try和catch
    matlab分岔图绘制
    安装Redis
  • 原文地址:https://blog.csdn.net/u014161864/article/details/139770733