C#ListView数据绑定组件

一、ListView组件

1.1 常用属性

1.View 设置显示模式

  • Details(详细视图):表格形式展示多列数据,支持自定义列宽、对齐方式。
  • List(列表视图):单列垂直排列,适合简单选项。
  • LargeIcon/SmallIcon(大/小图标):以图标形式展示,支持自定义图标集。
  • Tile(平铺视图):类似卡片布局,展示图标和文本。
listView1.View = View.Details;

2.Columns 详细信息视图中显示的列集合,也就是表头

listView1.Columns.Add("姓名", 100);//第一个参数是列名,第二个参数是Width宽度
listView1.Columns.Add("年龄", 80);//按照顺序来加列名

3.Items 列表中所有项的集合,也就是行记录集合

  • ListViewItem : Items集合包含的是一个一个Item对象
    • Text: 第一列的文本
    • SubItems: 除第一列的其他列的集合
ListViewItem item = new ListViewItem("张三");//增加一个表名
item.SubItems.Add("25");
listView1.Items.Add(item);

4.FullRowSelect是否整行选择(仅Details视图)

listView1.FullRowSelect = true;

5.GridLines 是否显示网格线(仅Details视图)

listView1.GridLines = true;

6.MultiSelect 是否允许多选

listView1.MultiSelect = true;

7.CheckBoxes是否显示复选框

 listView1.CheckBoxes = true;

8.SelectedItems 获取当前选中的项目集合

listView1.SelectedItems[0].SubItems[1].Text//获取集合中第二个元素文本
//还可以判断是否选中
listView1.SelectedItems.Count == 0//如果集合的数量为0,表示没有选中

9.SelectedIndices 获取当前选中的项目的索引集合

//根据索引获取选中项的内容
foreach (int index in listBox1.SelectedIndices)
{
    object item = listBox1.Items[index];
    Console.WriteLine($"索引 {index}: {item}");
}

10.Sorting 设置排序方式(None, Ascending(升序), Descending(降序))

// 初始化比较器
ListViewItemComparer itemComparer = new ListViewItemComparer();
// 设置比较器
listView1.ListViewItemSorter = itemComparer;
// 使用ColumnClick点击事件触发排序
listView1.Sort(); 

1.2 常用方法

1.BeginUpdate()/EndUpdate():批量更新时提高性能

// 开始批量更新 → 暂停界面刷新
listView1.BeginUpdate();
// 模拟添加10000条数据
for (int i = 1; i <= 10000; i++)
{
ListViewItem item = new ListViewItem($"编号 {i}");
item.SubItems.Add($"数据 {i}");
listView1.Items.Add(item);
}
// 结束批量更新 → 一次性刷新界面
listView1.EndUpdate();

2.EnsureVisible():确保指定项可见,始终显示在可见

// 让第99项显示出来(索引从0开始)
int targetIndex = 99;
listView1.Items[targetIndex].EnsureVisible();//类似于Excel的视图冻结

3.Sort():对列表进行排序

listView1.Sort();//升序排序

4.Clear():清除所有项目和列

  listView1.Clear();

二、基本使用

2.1 添加列(Details视图)

listView2.View = View.Details;
listView2.Columns.Add("编号", 100);
listView2.Columns.Add("姓名", 100);
listView2.Columns.Add("年龄", 80);
listView2.Columns.Add("部门", 150);

2.2 添加项目

int idx = 1;
private void btnAdd_Click(object sender, EventArgs e)
{
    // 模拟数据

    ListViewItem item = new ListViewItem(idx.ToString());
    item.SubItems.Add("zhansan");
    item.SubItems.Add(21.ToString());
    item.SubItems.Add("研发部");
    listView2.Items.Add(item);
    idx++;
}

2.3 批量增加 (使用BeginUpdate()/EndUpdate()减少重绘)

private void btnBatchAdd_Click(object sender, EventArgs e)
{
     listView2.BeginUpdate();
    //添加5000行数据
    for (int i = 0; i < 5000; i++)
    {
        ListViewItem item = new ListViewItem((idx++).ToString());
        item.SubItems.Add("zhansan"+idx);
        item.SubItems.Add(21.ToString());
        item.SubItems.Add("研发部"+idx);
        listView2.Items.Add(item);
    }
     listView2.EndUpdate();
}
  • 对于极大列表(>10,000项),考虑使用虚拟模式
  • 虚拟模式是一种优化技术,允许ListView仅加载和显示当前可见项,而不是一次性加载所有数据,特别适合处理大数据集(10,000+项)。
