当鼠标悬停在行上时突出显示 DataGridView 中的行
Highlight row in DataGridView when mouse hovers over a row
我有一个 DataGridView,目前它看起来像下图:
我想要实现的是,当我将鼠标悬停在任何行的任何列上时,整行都应该突出显示并且背景颜色应该变成不同的颜色,就像下图一样。
你能帮我解决这个问题吗?
你可以这样做:
private void dataGridView1_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
{ DataGridView1.ClearSelection();
If (e.RowIndex > -1) { DataGridView1.Rows(e.RowIndex).Selected = True; } }
我认为使用行的背景颜色是不可能的,但我不确定...
您在第二个屏幕截图中看到的不是 DataGridView
,而是 Details
模式下的 ListView
。
listView1.View = View.Details;
listView1.FulRowSelect = true;
使用 Columns
填充列,使用 Items
填充行。一行中的第二列和更多列可以由每个项目的 SubItems
属性 填充。
默认情况下该行不会自动悬停并且选择外观是丑陋的深蓝色静态线。要显示这个漂亮的浅蓝色悬停,请通过一个小技巧在您的列表视图中启用 "explorer" 主题:
internal sealed class AdvancedListView : ListView
{
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (!DesignMode && Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 6)
{
SetWindowTheme(Handle, "explorer", null);
}
}
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
private extern static int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);
}
现在您将获得与第二个屏幕截图完全相同的外观...
好吧,除了订购。要启用那个也是隐藏功能的小箭头,请使用下面的 class(请注意,它在此实现中按字符串值排序):
internal class ListViewSorter : IComparer
{
private const int HDI_FORMAT = 0x0004;
private const int HDF_SORTUP = 0x0400;
private const int HDF_SORTDOWN = 0x0200;
private const int LVM_GETHEADER = 0x1000 + 31; // LVM_FIRST + 31
private const int HDM_GETITEM = 0x1200 + 11; // HDM_FIRST + 11
private const int HDM_SETITEM = 0x1200 + 12; // HDM_FIRST + 12
private readonly int column;
private readonly SortOrder sortOrder;
public ListViewSorter(SortOrder sortOrder, int col, ListView listView)
{
IntPtr hColHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
HDITEM hdItem = new HDITEM();
IntPtr colHeader = new IntPtr(col);
hdItem.mask = HDI_FORMAT;
SendMessageItem(hColHeader, HDM_GETITEM, colHeader, ref hdItem);
if (sortOrder == SortOrder.Ascending)
{
hdItem.fmt &= ~HDF_SORTDOWN;
hdItem.fmt |= HDF_SORTUP;
}
else if (sortOrder == SortOrder.Descending)
{
hdItem.fmt &= ~HDF_SORTUP;
hdItem.fmt |= HDF_SORTDOWN;
}
else if (sortOrder == SortOrder.None)
{
hdItem.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
}
SendMessageItem(hColHeader, HDM_SETITEM, colHeader, ref hdItem);
this.sortOrder = sortOrder;
this.column = col;
}
protected virtual int DoCompare(ListViewItem item1, ListViewItem item2)
{
return sortOrder == SortOrder.Ascending ? String.Compare(item1.SubItems[column].Text, item2.SubItems[column].Text, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase)
: String.Compare(item2.SubItems[column].Text, item1.SubItems[column].Text, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
}
public int Compare(object x, object y)
{
ListViewItem item1 = (ListViewItem)x;
ListViewItem item2 = (ListViewItem)y;
return DoCompare(item1, item2);
}
[StructLayout(LayoutKind.Sequential)]
private struct HDITEM
{
public int mask;
public int cxy;
[MarshalAs(UnmanagedType.LPTStr)] public string pszText;
public IntPtr hbm;
public int cchTextMax;
public int fmt;
public int lParam;
public int iImage;
public int iOrder;
};
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern IntPtr SendMessageItem(IntPtr handle, int msg, IntPtr wParam, ref HDITEM lParam);
}
要对单击的列应用排序,请使用 ColumnClick
事件:
private void advancedListView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
advancedListView1.Sorting = advancedListView1.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
advancedListView1.ListViewItemSorter = new ListViewSorter(advancedListView1.Sorting, e.Column, advancedListView1);
}
在 Windows 7 中,它看起来像您的屏幕截图。在我的 Windows 10 中,它看起来像这样:
您可以在 RowPostPaint
event or you can override OnRowPostPaint
method in a derived DataGridView
中突出显示鼠标指针下的行。在这种方法中,您可以自己绘制整行或只绘制其中的一部分或在该行上绘制一些东西:
例子
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyDataGridView : DataGridView
{
public MyDataGridView() { DoubleBuffered = true; }
protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e)
{
base.OnRowPostPaint(e);
if (this.RectangleToScreen(e.RowBounds).Contains(MousePosition))
{
using (var b = new SolidBrush(Color.FromArgb(50, Color.Blue)))
using (var p = new Pen(Color.Blue))
{
var r = e.RowBounds; r.Width -= 1; r.Height -= 1;
e.Graphics.FillRectangle(b, r);
e.Graphics.DrawRectangle(p, r);
}
}
}
protected override void OnMouseMove(MouseEventArgs e){
base.OnMouseMove(e); this.Invalidate();
}
protected override void OnMouseEnter(EventArgs e){
base.OnMouseEnter(e); this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e){
base.OnMouseLeave(e); this.Invalidate();
}
protected override void OnScroll(ScrollEventArgs e){
base.OnScroll(e); this.Invalidate();
}
}
我有一个 DataGridView,目前它看起来像下图:
我想要实现的是,当我将鼠标悬停在任何行的任何列上时,整行都应该突出显示并且背景颜色应该变成不同的颜色,就像下图一样。
你能帮我解决这个问题吗?
你可以这样做:
private void dataGridView1_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
{ DataGridView1.ClearSelection();
If (e.RowIndex > -1) { DataGridView1.Rows(e.RowIndex).Selected = True; } }
我认为使用行的背景颜色是不可能的,但我不确定...
您在第二个屏幕截图中看到的不是 DataGridView
,而是 Details
模式下的 ListView
。
listView1.View = View.Details;
listView1.FulRowSelect = true;
使用 Columns
填充列,使用 Items
填充行。一行中的第二列和更多列可以由每个项目的 SubItems
属性 填充。
默认情况下该行不会自动悬停并且选择外观是丑陋的深蓝色静态线。要显示这个漂亮的浅蓝色悬停,请通过一个小技巧在您的列表视图中启用 "explorer" 主题:
internal sealed class AdvancedListView : ListView
{
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (!DesignMode && Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 6)
{
SetWindowTheme(Handle, "explorer", null);
}
}
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
private extern static int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);
}
现在您将获得与第二个屏幕截图完全相同的外观...
好吧,除了订购。要启用那个也是隐藏功能的小箭头,请使用下面的 class(请注意,它在此实现中按字符串值排序):
internal class ListViewSorter : IComparer
{
private const int HDI_FORMAT = 0x0004;
private const int HDF_SORTUP = 0x0400;
private const int HDF_SORTDOWN = 0x0200;
private const int LVM_GETHEADER = 0x1000 + 31; // LVM_FIRST + 31
private const int HDM_GETITEM = 0x1200 + 11; // HDM_FIRST + 11
private const int HDM_SETITEM = 0x1200 + 12; // HDM_FIRST + 12
private readonly int column;
private readonly SortOrder sortOrder;
public ListViewSorter(SortOrder sortOrder, int col, ListView listView)
{
IntPtr hColHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
HDITEM hdItem = new HDITEM();
IntPtr colHeader = new IntPtr(col);
hdItem.mask = HDI_FORMAT;
SendMessageItem(hColHeader, HDM_GETITEM, colHeader, ref hdItem);
if (sortOrder == SortOrder.Ascending)
{
hdItem.fmt &= ~HDF_SORTDOWN;
hdItem.fmt |= HDF_SORTUP;
}
else if (sortOrder == SortOrder.Descending)
{
hdItem.fmt &= ~HDF_SORTUP;
hdItem.fmt |= HDF_SORTDOWN;
}
else if (sortOrder == SortOrder.None)
{
hdItem.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
}
SendMessageItem(hColHeader, HDM_SETITEM, colHeader, ref hdItem);
this.sortOrder = sortOrder;
this.column = col;
}
protected virtual int DoCompare(ListViewItem item1, ListViewItem item2)
{
return sortOrder == SortOrder.Ascending ? String.Compare(item1.SubItems[column].Text, item2.SubItems[column].Text, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase)
: String.Compare(item2.SubItems[column].Text, item1.SubItems[column].Text, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
}
public int Compare(object x, object y)
{
ListViewItem item1 = (ListViewItem)x;
ListViewItem item2 = (ListViewItem)y;
return DoCompare(item1, item2);
}
[StructLayout(LayoutKind.Sequential)]
private struct HDITEM
{
public int mask;
public int cxy;
[MarshalAs(UnmanagedType.LPTStr)] public string pszText;
public IntPtr hbm;
public int cchTextMax;
public int fmt;
public int lParam;
public int iImage;
public int iOrder;
};
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern IntPtr SendMessageItem(IntPtr handle, int msg, IntPtr wParam, ref HDITEM lParam);
}
要对单击的列应用排序,请使用 ColumnClick
事件:
private void advancedListView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
advancedListView1.Sorting = advancedListView1.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
advancedListView1.ListViewItemSorter = new ListViewSorter(advancedListView1.Sorting, e.Column, advancedListView1);
}
在 Windows 7 中,它看起来像您的屏幕截图。在我的 Windows 10 中,它看起来像这样:
您可以在 RowPostPaint
event or you can override OnRowPostPaint
method in a derived DataGridView
中突出显示鼠标指针下的行。在这种方法中,您可以自己绘制整行或只绘制其中的一部分或在该行上绘制一些东西:
例子
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyDataGridView : DataGridView
{
public MyDataGridView() { DoubleBuffered = true; }
protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e)
{
base.OnRowPostPaint(e);
if (this.RectangleToScreen(e.RowBounds).Contains(MousePosition))
{
using (var b = new SolidBrush(Color.FromArgb(50, Color.Blue)))
using (var p = new Pen(Color.Blue))
{
var r = e.RowBounds; r.Width -= 1; r.Height -= 1;
e.Graphics.FillRectangle(b, r);
e.Graphics.DrawRectangle(p, r);
}
}
}
protected override void OnMouseMove(MouseEventArgs e){
base.OnMouseMove(e); this.Invalidate();
}
protected override void OnMouseEnter(EventArgs e){
base.OnMouseEnter(e); this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e){
base.OnMouseLeave(e); this.Invalidate();
}
protected override void OnScroll(ScrollEventArgs e){
base.OnScroll(e); this.Invalidate();
}
}