功能說明 使用ListView時,希望可以在單元格顯示圖片或其他控制項,發現原生的ListView不支持,於是通過拓展,實現ListView可以顯示任意控制項的功能,效果如下: 實現方法 本來想著在單元格裡面實現控制項的自繪的,但是沒找到辦法,最後是通過在單元格的錶面顯示對應控制項的,浮於錶面達到目的。 實 ...
功能說明
使用ListView時,希望可以在單元格顯示圖片或其他控制項,發現原生的ListView不支持,於是通過拓展,實現ListView可以顯示任意控制項的功能,效果如下:
實現方法
本來想著在單元格裡面實現控制項的自繪的,但是沒找到辦法,最後是通過在單元格的錶面顯示對應控制項的,浮於錶面達到目的。
實現要點如下:
ListView
需要設置OwnerDraw=true
,並重載自繪函數OnDrawColumnHeader
、OnDrawItem
、OnDrawSubItem
- 支持按單元格添加對應的控制項,其
Parent
設置為列表ListView
- 列表界面調整後,包括大小、列表頭、滾動等,需重新繪製單元格的控制項
實現源碼
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyListView.Ui
{
#region ListViewEx
public class ListViewEx : ListView
{
#region 內部屬性
/// <summary>
/// 存放單元格控制項
/// </summary>
List<Control> _CellControls = new List<Control>();
/// <summary>
/// 界面是否發生變化
/// </summary>
bool IsViewChanged { get; set; }
#endregion
#region 方法
/// <summary>
/// 構造函數
/// </summary>
public ListViewEx()
{
#region 初始化
#endregion
#region 事件
this.ColumnReordered += ColumnWidthChangedHandler;
this.ColumnWidthChanged += ColumnWidthChangedHandler;
#endregion
}
/// <summary>
/// 添加控制項
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="row"></param>
/// <param name="col"></param>
/// <param name="c"></param>
/// <returns></returns>
public T Add<T>(int row, int col, T c) where T : Control
{
if(row >= this.Items.Count || col >= this.Columns.Count)
{
return null;
}
var index = (row * this.Columns.Count) + col;
for (var i = _CellControls.Count; i <= index; i++)
{
_CellControls.Add(null);
}
var oc = _CellControls[index];
if (oc != null)
{
oc.Dispose();
}
OwnerDraw = true;
IsViewChanged = true;
c.Parent = this;
_CellControls[index] = c;
return c;
}
/// <summary>
/// 設置行高度
/// </summary>
/// <param name="height"></param>
public void SetItemHeight(int height)
{
if(this.SmallImageList == null)
{
this.SmallImageList = new ImageList();
}
this.SmallImageList.ImageSize = new Size(1, height);
}
#endregion
#region 內部函數
void ColumnWidthChangedHandler(object s, EventArgs e)
{
IsViewChanged = true;
}
/// <summary>
/// 顯示控制項到目標單元格
/// </summary>
/// <param name="c"></param>
/// <param name="item"></param>
void ShowCellControl(Control c, ListViewItem.ListViewSubItem item)
{
int margin = 2;
c.Text = item.Text;
c.Visible = true;
c.Bounds = new Rectangle(item.Bounds.X + margin,
item.Bounds.Top + margin,
item.Bounds.Width - 2 * margin,
item.Bounds.Height - 2 * margin);
}
/// <summary>
/// 顯示單元格控制項
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
Control GetCellControl(DrawListViewSubItemEventArgs e)
{
Control c = null;
#region 獲取控制項
var index = (e.ItemIndex * this.Columns.Count) + e.ColumnIndex;
if (index >= _CellControls.Count)
{
return null;
}
c = _CellControls[index];
#endregion
return c;
}
protected override void WndProc(ref Message m)
{
#region 事件定義
const int WM_SIZE = 0x0005;
const int WM_PAINT = 0x000F;
const int WM_HSCROLL = 0x114;
const int WM_VSCROLL = 0x115;
const int WM_MOUSEWHEEL = 0x020A;
#endregion
#region 重繪顯示控制項
if (m.Msg == WM_PAINT && IsViewChanged)
{
if(this.Columns.Count > 0)
{
for (var i = 0; i < _CellControls.Count; i++)
{
var cell_control = _CellControls[i];
if (cell_control == null)
{
continue;
}
cell_control.Visible = false;
var row = i / this.Columns.Count;
var col = i % this.Columns.Count;
if(row >= Items.Count || col >= this.Columns.Count)
{
continue;
}
var item = this.Items[row];
if(item.Bounds.Y < 0 || item.Bounds.Y >= this.Height)
{
continue;
}
if(item.SubItems[col].Bounds.X < 0 || item.SubItems[col].Bounds.X >= this.Width)
{
continue;
}
ShowCellControl(cell_control, item.SubItems[col]);
}
IsViewChanged = false;
}
}
else if(m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_SIZE)
{
IsViewChanged = true;
}
#endregion
base.WndProc(ref m);
}
protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
{
e.DrawDefault = true;
}
protected override void OnDrawItem(DrawListViewItemEventArgs e)
{
// 已經在OnDrawSubItem處理過了
// e.DrawText(TextFormatFlags.Default);
}
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
if(GetCellControl(e) != null)
{
return;
}
else
{
e.DrawDefault = true;
}
}
#endregion
}
#endregion
}
測試代碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyListView
{
public partial class Form1 : Form
{
#region 函數
public Form1()
{
#region 佈局初始化
InitializeComponent();
var lv = new Ui.ListViewEx()
{
Dock = DockStyle.Fill,
View = View.Details,
GridLines = true,
};
this.Controls.Add(lv);
var headers = new string[] { "序號", "名稱", "年齡", "住址", "榮譽", "崗位", "頭像" };
foreach(var v in headers)
{
lv.Columns.Add(v, 100, HorizontalAlignment.Center);
}
lv.SetItemHeight(40);
for(var i=0; i<50; i++)
{
var lvi = lv.Items.Add($"數據{i + 1}");
for(var j=1; j<lv.Columns.Count; j++)
{
lvi.SubItems.Add($"數據{i + 1}-{j}");
switch(j)
{
case 1:
lv.Add(i, j, new Label());
break;
case 2:
lv.Add(i, j, new Button());
break;
case 3:
lv.Add(i, j, new TextBox()
{
Font = new Font("宋體", 18)
});
break;
case 4:
lv.Add(i, j, new ComboBox()
{
Font = new Font("宋體", 18)
});
break;
case 6:
{
var pic = lv.Add(i, j, new PictureBox());
pic.Image = LoadImage($"logo{i%7}.jpg");
pic.SizeMode = PictureBoxSizeMode.StretchImage;
}
break;
}
}
}
#endregion
}
Image LoadImage(string name)
{
var file = Path.GetFullPath(Path.Combine(@"..\..\Data\IMG", name));
if(!File.Exists(file))
{
return null;
}
return Image.FromFile(file);
}
#endregion
}
}