private void btnBatchAdd_Click(object sender, EventArgs e)
{
listView2.BeginUpdate();

listView2.VirtualMode = true;
listView2.VirtualListSize = 100000; // 设置虚拟列表的大小
                             // 处理检索虚拟项目事件

listView2.RetrieveVirtualItem += (obj, ev) =>
{
ev.Item = new ListViewItem((idx++).ToString());
ev.Item.SubItems.Add("zhansan" + idx);
ev.Item.SubItems.Add(21.ToString());
ev.Item.SubItems.Add("研发部" + idx);
};

listView2.EndUpdate();
}

2.4 修改项目

 private void btnEdit_Click(object sender, EventArgs e)
 {
     int index = Convert.ToInt32(this.mudIndex.Value);//基于下标
     listView2.Items[index].SubItems[1].Text = "lisi";
     listView2.Items[index].SubItems[2].Text = "22";
     listView2.Items[index].SubItems[3].Text = "市场部";

      //基于复选框 || 选择项
     var checkItem = listView1.CheckedItems[0]; // 获取复选框第一行
     var selectItem = listView1.SelectedItems[0]; // 获取选择项第一行
     checkItem.SubItems[1].Text = "lisi";
     checkItem.SubItems[2].Text = "22";
     checkItem.SubItems[3].Text = "市场部";
 }

2.5 删除项目

//基于选择项删除                listView1.Items.Remove(listView1.SelectedItems[0]);
//基于复选框删除
listView1.Items.Remove(listView1.CheckedItems[0]);

2.6 添加图标

  private void uiButton1_Click(object sender, EventArgs e)
        {
            listView1.SmallImageList = SmallimageList;
            listView1.LargeImageList = BigimageList;
listView2.BeginUpdate();
            for (int i = 0; i < 100; i++)
            {
                int index = i % SmallimageList.Images.Count;
                ListViewItem item = new ListViewItem((id++).ToString(), index);
                item.SubItems.Add("zhansan" + id);
                item.SubItems.Add("123456");
                item.SubItems.Add(id % 2 == 0?"可用":"禁用") ;
                listView1.Items.Add(item);
            }
listView2.EndUpdate();
        }

注意事项:

  • 添加ImageList组件
  • 往ImageList组件里面的Images属性里面添加图标,设置ImageSize大小
  • 代码绑定ListView的LargeImageList/SmallImageList,也可以手动设置
  • 尽量大小图标数量保持一致
    2.7 排序
    点击列头,按照指定列进行排序
    第一步 编写列头比较器类
 /// <summary>
 /// 自定义 ListViewItem 比较器
 /// </summary>
 public class ListViewItemComparer : IComparer
 {
     /// <summary>
     /// 指定按照哪一列进行排序
     /// </summary>
     private int _columnToSort;

     /// <summary>
     /// 指定排序方式
     /// </summary>
     private System.Windows.Forms.SortOrder _orderOfSort;
     /// <summary>
     /// 声明CaseInsensitiveComparer对象
     /// </summary>
     private System.Collections.CaseInsensitiveComparer _comparer;

     public ListViewItemComparer() {
         //默认按第一列排序
         _columnToSort = 0;
         //默认不排序
         _orderOfSort = System.Windows.Forms.SortOrder.None;
         //初始化比较器
         _comparer = new System.Collections.CaseInsensitiveComparer();

     }

     /// <summary>
     /// 重写 Compare 方法
     /// </summary>
     /// <param name="x">比较的第一个对象</param>
     /// <param name="y">比较的第二个对象</param>
     /// <returns>比较结果: 相等返回0, x大于y返回1,x小于y返回-1</returns>
     public int Compare(object x, object y)
     {
        int compareResult;
         System.Windows.Forms.ListViewItem listviewX, listviewY;
         //将object转换为ListViewItem
         listviewX = (System.Windows.Forms.ListViewItem)x;
         listviewY = (System.Windows.Forms.ListViewItem)y;
         string xText = listviewX.SubItems[_columnToSort].Text;  
         string yText = listviewY.SubItems[_columnToSort].Text;
         //比较
         //如果全是数字
         if (double.TryParse(xText, out double xInt) && double.TryParse(yText, out double yInt)) 
         {
             //比较数字
             compareResult = xInt.CompareTo(yInt);
         }
         else
         //比较字符串
         {
             compareResult = xText.CompareTo(yText);
         }
         //根据比较结果和排序方式返回结果
         if (_orderOfSort == System.Windows.Forms.SortOrder.Ascending)
         {
             //升序
             return compareResult;
         }
         else if (_orderOfSort == System.Windows.Forms.SortOrder.Descending)
         {
             //降序
             return (-compareResult);
         }
         else
         {
             //相等返回0
             return 0;
         }
     }

     /// <summary>
     /// 获取或设置排序列
     /// </summary>
     public  int ColumnToSort {
         get 
         {
            return  _columnToSort;
         }
         set 
         {
             _columnToSort = value;
         }
     }

     /// <summary>
     /// 获取或设置排序方式
     /// </summary>
     public System.Windows.Forms.SortOrder OrderOfSort
     {
         get
         {
             return _orderOfSort;
         }
         set
         {
             _orderOfSort = value;
         }
     }
 }

