悬停时如何以不同方式绘制所有者绘制的 ListViewItem?
How to paint owner drawn ListViewItem differently when hovered?
下面是代码。我看到 MouseMove 事件并不总是被触发,尤其是当鼠标移动得非常快时,并且因为这两个项目可以同时标记为悬停,所以我现在使用一个变量来保存最后一个悬停的项目,但是问题是重绘太多了。我还看到 DrawListViewItemEventArgs.State 属性 只是 ShowKeyboardCues
而它还应该包含 Hot
.
private void Form1_Load(object sender, EventArgs e)
{
listView1.OwnerDraw = true;
listView1.View = View.LargeIcon;
listView1.DrawItem += ListView1_DrawItem;
listView1.MouseMove += ListView1_MouseMove;
for (int i = 1; i <= 6; ++i)
{
listView1.Items.Add($"item {i}", 0);
}
}
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
ListViewItem item = listView1.GetItemAt(e.X, e.Y);
if (item != null)
{
if (LastHoveredItem != null && LastHoveredItem.Index == item.Index)
{
return;
}
listView1.RedrawItems(item.Index, item.Index, false);
}
}
internal ListViewItem LastHoveredItem = null;
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
bool hot = e.Item.Bounds.Contains(listView1.PointToClient(Cursor.Position));
if (LastHoveredItem != null)
{
listView1.RedrawItems(LastHoveredItem.Index, LastHoveredItem.Index, false);
}
if (hot)
{
LastHoveredItem = e.Item;
e.Graphics.FillRectangle(Brushes.Green, e.Bounds);
}
else
{
LastHoveredItem = null;
}
e.DrawText();
}
这里有几个新的方法和更新现有的方法:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listView1.OwnerDraw = true;
listView1.View = View.LargeIcon;
listView1.DrawItem += ListView1_DrawItem;
listView1.MouseEnter += ListView1_MouseEnter;
listView1.MouseMove += ListView1_MouseMove;
listView1.MouseLeave += ListView1_MouseLeave;
for (int i = 1; i <= 10; ++i)
{
listView1.Items.Add($"item {i}", 0);
}
}
private void ListView1_MouseEnter(object sender, EventArgs e)
{
CheckHoveredAndInvalidate();
}
private void ListView1_MouseLeave(object sender, EventArgs e)
{
RemoveHoveredAndInvalidate();
}
internal static Rectangle GetEntireItemBounds(ListViewItem it)
{
return it.GetBounds(ItemBoundsPortion.Entire);
}
internal ListViewItem GetEntireItemAtCursorPosition()
{
Point p = listView1.PointToClient(Cursor.Position);
foreach (ListViewItem it in listView1.Items)
{
if (GetEntireItemBounds(it).Contains(p))
{
return it;
}
}
return null;
}
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
CheckHoveredAndInvalidate();
}
private void CheckHoveredAndInvalidate()
{
ListViewItem item = GetEntireItemAtCursorPosition();
if (item == null)
{
RemoveHoveredAndInvalidate();
}
else if (item != null)
{
if (LastHoveredItem != null)
{
if (LastHoveredItem != item)
{
ListViewItem item2 = LastHoveredItem;
LastHoveredItem = item;
listView1.Invalidate(GetEntireItemBounds(item2));
listView1.Invalidate(GetEntireItemBounds(item));
}
else if (LastHoveredItem == item)
{
}
}
else if (LastHoveredItem == null)
{
LastHoveredItem = item;
listView1.Invalidate(GetEntireItemBounds(item));
}
}
}
private void RemoveHoveredAndInvalidate()
{
if (LastHoveredItem != null)
{
ListViewItem item2 = LastHoveredItem;
LastHoveredItem = null;
listView1.Invalidate(GetEntireItemBounds(item2));
}
else if (LastHoveredItem == null)
{
}
}
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (LastHoveredItem == e.Item)
{
e.Graphics.FillRectangle(Brushes.Yellow, e.Item.Bounds);
}
else
{
e.Graphics.FillRectangle(Brushes.Green, e.Item.Bounds);
}
}
文字绘制部分省略
下面是代码。我看到 MouseMove 事件并不总是被触发,尤其是当鼠标移动得非常快时,并且因为这两个项目可以同时标记为悬停,所以我现在使用一个变量来保存最后一个悬停的项目,但是问题是重绘太多了。我还看到 DrawListViewItemEventArgs.State 属性 只是 ShowKeyboardCues
而它还应该包含 Hot
.
private void Form1_Load(object sender, EventArgs e)
{
listView1.OwnerDraw = true;
listView1.View = View.LargeIcon;
listView1.DrawItem += ListView1_DrawItem;
listView1.MouseMove += ListView1_MouseMove;
for (int i = 1; i <= 6; ++i)
{
listView1.Items.Add($"item {i}", 0);
}
}
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
ListViewItem item = listView1.GetItemAt(e.X, e.Y);
if (item != null)
{
if (LastHoveredItem != null && LastHoveredItem.Index == item.Index)
{
return;
}
listView1.RedrawItems(item.Index, item.Index, false);
}
}
internal ListViewItem LastHoveredItem = null;
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
bool hot = e.Item.Bounds.Contains(listView1.PointToClient(Cursor.Position));
if (LastHoveredItem != null)
{
listView1.RedrawItems(LastHoveredItem.Index, LastHoveredItem.Index, false);
}
if (hot)
{
LastHoveredItem = e.Item;
e.Graphics.FillRectangle(Brushes.Green, e.Bounds);
}
else
{
LastHoveredItem = null;
}
e.DrawText();
}
这里有几个新的方法和更新现有的方法:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listView1.OwnerDraw = true;
listView1.View = View.LargeIcon;
listView1.DrawItem += ListView1_DrawItem;
listView1.MouseEnter += ListView1_MouseEnter;
listView1.MouseMove += ListView1_MouseMove;
listView1.MouseLeave += ListView1_MouseLeave;
for (int i = 1; i <= 10; ++i)
{
listView1.Items.Add($"item {i}", 0);
}
}
private void ListView1_MouseEnter(object sender, EventArgs e)
{
CheckHoveredAndInvalidate();
}
private void ListView1_MouseLeave(object sender, EventArgs e)
{
RemoveHoveredAndInvalidate();
}
internal static Rectangle GetEntireItemBounds(ListViewItem it)
{
return it.GetBounds(ItemBoundsPortion.Entire);
}
internal ListViewItem GetEntireItemAtCursorPosition()
{
Point p = listView1.PointToClient(Cursor.Position);
foreach (ListViewItem it in listView1.Items)
{
if (GetEntireItemBounds(it).Contains(p))
{
return it;
}
}
return null;
}
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
CheckHoveredAndInvalidate();
}
private void CheckHoveredAndInvalidate()
{
ListViewItem item = GetEntireItemAtCursorPosition();
if (item == null)
{
RemoveHoveredAndInvalidate();
}
else if (item != null)
{
if (LastHoveredItem != null)
{
if (LastHoveredItem != item)
{
ListViewItem item2 = LastHoveredItem;
LastHoveredItem = item;
listView1.Invalidate(GetEntireItemBounds(item2));
listView1.Invalidate(GetEntireItemBounds(item));
}
else if (LastHoveredItem == item)
{
}
}
else if (LastHoveredItem == null)
{
LastHoveredItem = item;
listView1.Invalidate(GetEntireItemBounds(item));
}
}
}
private void RemoveHoveredAndInvalidate()
{
if (LastHoveredItem != null)
{
ListViewItem item2 = LastHoveredItem;
LastHoveredItem = null;
listView1.Invalidate(GetEntireItemBounds(item2));
}
else if (LastHoveredItem == null)
{
}
}
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (LastHoveredItem == e.Item)
{
e.Graphics.FillRectangle(Brushes.Yellow, e.Item.Bounds);
}
else
{
e.Graphics.FillRectangle(Brushes.Green, e.Item.Bounds);
}
}
文字绘制部分省略