完善 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;
    // ... 更新代码省略
});


 


 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值