#region FilterableHeaderCell
public class FilterableHeaderCell : DataGridViewColumnHeaderCell
{
private Rectangle dropdownButtonRect = Rectangle.Empty;
private bool dropdownOpen = false;
private ContextMenuStrip filterMenu = new ContextMenuStrip();
public HashSet<string> selectedFilters = new HashSet<string>();
private List<string> allFilterValues = new List<string>();
public List<DataGridViewRow> listAllRow = new List<DataGridViewRow>();
private string headerText = "";
public FilterableHeaderCell()
{
filterMenu.ItemClicked += FilterMenu_ItemClicked;
filterMenu.Closing += FilterMenu_Closing;
}
public FilterableHeaderCell(string headerText)
{
this.headerText = headerText;
filterMenu.ItemClicked += FilterMenu_ItemClicked;
filterMenu.Closing += FilterMenu_Closing;
}
public void Rest()
{
try
{
listAllRow.Clear();
foreach (DataGridViewRow row in this.DataGridView.Rows)
{
listAllRow.Add(row);
}
filterMenu.Items.Clear();
selectedFilters.Clear();
allFilterValues.Clear();
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex,
DataGridViewElementStates dataGridViewElementState, object value, object formattedValue,
string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
try
{
string showValue = string.IsNullOrEmpty(this.headerText) ? value.ToString() : this.headerText;
//string headerText = this.DataGridView.Columns[this.ColumnIndex].HeaderText;
// Draw the default header cell
base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, showValue,
showValue, errorText, cellStyle, advancedBorderStyle, paintParts);
int width = 8;
int height = 8;
// Define the rectangle for the dropdown button relative to the cellBounds.
dropdownButtonRect = new Rectangle(
cellBounds.Right - width - 2, // 15 pixels from the right edge of the cellBounds
cellBounds.Bottom - cellBounds.Height / 2 - height / 2, // 5 pixels from the top edge of the cellBounds
width, // 10 pixels wide
height// The height is the cell height minus 10 pixels
);
// Draw a custom dropdown button
/*// Draw the dropdown button
ControlPaint.DrawComboButton(graphics, dropdownButtonRect, ButtonState.Normal);
if (dropdownOpen)
{
ControlPaint.DrawComboButton(graphics, dropdownButtonRect, ButtonState.Pushed);
}*/
graphics.FillRectangle(Brushes.LightGray, dropdownButtonRect); // Change the color as needed
graphics.DrawRectangle(Pens.Black, dropdownButtonRect); // Draw border
// Create the path for the arrow
var arrowX = dropdownButtonRect.Left + dropdownButtonRect.Width / 2;
var arrowY = dropdownButtonRect.Top + dropdownButtonRect.Height / 2;
var arrowPath = new GraphicsPath();
arrowPath.AddLine(arrowX - 3, arrowY - 1, arrowX + 3, arrowY - 1);
arrowPath.AddLine(arrowX + 3, arrowY - 1, arrowX, arrowY + 2);
arrowPath.CloseFigure();
// Draw the arrow
graphics.FillPath(Brushes.Black, arrowPath); // Change the color as needed
if (dropdownOpen)
{
// Modify the appearance for when the dropdown is open
graphics.FillRectangle(Brushes.LightGray, dropdownButtonRect); // Change as needed
graphics.FillPath(Brushes.Black, arrowPath); // Change the color as needed
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
{
try
{
// 转换坐标,使之相对于列头单元格
Point cellRelativeCoords = new Point(e.X + this.DataGridView.GetCellDisplayRectangle(e.ColumnIndex, -1, true).Left, e.Y);
// 创建一个比可视按钮大的点击检测区域
Rectangle largerClickArea = new Rectangle(
dropdownButtonRect.Left, // 扩大点击区域
dropdownButtonRect.Top, // 扩大点击区域
dropdownButtonRect.Width, // 扩大点击区域
dropdownButtonRect.Height // 扩大点击区域
);
if (largerClickArea.Contains(cellRelativeCoords))
{
this.DataGridView.InvalidateCell(this);
// 变更下拉按钮的状态
// 显示筛选菜单
ShowFilterMenu();
return;
}
base.OnMouseDown(e);
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
{
try
{
// 转换坐标,使之相对于列头单元格
Point cellRelativeCoords = new Point(e.X + this.DataGridView.GetCellDisplayRectangle(e.ColumnIndex, -1, true).Left, e.Y);
// 创建一个比可视按钮大的点击检测区域
Rectangle largerClickArea = new Rectangle(
dropdownButtonRect.Left, // 扩大点击区域
dropdownButtonRect.Top, // 扩大点击区域
dropdownButtonRect.Width, // 扩大点击区域
dropdownButtonRect.Height // 扩大点击区域
);
Rectangle headcellArea = this.DataGridView.GetCellDisplayRectangle(this.ColumnIndex, this.RowIndex, false);
if (largerClickArea.Contains(cellRelativeCoords))
{
return;
}
if (filterMenu.Items.Count > 1)
{
if (headcellArea.Contains(cellRelativeCoords))
{
return;
}
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
base.OnMouseUp(e);
}
private void FilterMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
try
{
if (e.ClickedItem is ToolStripSeparator)
return;
ToolStripMenuItem clickedItem = (ToolStripMenuItem)e.ClickedItem;
string filterValue = clickedItem.Text;
// Handle the "All" option
if (filterValue == "All")
{
// If "All" is clicked, clear all filters and uncheck all other items
selectedFilters.Clear();
dropdownOpen = false;
foreach (ToolStripMenuItem item in filterMenu.Items.OfType<ToolStripMenuItem>())
{
item.Checked = false;
}
clickedItem.Checked = true; // Check the "All" item
}
else
{
// This is a regular filter item
clickedItem.Checked = !clickedItem.Checked; // Toggle the checked state
// Update the selected filters based on the item's checked state
if (clickedItem.Checked)
{
dropdownOpen = true;
selectedFilters.Add(filterValue);
// Uncheck the "All" item if any other item is checked
ToolStripMenuItem allItem = (ToolStripMenuItem)filterMenu.Items[0];
allItem.Checked = false;
}
else
{
selectedFilters.Remove(filterValue);
}
}
ApplyFilter();
clickedItem.Invalidate();
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
private void FilterMenu_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
try
{
// Prevent the menu from closing when an item is clicked.
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
{
e.Cancel = true;
(sender as ToolStripDropDownMenu).Invalidate();
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
private void ShowFilterMenu()
{
try
{
InitializeFilterMenu();
filterMenu.Show(this.DataGridView, this.DataGridView.GetCellDisplayRectangle(OwningColumn.Index, -1, true).Location);
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
private void InitializeFilterMenu()
{
try
{
filterMenu.Items.Clear();
foreach (DataGridViewRow row in this.DataGridView.Rows)
{
string value = row.Cells[this.ColumnIndex].Value.ToString();
if (!allFilterValues.Contains(value))
{
allFilterValues.Add(value);
}
}
allFilterValues.Sort();
//allFilterValues = GetUniqueValuesForColumn(this.OwningColumn.DataPropertyName);
ToolStripMenuItem allItem = new ToolStripMenuItem("All")
{
CheckOnClick = false,
Checked = selectedFilters.Count == 0
};
filterMenu.Items.Add(allItem);
filterMenu.Items.Add(new ToolStripSeparator()); // Add a separator
foreach (string value in allFilterValues)
{
ToolStripMenuItem item = new ToolStripMenuItem(value)
{
CheckOnClick = false,
Checked = selectedFilters.Contains(value)
};
filterMenu.Items.Add(item);
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
private void ApplyFilter()
{
try
{
//if (this.DataGridView?.DataSource is BindingSource bindingSource)
//{
// string filterString = CreateFilterString(selectedFilters);
// bindingSource.Filter = filterString;
//}
//else
//{
// // Debug.WriteLine("dfsdf");
//}
//if (listAllRow.Count == 0)
//{
// foreach (DataGridViewRow row in this.DataGridView.Rows)
// {
// listAllRow.Add(row);
// }
//}
//check has another filter
Dictionary<FilterableHeaderCell, HashSet<string>> dicHeaderCellFilter = new Dictionary<FilterableHeaderCell, HashSet<string>>();
foreach (DataGridViewColumn column in this.DataGridView.Columns)
{
var headerCell = column.HeaderCell;
if (headerCell is FilterableHeaderCell)
{
dicHeaderCellFilter[(FilterableHeaderCell)headerCell] = ((FilterableHeaderCell)headerCell).selectedFilters;
}
}
this.DataGridView.Rows.Clear();
List<DataGridViewRow> baseRows = new List<DataGridViewRow>();
foreach (DataGridViewRow row in listAllRow)
{
baseRows.Add(row);
}
foreach (var kvp in dicHeaderCellFilter)
{
FilterableHeaderCell headerCell = kvp.Key;
HashSet<string> filter = kvp.Value;
List<DataGridViewRow> listRemovedRow = new List<DataGridViewRow>();
foreach (DataGridViewRow row in baseRows)
{
string cellValue = row.Cells[headerCell.ColumnIndex].Value.ToString();
if (filter.Count > 0 && !filter.Contains(cellValue))
{
listRemovedRow.Add(row);
}
}
foreach (DataGridViewRow row in listRemovedRow)
{
baseRows.Remove(row);
}
}
foreach (DataGridViewRow row in baseRows)
{
this.DataGridView.Rows.Add(row);
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
}
private string CreateFilterString(HashSet<string> filters)
{
try
{
if (filters.Count == 0) return string.Empty;
var filterParts = filters.Select(f => string.Format("[{0}] = '{1}'", this.OwningColumn.DataPropertyName, f.Replace("'", "''")));
return string.Join(" OR ", filterParts);
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
return "";
}
private List<string> GetUniqueValuesForColumn(string dataPropertyName)
{
var uniqueValues = new HashSet<string>();
try
{
foreach (DataGridViewRow row in this.DataGridView.Rows)
{
if (!row.IsNewRow)
{
var value = row.Cells[dataPropertyName].Value?.ToString() ?? string.Empty;
uniqueValues.Add(value);
}
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message + ";" + ex.StackTrace);
}
return uniqueValues.ToList();
}
}
#endregion
#region 设置表头
List<DataGridViewColumn> listFilterColumns = new List<DataGridViewColumn>();
listFilterColumns.Add(clmSubWo);
listFilterColumns.Add(clmMaterialState);
listFilterColumns.Add(clmMaterialPartNumber);
listFilterColumns.Add(clmEquPartNumber);
listFilterColumns.Add(clmEquState);
foreach (DataGridViewColumn column in listFilterColumns)
{
column.HeaderCell = new FilterableHeaderCell(column.HeaderText);
}
#endregion
#region 初始化数据源
private void RestHeaderCell(DataGridView dataGridView)
{
try
{
foreach (DataGridViewColumn column in listFilterColumns)
{
if (dataGridView.Columns.Contains(column))
{
((FilterableHeaderCell)column.HeaderCell).Rest();
}
}
}
catch (Exception ex)
{
LogHelper.Error(ex.Message);
}
}
#endregion
//执行初始化
RestHeaderCell(gridMaterialBinNumber);
- 效果