首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

WinForms ListView 嵌入 ComboBox 編輯完全實現:自訂控件與座標計算詳解

     編輯:關於C語言

前言

ListView(Details 檢視)原生不支援單元格編輯。經典解法:在滑鼠點擊單元格時,動態定位一個隱藏的 ComboBox 覆蓋該單元格,編輯完成後寫回 ListViewItem。本文完整呈現自訂 MyListView 控件與表單代碼,詳細解析座標計算、事件處理、焦點管理等關鍵技術點。

核心架構

  • MyListView:繼承 ListView 的自訂控件(原始碼未提供,假設為標準 ListView)
  • ComboBox (cbListViewCombo):表單上預置、Visible=false、項目預填「NC」、「WA」
  • ListView (myListView1):View=Details、FullRowSelect=true、兩欄(State Abbr.、State)

關鍵事件與代碼邏輯

1. 滑鼠按下 → 定位 ComboBox (myListView1_MouseUp)

private void myListView1_MouseUp(object sender, MouseEventArgs e)
{
    lvItem = myListView1.GetItemAt(e.X, e.Y);
    if (lvItem == null) return;

    // 僅第一欄可編輯
    if (e.X > myListView1.Columns[0].Width) return;

    var itemBounds = lvItem.Bounds;
    // 處理水平捲動導致項目部分可見的邊界修正
    if ((itemBounds.Left + myListView1.Columns[0].Width) < 0) return; // 完全捲出左側
    else if (itemBounds.Left < 0) // 部分捲出左側
    {
        if ((itemBounds.Left + myListView1.Columns[0].Width) > myListView1.Width)
        {
            itemBounds.Width = myListView1.Width;
            itemBounds.X = 0;
        }
        else
        {
            itemBounds.Width = myListView1.Columns[0].Width + itemBounds.Left;
            itemBounds.X = 2;
        }
    }
    else if (myListView1.Columns[0].Width > myListView1.Width)
    {
        itemBounds.Width = myListView1.Width;
    }
    else
    {
        itemBounds.Width = myListView1.Columns[0].Width;
        itemBounds.X = 2;
    }

    // 轉換為表單座標
    itemBounds.Y += myListView1.Top;
    itemBounds.X += myListView1.Left;

    // 套用至 ComboBox 並顯示
    cbListViewCombo.Bounds = itemBounds;
    cbListViewCombo.Text = lvItem.Text;
    cbListViewCombo.Visible = true;
    cbListViewCombo.BringToFront();
    cbListViewCombo.Focus();
}

2. ComboBox 選值/按鍵 → 寫回並隱藏

private void cbListViewCombo_SelectedValueChanged(object sender, EventArgs e)
{
    lvItem.Text = cbListViewCombo.Text;
    cbListViewCombo.Visible = false;
}

private void cbListViewCombo_KeyPress(object sender, KeyPressEventArgs e)
{
    switch (e.KeyChar)
    {
        case (char)Keys.Escape:
            cbListViewCombo.Text = lvItem.Text; // 還原原值
            cbListViewCombo.Visible = false;
            break;
        case (char)Keys.Enter:
            cbListViewCombo.Visible = false;
            break;
    }
}

3. 點擊 ListView 空白處 → 隱藏 ComboBox

private void myListView1_Click(object sender, EventArgs e)
{
    cbListViewCombo.Visible = false;
}

座標計算核心邏輯圖解

ListView 座標系 (client)          表單座標系
┌─────────────────────┐            ┌─────────────────────┐
│ [Header]            │            │                     │
│ ┌──────┬────────┐   │   Item.Bounds (相對 ListView)   │
│ │Col 0 │ Col 1  │   │   → 需 + ListView.Left/Top      │
│ │ Item │        │   │   → 修正水平捲動截斷            │
│ └──────┴────────┘   │   → 設定 ComboBox.Bounds        │
└─────────────────────┘            └─────────────────────┘

關鍵技術點總結

技術點實現方式
單元格編輯觸發MouseUp + GetItemAt + 欄位索引判斷
ComboBox 定位Bounds 直接賦值 Rectangle(含座標轉換與捲動修正)
焦點管理BringToFront() + Focus() 確保鍵盤輸入生效
值同步SelectedValueChanged 寫回 ListViewItem.Text
取消編輯Escape 鍵還原原值並隱藏
失焦隱藏ListView.Click 隱藏 ComboBox

現代替代方案提示

  • DataGridView:原生支援 DataGridViewComboBoxColumn,無需手工座標計算。
  • ObjectListView (NuGet):ListView 增強庫,內建單元格編輯。
  • WPF / WinUI 3:DataGrid、ListView 皆支援 CellTemplate/CellEditingTemplate 雙模板原生編輯。

總結

ListView 嵌入 ComboBox 編輯是 WinForms 經典技巧,核心在於 精確的座標轉換與捲動修正、焦點與事件流程控制。雖代碼量較大,但理解其原理有助於掌握 WinForms 底層繪製與座標系統。新專案建議直接使用 DataGridView 或現代 UI 框架,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved