希望是在 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;
// ... 更新代碼省略
});