完善 C# ListView 系列-可編輯單元格

希望是在 ListView 中雙擊某單元格時,該單元格內容可編輯。

不過 ListView 本身是不帶這個功能的,我們要實現的原理是獲取雙擊的是哪個單元格,然後在該單元格顯示一個文本框(也可以是其他控件,本文以文本框爲例)。

ListViewCell

namespace Yulin.YWinForm
{
    public class ListViewCell
    {
        /// <summary>
        /// 單元格所在的行。
        /// </summary>
        public ListViewItem Item { get; set; }
        /// <summary>
        /// Item 的 Index 值會變成 -1,暫時未找到原因,用這個代替。
        /// </summary>
        public int ItemIndex { get; set; }
        /// <summary>
        /// 單元格所在的列。
        /// </summary>
        public ColumnHeader Column { get; set; }
        /// <summary>
        /// 單元格相對於 ListView 的大小和位置。
        /// </summary>
        public Rectangle Bounds { get; set; }
    }


    public class ListViewCellLocator
    {
        [DllImport("user32")]
        public static extern int GetScrollPos(int hwnd, int nBar);


        /// <summary>
        /// 根據位置 x、y 獲得 ListViewCell。
        /// </summary>
        /// <param name="listView"></param>
        /// <param name="x">工作區座標表示的 x 軸座標。</param>
        /// <param name="y">工作區座標表示的 y 軸座標。</param>
        /// <returns></returns>
        public static ListViewCell GetCell(ListView listView, int x, int y)
        {
            ListViewCell cell = new ListViewCell();

            // 獲得單元格所在的行。
            cell.Item = listView.GetItemAt(x, y);
            if (cell.Item == null)
            {
                return null;
            }
            cell.ItemIndex = cell.Item.Index; // 現在 Item.Index 還能用

            // 根據各列寬度,獲得單元格所在的列,以及 Bounds。
            int currentX = cell.Item.GetBounds(ItemBoundsPortion.Entire).Left; // 依次循環各列,表示各列的起點值
            int scrollLeft = GetScrollPos(listView.Handle.ToInt32(), 0); // 可能出現了橫向滾動條,左邊隱藏起來的寬度
            for (int i = 0; i < listView.Columns.Count; i++)
            {
                if (scrollLeft + x >= currentX &&
                    scrollLeft + x < currentX + listView.Columns[i].Width)
                {
                    cell.Column = listView.Columns[i]; // 列找到了
                    Rectangle itemBounds = cell.Item.GetBounds(ItemBoundsPortion.Entire);
                    cell.Bounds = new Rectangle(currentX,
                        itemBounds.Y,
                        listView.Columns[i].Width,
                        itemBounds.Height);
                    break;
                }
                currentX += listView.Columns[i].Width;
            }

            if (cell.Column == null)
            {
                return null;
            }
            return cell;
        }
    }
}



<span style="font-family: SimSun, serif; font-size: 14px;  line-height: 21px; text-indent: 28px;"><strong>EditableListView</strong></span>
<span style="font-family: SimSun, serif; font-size: 14px; line-height: 21px; text-indent: 28px;"></span><pre name="code" class="csharp">namespace Yulin.YWinForm
{
    public class EditableListViewSubmittingEventArgs : EventArgs
    {
        public ListViewCell Cell { get; set; }
        public string Value { get; set; }
    }
    public delegate void EditableListViewSubmitting(object sender, EditableListViewSubmittingEventArgs e);

    public class EditableListView
    {
        public event EditableListViewSubmitting Submitting;

        private ListView ListView { get; set; }
        private Point MousePosition = new Point();
        private TextBox EditBox { get; set; }
        public int[] TextBoxColumns { get; set; }

        public EditableListView(ListView listView)
        {
            // 初始化 EditBox
            EditBox = new TextBox();
            EditBox.Visible = false;
            EditBox.KeyUp += new KeyEventHandler(delegate(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Escape)
                {
                    LeaveEdit();
                }
                else if (e.KeyCode == Keys.Enter)
                {
                    if (Submitting != null)
                    {
                        EditableListViewSubmittingEventArgs args = new EditableListViewSubmittingEventArgs();
                        if (EditBox.Tag != null)
                        {
                            args.Cell = (ListViewCell)EditBox.Tag;
                        }
                        else
                        {
                            args.Cell = null;
                        }
                        args.Value = EditBox.Text;
                        Submitting(listView, args);
                    }
                }
            });

            // 設置 ListView
            ListView = listView;
            ListView.MouseMove += new MouseEventHandler(delegate(object sender, MouseEventArgs e)
            {
                // 記錄鼠標位置,便於在鼠標動作中使用(有些鼠標動作,比如雙擊,事件中並不傳遞鼠標雙擊時的位置)。
                MousePosition.X = e.X;
                MousePosition.Y = e.Y;
            });

            EditBox.Parent = ListView;

            // 事件
            ListView.DoubleClick += new EventHandler(delegate(object sender, EventArgs e)
            {
                ListViewCell cell = ListViewCellLocator.GetCell(this.ListView, MousePosition.X, MousePosition.Y);

                if (cell == null)
                {
                    return;
                }

                if (TextBoxColumns.Contains(cell.Column.Index))
                {
                    // 設置 EditBox 的位置、大小、內容、可顯示等。
                    EditBox.Bounds = cell.Bounds;
                    EditBox.Text = cell.Item.SubItems[cell.Column.Index].Text;
                    EditBox.Visible = true;
                    EditBox.Focus();
                    EditBox.Tag = cell;
                }
            });
        }


        public bool IsEditableColumn(int columnIndex)
        {
            if (TextBoxColumns.Contains(columnIndex))
            {
                return true;
            }

            return false;
        }


        public void LeaveEdit()
        {
            EditBox.Visible = false;
            EditBox.Tag = null;
        }
    }
}


<span style="font-family: SimSun, serif; font-size: 14px;  line-height: 21px; text-indent: 28px;"><strong>應用</strong></span>
<span style="font-family: SimSun, serif; font-size: 14px;  line-height: 21px; text-indent: 28px;"><strong>
</strong></span>
<span style="font-family: SimSun, serif; font-size: 14px;  line-height: 21px; text-indent: 28px;"><strong>
</strong></span>
<span style="font-family: SimSun, serif; font-size: 14px; line-height: 21px; text-indent: 28px;"></span><pre name="code" class="csharp">EditablelistViewSubmittingEventArgs e)
{
    if (e.Cell == null)
    {
        return;
    }
    int dataId = Convert.ToInt32(e.Cell.Item.SubItems[_dataIdColumn.Index].Text);
    string newValue = e.Value;
    // ... 更新代碼省略
});







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章