第二步 给ListView添加一个ColumnClick事件

// 初始化比较器
 private ListViewItemComparer  comparer = new ListViewItemComparer();
 private void listView2_ColumnClick(object sender, ColumnClickEventArgs e)
 {
     if (e.Column == comparer.ColumnToSort)
     {
         if (comparer.OrderOfSort == SortOrder.Ascending)
         {
             comparer.OrderOfSort = SortOrder.Descending;
         }
         else
         {
             comparer.OrderOfSort = SortOrder.Ascending;
         }
     }
     else 
     {
         comparer.ColumnToSort = e.Column;
         comparer.OrderOfSort = SortOrder.Ascending;
     }
     this.listView2.Sort();
 }

第三步 给ListView设置ListViewItemSorter比较器

 //设置比较器
 listView2.ListViewItemSorter = comparer;

三、习题讲解

题目: 使用ListView完成用户CURD操作, 效果图如下:
xw_20250813101832
思路:
根据题目要求,需要实现在修改用户的时候,将选中的用户信息显示在添加窗口上,并且还要把修改后的数据重新给到ListView组件上;这里可以用到前面学过的事件的发布-订阅机制来实现
事件机制:发布者:发布指令和触发事件的方法,订阅者:触发事件,响应指令
首先需要确定谁是谁是事件的发布者,谁是订阅者,AddForm窗口需要获取ListView上面的数据,所有它是发布者,Form1需要把ListView的数据传给AddForm,所有Form1是订阅者。

实现添加功能:
AddForm窗口:
定义事件参数类:

public class AddItemEventArgs:EventArgs
{
    public string Name { get; set; }
    public string Password { get; set; }
    public string State { get; set; }
}

定义事件

public event EventHandler<AddItemEventArgs> AddEvent;

定义触发事件

private void Save_btn_Click(object sender, EventArgs e)
      {
          string name = NameText.Text;
          string password =PasswordText.Text;
          string state = "";
          if (StateRbtn.Checked)
          {
              state = StateRbtn.Text;
          }
          else if (StateRbtn2.Checked)
          {
              state= StateRbtn2.Text;
          }

          //触发事件
          AddEvent?.Invoke(this, new AddItemEventArgs() {
                Name= name,
                Password= password,
                State= state
            
            });
            MessageBox.Show("添加成功");
            Close();

        }

Form1窗口(主窗口):
事件订阅者:
设置列头

private void AddColumns()
{
   listView1.Columns.Clear();
   listView1.View = View.Details;
   listView1.Columns.Add("编号", 120);
   listView1.Columns.Add("用户名", 170);
   listView1.Columns.Add("密码", 170);
   listView1.Columns.Add("状态", 170);
}

窗体初始化

private void Form1_Load(object sender, EventArgs e)
{
    AddColumns();
    //设置比较器
    listView1.ListViewItemSorter = comparer;
    //设置小图标和大图标的列表
    //listView1.SmallImageList = SmallimageList;
    //listView1.LargeImageList = BigimageList;

}

点击按钮订阅事件

private int id = 1;
private void Add_btn_Click(object sender, EventArgs e)
{
    //显示添加窗体
    AddForm addForm = new AddForm();
    //订阅事件
    addForm.AddEvent += (target, ev) =>
    {
        //把数据添加到ListView中
        ListViewItem item = new ListViewItem(id.ToString(),id% SmallimageList.Images.Count);
        //添加其他列的值
        item.SubItems.Add(ev.Name);
        item.SubItems.Add(ev.Password.ToString());
        item.SubItems.Add(ev.State);
        //把ListViewItem添加到Items属性
        listView1.Items.Add(item);
        id++;
    };

    addForm.ShowDialog();
}

实现修改用户功能:(同理)
Update:

 public partial class Update : UIForm
{
    //定义事件
    public event EventHandler<AddItemEventArgs> UpdateEvent;
    public Update()
    {
        InitializeComponent();
    }
     public AddItemEventArgs args;
    public Update(AddItemEventArgs addItem)
    {
        InitializeComponent();
        args = addItem;
    }
    #region 加载修改窗体
    private void Update_Load(object sender, EventArgs e)
    {
        NameText.Text = args.Name;
        PasswordText.Text = args.Password;
        if (args.State == "可用")
        {
            StateRbtn.Checked = true;
        }
        else
        {
            StateRbtn2.Checked = true;
        }
    }
    #endregion
    //按钮绑定触发事件
    private void Save_btn_Click(object sender, EventArgs e)
    {
        string name = NameText.Text;
        string password = PasswordText.Text;
        string state = string.Empty;
        if (StateRbtn.Checked)
        {
            state = StateRbtn.Text;
        }
        else if (StateRbtn2.Checked)
        {
            state = StateRbtn2.Text;
        }
        if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(state))
        {
            MessageBox.Show("请填写或者选择!");
        }
        else
        {
            UpdateEvent?.Invoke(this, new AddItemEventArgs()
            {
                Name = name,
                Password = password,
                State = StateRbtn.Checked ? "可用" : "禁用"
            });
            MessageBox.Show("温馨提示!", "修改成功!");
            Close();
        }
    }
}

Form1中:

private void Update_btn_Click(object sender, EventArgs e)
{
    if (listView1.SelectedItems.Count == 0 && listView1.CheckedItems.Count==0)
    {
        MessageBox.Show("请选择数据!");
    }
    else if(listView1.SelectedItems.Count != 0)//修改选择项
    {
        AddItemEventArgs eventArgs = new AddItemEventArgs()
        {
            Name = listView1.CheckedItems[0].SubItems[1].Text,
            Password = listView1.CheckedItems[0].SubItems[2].Text,
            State = listView1.CheckedItems[0].SubItems[3].Text
        };
        Update update = new Update(eventArgs);
        update.UpdateEvent += (obj, ev) =>
        {
            listView1.CheckedItems[0].SubItems[1].Text = ev.Name;
            listView1.CheckedItems[0].SubItems[2].Text = ev.Password;
            listView1.CheckedItems[0].SubItems[3].Text = ev.State;
        };
        update.ShowDialog();
    }
}

实现删除功能

private void Clear_btn_Click(object sender, EventArgs e)
{

    if (listView1.SelectedItems.Count == 0 && listView1.CheckedItems.Count==0)
    {
        MessageBox.Show("请先选择数据!");
    }
    else if (listView1.SelectedItems.Count != 0) // 只能单删
    {
        UIMessageBox.ShowMessageDialog2("温馨提示", $"用户信息:{listView1.SelectedItems[0].SubItems[1].Text} 删除成功!", UINotifierType.WARNING);
        listView1.Items.Remove(listView1.SelectedItems[0]);
    }
    else if (listView1.CheckedItems.Count != 0) // 多删
    {
        listView1.BeginUpdate();
        StringBuilder sb = new StringBuilder();
        sb.AppendLine();
        foreach (ListViewItem item in listView1.CheckedItems)
        {
            for (int i = 0; i < listView1.Columns.Count; i++)
            {
                sb.Append(item.SubItems[i].Text + ", ");
            }
            sb.AppendLine();
        }
        DialogResult result = MessageBox.Show($"确定要删除如下选项:{sb.ToString()}", "友情提示", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        if (result == DialogResult.Yes)
        {
            foreach (ListViewItem item in listView1.CheckedItems)
            {
                listView1.Items.Remove(item);
            }
        }
        listView1.EndUpdate();
    }

}

四、总结

ListView有不同视图展示数据,但它的所有列都是文本Text属性,比较单一,不能实现多类型,如果要实现多种类型的,推荐使用DataGridView组件。

posted @ 2026-03-28 17:13  大眼邓小眼睛  阅读(75)  评论(0)    收藏  举报