c# Winfrom-DataGridView实现筛选功能
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Collections;
using System.Reflection; namespace DataGridViewAutoFilter
{ public class DataGridViewAutoFilterColumnHeaderCell : DataGridViewColumnHeaderCell
{
/// <summary>
/// The ListBox used for all drop-down lists.
/// </summary>
private FilterListBox dropDownListBox = new FilterListBox(); /// <summary>
/// A list of filters available for the owning column stored as
/// formatted and unformatted string values.
/// </summary>
private System.Collections.Specialized.OrderedDictionary filters =
new System.Collections.Specialized.OrderedDictionary(); /// <summary>
/// The drop-down list filter value currently in effect for the owning column.
/// </summary>
private String selectedFilterValue = String.Empty; /// <summary>
/// The complete filter string currently in effect for the owning column.
/// </summary>
private String currentColumnFilter = String.Empty; /// <summary>
/// Indicates whether the DataGridView is currently filtered by the owning column.
/// </summary>
private Boolean filtered; /// <summary>
/// Initializes a new instance of the DataGridViewColumnHeaderCell
/// class and sets its property values to the property values of the
/// specified DataGridViewColumnHeaderCell.
/// </summary>
/// <param name="oldHeaderCell">The DataGridViewColumnHeaderCell to copy property values from.</param>
public DataGridViewAutoFilterColumnHeaderCell(DataGridViewColumnHeaderCell oldHeaderCell)
{
this.ContextMenuStrip = oldHeaderCell.ContextMenuStrip;
this.ErrorText = oldHeaderCell.ErrorText;
this.Tag = oldHeaderCell.Tag;
this.ToolTipText = oldHeaderCell.ToolTipText;
this.Value = oldHeaderCell.Value;
this.ValueType = oldHeaderCell.ValueType; // Use HasStyle to avoid creating a new style object
// when the Style property has not previously been set.
if (oldHeaderCell.HasStyle)
{
this.Style = oldHeaderCell.Style;
} // Copy this type's properties if the old cell is an auto-filter cell.
// This enables the Clone method to reuse this constructor.
DataGridViewAutoFilterColumnHeaderCell filterCell =
oldHeaderCell as DataGridViewAutoFilterColumnHeaderCell;
if (filterCell != null)
{
this.FilteringEnabled = filterCell.FilteringEnabled;
this.AutomaticSortingEnabled = filterCell.AutomaticSortingEnabled;
this.DropDownListBoxMaxLines = filterCell.DropDownListBoxMaxLines;
this.currentDropDownButtonPaddingOffset =
filterCell.currentDropDownButtonPaddingOffset;
}
} /// <summary>
/// Initializes a new instance of the DataGridViewColumnHeaderCell
/// class.
/// </summary>
public DataGridViewAutoFilterColumnHeaderCell()
{
} /// <summary>
/// Creates an exact copy of this cell.
/// </summary>
/// <returns>An object that represents the cloned DataGridViewAutoFilterColumnHeaderCell.</returns>
public override object Clone()
{
return new DataGridViewAutoFilterColumnHeaderCell(this);
} /// <summary>
/// Called when the value of the DataGridView property changes
/// in order to perform initialization that requires access to the
/// owning control and column.
/// </summary>
/// protected override void OnDataGridViewChanged()
{
// Continue only if there is a DataGridView.
if (this.DataGridView == null)
{
return;
} // Disable sorting and filtering for columns that can't make
// effective use of them.
if (OwningColumn != null)
{
if (OwningColumn is DataGridViewImageColumn ||
(OwningColumn is DataGridViewButtonColumn &&
((DataGridViewButtonColumn)OwningColumn).UseColumnTextForButtonValue) ||
(OwningColumn is DataGridViewLinkColumn &&
((DataGridViewLinkColumn)OwningColumn).UseColumnTextForLinkValue))
{
AutomaticSortingEnabled = false;
FilteringEnabled = false;
} // Ensure that the column SortMode property value is not Automatic.
// This prevents sorting when the user clicks the drop-down button.
if (OwningColumn.SortMode == DataGridViewColumnSortMode.Automatic)
{
OwningColumn.SortMode = DataGridViewColumnSortMode.Programmatic;
}
} // Confirm that the data source meets requirements.
VerifyDataSource(); // Add handlers to DataGridView events.
HandleDataGridViewEvents(); // Initialize the drop-down button bounds so that any initial
// column autosizing will accommodate the button width.
SetDropDownButtonBounds(); // Call the OnDataGridViewChanged method on the base class to
// raise the DataGridViewChanged event.
base.OnDataGridViewChanged();
} /// <summary>
/// Confirms that the data source, if it has been set, is a BindingSource.
/// </summary>
private void VerifyDataSource()
{
// Continue only if there is a DataGridView and its DataSource has been set.
if (this.DataGridView == null || this.DataGridView.DataSource == null)
{
return;
} // Throw an exception if the data source is not a BindingSource.
BindingSource data = this.DataGridView.DataSource as BindingSource;
if (data == null)
{
throw new NotSupportedException(
"The DataSource property of the containing DataGridView control " +
"must be set to a BindingSource.");
}
} #region DataGridView events: HandleDataGridViewEvents, DataGridView event handlers, ResetDropDown, ResetFilter /// <summary>
/// Add handlers to various DataGridView events, primarily to invalidate
/// the drop-down button bounds, hide the drop-down list, and reset
/// cached filter values when changes in the DataGridView require it.
/// </summary>
private void HandleDataGridViewEvents()
{
this.DataGridView.Scroll += new ScrollEventHandler(DataGridView_Scroll);
this.DataGridView.ColumnDisplayIndexChanged += new DataGridViewColumnEventHandler(DataGridView_ColumnDisplayIndexChanged);
this.DataGridView.ColumnWidthChanged += new DataGridViewColumnEventHandler(DataGridView_ColumnWidthChanged);
this.DataGridView.ColumnHeadersHeightChanged += new EventHandler(DataGridView_ColumnHeadersHeightChanged);
this.DataGridView.SizeChanged += new EventHandler(DataGridView_SizeChanged);
this.DataGridView.DataSourceChanged += new EventHandler(DataGridView_DataSourceChanged);
this.DataGridView.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(DataGridView_DataBindingComplete); // Add a handler for the ColumnSortModeChanged event to prevent the
// column SortMode property from being inadvertently set to Automatic.
this.DataGridView.ColumnSortModeChanged += new DataGridViewColumnEventHandler(DataGridView_ColumnSortModeChanged);
} /// <summary>
/// Invalidates the drop-down button bounds when the user scrolls horizontally.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A ScrollEventArgs that contains the event data.</param>
private void DataGridView_Scroll(object sender, ScrollEventArgs e)
{
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
ResetDropDown();
}
} /// <summary>
/// Invalidates the drop-down button bounds when the column display index changes.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataGridView_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
ResetDropDown();
} /// <summary>
/// Invalidates the drop-down button bounds when a column width changes
/// in the DataGridView control. A width change in any column of the
/// control has the potential to affect the drop-down button location,
/// depending on the current horizontal scrolling position and whether
/// the changed column is to the left or right of the current column.
/// It is easier to invalidate the button in all cases.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A DataGridViewColumnEventArgs that contains the event data.</param>
private void DataGridView_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
ResetDropDown();
} /// <summary>
/// Invalidates the drop-down button bounds when the height of the column headers changes.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">An EventArgs that contains the event data.</param>
private void DataGridView_ColumnHeadersHeightChanged(object sender, EventArgs e)
{
ResetDropDown();
} /// <summary>
/// Invalidates the drop-down button bounds when the size of the DataGridView changes.
/// This prevents a painting issue that occurs when the right edge of the control moves
/// to the right and the control contents have previously been scrolled to the right.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">An EventArgs that contains the event data.</param>
private void DataGridView_SizeChanged(object sender, EventArgs e)
{
ResetDropDown();
} /// <summary>
/// Invalidates the drop-down button bounds, hides the drop-down
/// filter list, if it is showing, and resets the cached filter values
/// if the filter has been removed.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A DataGridViewBindingCompleteEventArgs that contains the event data.</param>
private void DataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType == ListChangedType.Reset)
{
ResetDropDown();
ResetFilter();
}
} /// <summary>
/// Verifies that the data source meets requirements, invalidates the
/// drop-down button bounds, hides the drop-down filter list if it is
/// showing, and resets the cached filter values if the filter has been removed.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">An EventArgs that contains the event data.</param>
private void DataGridView_DataSourceChanged(object sender, EventArgs e)
{
VerifyDataSource();
ResetDropDown();
ResetFilter();
} /// <summary>
/// Invalidates the drop-down button bounds and hides the filter
/// list if it is showing.
/// </summary>
private void ResetDropDown()
{
InvalidateDropDownButtonBounds();
if (dropDownListBoxShowing)
{
HideDropDownList();
}
} /// <summary>
/// Resets the cached filter values if the filter has been removed.
/// </summary>
private void ResetFilter()
{
if (this.DataGridView == null) return;
BindingSource source = this.DataGridView.DataSource as BindingSource;
if (source == null || String.IsNullOrEmpty(source.Filter))
{
filtered = false;
selectedFilterValue = "(All)";
currentColumnFilter = String.Empty;
}
} /// <summary>
/// Throws an exception when the column sort mode is changed to Automatic.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A DataGridViewColumnEventArgs that contains the event data.</param>
private void DataGridView_ColumnSortModeChanged(object sender, DataGridViewColumnEventArgs e)
{
if (e.Column == OwningColumn &&
e.Column.SortMode == DataGridViewColumnSortMode.Automatic)
{
throw new InvalidOperationException(
"A SortMode value of Automatic is incompatible with " +
"the DataGridViewAutoFilterColumnHeaderCell type. " +
"Use the AutomaticSortingEnabled property instead.");
}
} #endregion DataGridView events /// <summary>
/// Paints the column header cell, including the drop-down button.
/// </summary>
/// <param name="graphics">The Graphics used to paint the DataGridViewCell.</param>
/// <param name="clipBounds">A Rectangle that represents the area of the DataGridView that needs to be repainted.</param>
/// <param name="cellBounds">A Rectangle that contains the bounds of the DataGridViewCell that is being painted.</param>
/// <param name="rowIndex">The row index of the cell that is being painted.</param>
/// <param name="cellState">A bitwise combination of DataGridViewElementStates values that specifies the state of the cell.</param>
/// <param name="value">The data of the DataGridViewCell that is being painted.</param>
/// <param name="formattedValue">The formatted data of the DataGridViewCell that is being painted.</param>
/// <param name="errorText">An error message that is associated with the cell.</param>
/// <param name="cellStyle">A DataGridViewCellStyle that contains formatting and style information about the cell.</param>
/// <param name="advancedBorderStyle">A DataGridViewAdvancedBorderStyle that contains border styles for the cell that is being painted.</param>
/// <param name="paintParts">A bitwise combination of the DataGridViewPaintParts values that specifies which parts of the cell need to be painted.</param>
protected override void Paint(
Graphics graphics, Rectangle clipBounds, Rectangle cellBounds,
int rowIndex, DataGridViewElementStates cellState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
// Use the base method to paint the default appearance.
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
cellState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts); // Continue only if filtering is enabled and ContentBackground is
// part of the paint request.
if (!FilteringEnabled ||
(paintParts & DataGridViewPaintParts.ContentBackground) == )
{
return;
} // Retrieve the current button bounds.
Rectangle buttonBounds = DropDownButtonBounds; // Continue only if the buttonBounds is big enough to draw.
if (buttonBounds.Width < || buttonBounds.Height < ) return; // Paint the button manually or using visual styles if visual styles
// are enabled, using the correct state depending on whether the
// filter list is showing and whether there is a filter in effect
// for the current column.
if (Application.RenderWithVisualStyles)
{
ComboBoxState state = ComboBoxState.Normal; if (dropDownListBoxShowing)
{
state = ComboBoxState.Pressed;
}
else if (filtered)
{
state = ComboBoxState.Hot;
}
ComboBoxRenderer.DrawDropDownButton(
graphics, buttonBounds, state);
}
else
{
// Determine the pressed state in order to paint the button
// correctly and to offset the down arrow.
Int32 pressedOffset = ;
PushButtonState state = PushButtonState.Normal;
if (dropDownListBoxShowing)
{
state = PushButtonState.Pressed;
pressedOffset = ;
}
ButtonRenderer.DrawButton(graphics, buttonBounds, state); // If there is a filter in effect for the column, paint the
// down arrow as an unfilled triangle. If there is no filter
// in effect, paint the down arrow as a filled triangle.
if (filtered)
{
graphics.DrawPolygon(SystemPens.ControlText, new Point[] {
new Point(
buttonBounds.Width / +
buttonBounds.Left - + pressedOffset,
buttonBounds.Height * / +
buttonBounds.Top - + pressedOffset),
new Point(
buttonBounds.Width / +
buttonBounds.Left + pressedOffset,
buttonBounds.Height / +
buttonBounds.Top - + pressedOffset),
new Point(
buttonBounds.Width * / +
buttonBounds.Left - + pressedOffset,
buttonBounds.Height / +
buttonBounds.Top - + pressedOffset)
});
}
else
{
graphics.FillPolygon(SystemBrushes.ControlText, new Point[] {
new Point(
buttonBounds.Width / +
buttonBounds.Left - + pressedOffset,
buttonBounds.Height * / +
buttonBounds.Top - + pressedOffset),
new Point(
buttonBounds.Width / +
buttonBounds.Left + pressedOffset,
buttonBounds.Height / +
buttonBounds.Top - + pressedOffset),
new Point(
buttonBounds.Width * / +
buttonBounds.Left - + pressedOffset,
buttonBounds.Height / +
buttonBounds.Top - + pressedOffset)
});
}
} } /// <summary>
/// Handles mouse clicks to the header cell, displaying the
/// drop-down list or sorting the owning column as appropriate.
/// </summary>
/// <param name="e">A DataGridViewCellMouseEventArgs that contains the event data.</param>
protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
{
Debug.Assert(this.DataGridView != null, "DataGridView is null"); // Continue only if the user did not click the drop-down button
// while the drop-down list was displayed. This prevents the
// drop-down list from being redisplayed after being hidden in
// the LostFocus event handler.
if (lostFocusOnDropDownButtonClick)
{
lostFocusOnDropDownButtonClick = false;
return;
} // Retrieve the current size and location of the header cell,
// excluding any portion that is scrolled off screen.
Rectangle cellBounds = this.DataGridView
.GetCellDisplayRectangle(e.ColumnIndex, -, false); // Continue only if the column is not manually resizable or the
// mouse coordinates are not within the column resize zone.
if (this.OwningColumn.Resizable == DataGridViewTriState.True &&
((this.DataGridView.RightToLeft == RightToLeft.No &&
cellBounds.Width - e.X < ) || e.X < ))
{
return;
} // Unless RightToLeft is enabled, store the width of the portion
// that is scrolled off screen.
Int32 scrollingOffset = ;
if (this.DataGridView.RightToLeft == RightToLeft.No &&
this.DataGridView.FirstDisplayedScrollingColumnIndex ==
this.ColumnIndex)
{
scrollingOffset =
this.DataGridView.FirstDisplayedScrollingColumnHiddenWidth;
} // Show the drop-down list if filtering is enabled and the mouse click occurred
// within the drop-down button bounds. Otherwise, if sorting is enabled and the
// click occurred outside the drop-down button bounds, sort by the owning column.
// The mouse coordinates are relative to the cell bounds, so the cell location
// and the scrolling offset are needed to determine the client coordinates.
if (FilteringEnabled &&
DropDownButtonBounds.Contains(
e.X + cellBounds.Left - scrollingOffset, e.Y + cellBounds.Top))
{
// If the current cell is in edit mode, commit the edit.
if (this.DataGridView.IsCurrentCellInEditMode)
{
// Commit and end the cell edit.
this.DataGridView.EndEdit(); // Commit any change to the underlying data source.
BindingSource source =
this.DataGridView.DataSource as BindingSource;
if (source != null)
{
source.EndEdit();
}
}
ShowDropDownList();
}
else if (AutomaticSortingEnabled &&
this.DataGridView.SelectionMode !=
DataGridViewSelectionMode.ColumnHeaderSelect)
{
SortByColumn();
} base.OnMouseDown(e);
} /// <summary>
/// Sorts the DataGridView by the current column if AutomaticSortingEnabled is true.
/// </summary>
private void SortByColumn()
{
Debug.Assert(this.DataGridView != null && OwningColumn != null, "DataGridView or OwningColumn is null"); // Continue only if the data source supports sorting.
IBindingList sortList = this.DataGridView.DataSource as IBindingList;
if (sortList == null ||
!sortList.SupportsSorting ||
!AutomaticSortingEnabled)
{
return;
} // Determine the sort direction and sort by the owning column.
ListSortDirection direction = ListSortDirection.Ascending;
if (this.DataGridView.SortedColumn == OwningColumn &&
this.DataGridView.SortOrder == SortOrder.Ascending)
{
direction = ListSortDirection.Descending;
}
this.DataGridView.Sort(OwningColumn, direction);
} #region drop-down list: Show/HideDropDownListBox, SetDropDownListBoxBounds, DropDownListBoxMaxHeightInternal /// <summary>
/// Indicates whether dropDownListBox is currently displayed
/// for this header cell.
/// </summary>
private bool dropDownListBoxShowing; /// <summary>
/// Displays the drop-down filter list.
/// </summary>
public void ShowDropDownList()
{
Debug.Assert(this.DataGridView != null, "DataGridView is null"); // Ensure that the current row is not the row for new records.
// This prevents the new row from affecting the filter list and also
// prevents the new row from being added when the filter changes.
if (this.DataGridView.CurrentRow != null &&
this.DataGridView.CurrentRow.IsNewRow)
{
this.DataGridView.CurrentCell = null;
} // Populate the filters dictionary, then copy the filter values
// from the filters.Keys collection into the ListBox.Items collection,
// selecting the current filter if there is one in effect.
PopulateFilters(); String[] filterArray = new String[filters.Count];
filters.Keys.CopyTo(filterArray, );
dropDownListBox.Items.Clear();
dropDownListBox.Items.AddRange(filterArray);
dropDownListBox.SelectedItem = selectedFilterValue; // Add handlers to dropDownListBox events.
HandleDropDownListBoxEvents(); // Set the size and location of dropDownListBox, then display it.
SetDropDownListBoxBounds();
dropDownListBox.Visible = true;
dropDownListBoxShowing = true; Debug.Assert(dropDownListBox.Parent == null,
"ShowDropDownListBox has been called multiple times before HideDropDownListBox"); // Add dropDownListBox to the DataGridView.
this.DataGridView.Controls.Add(dropDownListBox); // Set the input focus to dropDownListBox.
dropDownListBox.Focus(); // Invalidate the cell so that the drop-down button will repaint
// in the pressed state.
this.DataGridView.InvalidateCell(this);
} /// <summary>
/// Hides the drop-down filter list.
/// </summary>
public void HideDropDownList()
{
if (DataGridView != null)
{
Debug.Assert(this.DataGridView != null, "DataGridView is null"); // Hide dropDownListBox, remove handlers from its events, and remove
// it from the DataGridView control.
dropDownListBoxShowing = false;
dropDownListBox.Visible = false;
UnhandleDropDownListBoxEvents();
this.DataGridView.Controls.Remove(dropDownListBox); // Invalidate the cell so that the drop-down button will repaint
// in the unpressed state.
this.DataGridView.InvalidateCell(this);
}
} /// <summary>
/// Sets the dropDownListBox size and position based on the formatted
/// values in the filters dictionary and the position of the drop-down
/// button. Called only by ShowDropDownListBox.
/// </summary>
private void SetDropDownListBoxBounds()
{
Debug.Assert(filters.Count > , "filters.Count <= 0"); // Declare variables that will be used in the calculation,
// initializing dropDownListBoxHeight to account for the
// ListBox borders.
Int32 dropDownListBoxHeight = ;
Int32 currentWidth = ;
Int32 dropDownListBoxWidth = ;
Int32 dropDownListBoxLeft = ; // For each formatted value in the filters dictionary Keys collection,
// add its height to dropDownListBoxHeight and, if it is wider than
// all previous values, set dropDownListBoxWidth to its width.
using (Graphics graphics = dropDownListBox.CreateGraphics())
{
foreach (String filter in filters.Keys)
{
SizeF stringSizeF = graphics.MeasureString(
filter, dropDownListBox.Font);
dropDownListBoxHeight += (Int32)stringSizeF.Height;
currentWidth = (Int32)stringSizeF.Width;
if (dropDownListBoxWidth < currentWidth)
{
dropDownListBoxWidth = currentWidth;
}
}
} // Increase the width to allow for horizontal margins and borders.
dropDownListBoxWidth += ; // Constrain the dropDownListBox height to the
// DropDownListBoxMaxHeightInternal value, which is based on
// the DropDownListBoxMaxLines property value but constrained by
// the maximum height available in the DataGridView control.
if (dropDownListBoxHeight > DropDownListBoxMaxHeightInternal)
{
dropDownListBoxHeight = DropDownListBoxMaxHeightInternal; // If the preferred height is greater than the available height,
// adjust the width to accommodate the vertical scroll bar.
dropDownListBoxWidth += SystemInformation.VerticalScrollBarWidth;
} // Calculate the ideal location of the left edge of dropDownListBox
// based on the location of the drop-down button and taking the
// RightToLeft property value into consideration.
if (this.DataGridView.RightToLeft == RightToLeft.No)
{
dropDownListBoxLeft = DropDownButtonBounds.Right -
dropDownListBoxWidth + ;
}
else
{
dropDownListBoxLeft = DropDownButtonBounds.Left - ;
} // Determine the left and right edges of the available horizontal
// width of the DataGridView control.
Int32 clientLeft = ;
Int32 clientRight = this.DataGridView.ClientRectangle.Right;
if (this.DataGridView.DisplayedRowCount(false) <
this.DataGridView.RowCount)
{
if (this.DataGridView.RightToLeft == RightToLeft.Yes)
{
clientLeft += SystemInformation.VerticalScrollBarWidth;
}
else
{
clientRight -= SystemInformation.VerticalScrollBarWidth;
}
} // Adjust the dropDownListBox location and/or width if it would
// otherwise overlap the left or right edge of the DataGridView.
if (dropDownListBoxLeft < clientLeft)
{
dropDownListBoxLeft = clientLeft;
}
Int32 dropDownListBoxRight =
dropDownListBoxLeft + dropDownListBoxWidth + ;
if (dropDownListBoxRight > clientRight)
{
if (dropDownListBoxLeft == clientLeft)
{
dropDownListBoxWidth -=
dropDownListBoxRight - clientRight;
}
else
{
dropDownListBoxLeft -=
dropDownListBoxRight - clientRight;
if (dropDownListBoxLeft < clientLeft)
{
dropDownListBoxWidth -= clientLeft - dropDownListBoxLeft;
dropDownListBoxLeft = clientLeft;
}
}
} // Set the ListBox.Bounds property using the calculated values.
dropDownListBox.Bounds = new Rectangle(dropDownListBoxLeft,
DropDownButtonBounds.Bottom, // top of drop-down list box
dropDownListBoxWidth, dropDownListBoxHeight);
} /// <summary>
/// Gets the actual maximum height of the drop-down list, in pixels.
/// The maximum height is calculated from the DropDownListBoxMaxLines
/// property value, but is limited to the available height of the
/// DataGridView control.
/// </summary>
protected Int32 DropDownListBoxMaxHeightInternal
{
get
{
// Calculate the height of the available client area
// in the DataGridView control, taking the horizontal
// scroll bar into consideration and leaving room
// for the ListBox bottom border.
Int32 dataGridViewMaxHeight = this.DataGridView.Height -
this.DataGridView.ColumnHeadersHeight - ;
if (this.DataGridView.DisplayedColumnCount(false) <
this.DataGridView.ColumnCount)
{
dataGridViewMaxHeight -=
SystemInformation.HorizontalScrollBarHeight;
} // Calculate the height of the list box, using the combined
// height of all items plus 2 for the top and bottom border.
Int32 listMaxHeight = dropDownListBoxMaxLinesValue * dropDownListBox.ItemHeight + ; // Return the smaller of the two values.
if (listMaxHeight < dataGridViewMaxHeight)
{
return listMaxHeight;
}
else
{
return dataGridViewMaxHeight;
}
}
} #endregion drop-down list #region ListBox events: HandleDropDownListBoxEvents, UnhandleDropDownListBoxEvents, ListBox event handlers /// <summary>
/// Adds handlers to ListBox events for handling mouse
/// and keyboard input.
/// </summary>
private void HandleDropDownListBoxEvents()
{
dropDownListBox.MouseClick += new MouseEventHandler(DropDownListBox_MouseClick);
dropDownListBox.LostFocus += new EventHandler(DropDownListBox_LostFocus);
dropDownListBox.KeyDown += new KeyEventHandler(DropDownListBox_KeyDown);
} /// <summary>
/// Removes the ListBox event handlers.
/// </summary>
private void UnhandleDropDownListBoxEvents()
{
dropDownListBox.MouseClick -= new MouseEventHandler(DropDownListBox_MouseClick);
dropDownListBox.LostFocus -= new EventHandler(DropDownListBox_LostFocus);
dropDownListBox.KeyDown -= new KeyEventHandler(DropDownListBox_KeyDown);
} /// <summary>
/// Adjusts the filter in response to a user selection from the drop-down list.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A MouseEventArgs that contains the event data.</param>
private void DropDownListBox_MouseClick(object sender, MouseEventArgs e)
{
Debug.Assert(this.DataGridView != null, "DataGridView is null"); // Continue only if the mouse click was in the content area
// and not on the scroll bar.
if (!dropDownListBox.DisplayRectangle.Contains(e.X, e.Y))
{
return;
} UpdateFilter();
HideDropDownList();
} /// <summary>
/// Indicates whether the drop-down list lost focus because the
/// user clicked the drop-down button.
/// </summary>
private Boolean lostFocusOnDropDownButtonClick; /// <summary>
/// Hides the drop-down list when it loses focus.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">An EventArgs that contains the event data.</param>
private void DropDownListBox_LostFocus(object sender, EventArgs e)
{
// If the focus was lost because the user clicked the drop-down
// button, store a value that prevents the subsequent OnMouseDown
// call from displaying the drop-down list again.
if (DropDownButtonBounds.Contains(
this.DataGridView.PointToClient(new Point(
Control.MousePosition.X, Control.MousePosition.Y))))
{
lostFocusOnDropDownButtonClick = true;
}
HideDropDownList();
} /// <summary>
/// Handles the ENTER and ESC keys.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">A KeyEventArgs that contains the event data.</param>
void DropDownListBox_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Enter:
UpdateFilter();
HideDropDownList();
break;
case Keys.Escape:
HideDropDownList();
break;
}
} #endregion ListBox events #region filtering: PopulateFilters, FilterWithoutCurrentColumn, UpdateFilter, RemoveFilter, AvoidNewRowWhenFiltering, GetFilterStatus /// <summary>
/// Populates the filters dictionary with formatted and unformatted string
/// representations of each unique value in the column, accounting for all
/// filters except the current column's. Also adds special filter options.
/// </summary>
private void PopulateFilters()
{
// Continue only if there is a DataGridView.
if (this.DataGridView == null)
{
return;
} // Cast the data source to a BindingSource.
BindingSource data = this.DataGridView.DataSource as BindingSource; Debug.Assert(data != null && data.SupportsFiltering && OwningColumn != null,
"DataSource is not a BindingSource, or does not support filtering, or OwningColumn is null"); // Prevent the data source from notifying the DataGridView of changes.
data.RaiseListChangedEvents = false; // Cache the current BindingSource.Filter value and then change
// the Filter property to temporarily remove any filter for the
// current column.
String oldFilter = data.Filter;
data.Filter = FilterWithoutCurrentColumn(oldFilter); // Reset the filters dictionary and initialize some flags
// to track whether special filter options are needed.
filters.Clear();
Boolean containsBlanks = false;
Boolean containsNonBlanks = false; // Initialize an ArrayList to store the values in their original
// types. This enables the values to be sorted appropriately.
ArrayList list = new ArrayList(data.Count); // Retrieve each value and add it to the ArrayList if it isn't
// already present.
foreach (Object item in data)
{
Object value = null; // Use the ICustomTypeDescriptor interface to retrieve properties
// if it is available; otherwise, use reflection. The
// ICustomTypeDescriptor interface is useful to customize
// which values are exposed as properties. For example, the
// DataRowView class implements ICustomTypeDescriptor to expose
// cell values as property values.
//
// Iterate through the property names to find a case-insensitive
// match with the DataGridViewColumn.DataPropertyName value.
// This is necessary because DataPropertyName is case-
// insensitive, but the GetProperties and GetProperty methods
// used below are case-sensitive.
ICustomTypeDescriptor ictd = item as ICustomTypeDescriptor;
if (ictd != null)
{
PropertyDescriptorCollection properties = ictd.GetProperties();
foreach (PropertyDescriptor property in properties)
{
if (String.Compare(this.OwningColumn.DataPropertyName,
property.Name, true /*case insensitive*/,
System.Globalization.CultureInfo.InvariantCulture) == )
{
value = property.GetValue(item);
break;
}
}
}
else
{
PropertyInfo[] properties = item.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
if (String.Compare(this.OwningColumn.DataPropertyName,
property.Name, true /*case insensitive*/,
System.Globalization.CultureInfo.InvariantCulture) == )
{
value = property.GetValue(item, null /*property index*/);
break;
}
}
} // Skip empty values, but note that they are present.
if (value == null || value == DBNull.Value)
{
containsBlanks = true;
continue;
} // Add values to the ArrayList if they are not already there.
if (!list.Contains(value))
{
list.Add(value);
}
} // Sort the ArrayList. The default Sort method uses the IComparable
// implementation of the stored values so that string, numeric, and
// date values will all be sorted correctly.
list.Sort(); // Convert each value in the ArrayList to its formatted representation
// and store both the formatted and unformatted string representations
// in the filters dictionary.
foreach (Object value in list)
{
// Use the cell's GetFormattedValue method with the column's
// InheritedStyle property so that the dropDownListBox format
// will match the display format used for the column's cells.
String formattedValue = null;
DataGridViewCellStyle style = OwningColumn.InheritedStyle;
formattedValue = (String)GetFormattedValue(value, -, ref style,
null, null, DataGridViewDataErrorContexts.Formatting); if (String.IsNullOrEmpty(formattedValue))
{
// Skip empty values, but note that they are present.
containsBlanks = true;
}
else if (!filters.Contains(formattedValue))
{
// Note whether non-empty values are present.
containsNonBlanks = true; // For all non-empty values, add the formatted and
// unformatted string representations to the filters
// dictionary.
filters.Add(formattedValue, value.ToString());
}
} // Restore the filter to the cached filter string and
// re-enable data source change notifications.
if (oldFilter != null) data.Filter = oldFilter;
data.RaiseListChangedEvents = true; // Add special filter options to the filters dictionary
// along with null values, since unformatted representations
// are not needed.
filters.Insert(, "(All)", null);
if (containsBlanks && containsNonBlanks)
{
filters.Add("(Blanks)", null);
filters.Add("(NonBlanks)", null);
}
} /// <summary>
/// Returns a copy of the specified filter string after removing the part that filters the current column, if present.
/// </summary>
/// <param name="filter">The filter string to parse.</param>
/// <returns>A copy of the specified filter string without the current column's filter.</returns>
private String FilterWithoutCurrentColumn(String filter)
{
// If there is no filter in effect, return String.Empty.
if (String.IsNullOrEmpty(filter))
{
return String.Empty;
} // If the column is not filtered, return the filter string unchanged.
if (!filtered)
{
return filter;
} if (filter.IndexOf(currentColumnFilter) > )
{
// If the current column filter is not the first filter, return
// the specified filter value without the current column filter
// and without the preceding " AND ".
return filter.Replace(
" AND " + currentColumnFilter, String.Empty);
}
else
{
if (filter.Length > currentColumnFilter.Length)
{
// If the current column filter is the first of multiple
// filters, return the specified filter value without the
// current column filter and without the subsequent " AND ".
return filter.Replace(
currentColumnFilter + " AND ", String.Empty);
}
else
{
// If the current column filter is the only filter,
// return the empty string.
return String.Empty;
}
}
} /// <summary>
/// Updates the BindingSource.Filter value based on a user selection
/// from the drop-down filter list.
/// </summary>
private void UpdateFilter()
{
// Continue only if the selection has changed.
if (dropDownListBox.SelectedItem.ToString().Equals(selectedFilterValue))
{
return;
} // Store the new selection value.
selectedFilterValue = dropDownListBox.SelectedItem.ToString(); // Cast the data source to an IBindingListView.
IBindingListView data =
this.DataGridView.DataSource as IBindingListView; Debug.Assert(data != null && data.SupportsFiltering,
"DataSource is not an IBindingListView or does not support filtering"); // If the user selection is (All), remove any filter currently
// in effect for the column.
if (selectedFilterValue.Equals("(All)"))
{
data.Filter = FilterWithoutCurrentColumn(data.Filter);
filtered = false;
currentColumnFilter = String.Empty;
return;
} // Declare a variable to store the filter string for this column.
String newColumnFilter = null; // Store the column name in a form acceptable to the Filter property,
// using a backslash to escape any closing square brackets.
String columnProperty =
OwningColumn.DataPropertyName.Replace("]", @"\]"); // Determine the column filter string based on the user selection.
// For (Blanks) and (NonBlanks), the filter string determines whether
// the column value is null or an empty string. Otherwise, the filter
// string determines whether the column value is the selected value.
switch (selectedFilterValue)
{
case "(Blanks)":
newColumnFilter = String.Format(
"LEN(ISNULL(CONVERT([{0}],'System.String'),''))=0",
columnProperty);
break;
case "(NonBlanks)":
newColumnFilter = String.Format(
"LEN(ISNULL(CONVERT([{0}],'System.String'),''))>0",
columnProperty);
break;
default:
newColumnFilter = String.Format("[{0}]='{1}'",
columnProperty,
((String)filters[selectedFilterValue])
.Replace("'", "''"));
break;
} // Determine the new filter string by removing the previous column
// filter string from the BindingSource.Filter value, then appending
// the new column filter string, using " AND " as appropriate.
String newFilter = FilterWithoutCurrentColumn(data.Filter);
if (String.IsNullOrEmpty(newFilter))
{
newFilter += newColumnFilter;
}
else
{
newFilter += " AND " + newColumnFilter;
} // Set the filter to the new value.
try
{
data.Filter = newFilter;
}
catch (InvalidExpressionException ex)
{
throw new NotSupportedException(
"Invalid expression: " + newFilter, ex);
} // Indicate that the column is currently filtered
// and store the new column filter for use by subsequent
// calls to the FilterWithoutCurrentColumn method.
filtered = true;
currentColumnFilter = newColumnFilter;
} /// <summary>
/// Removes the filter from the BindingSource bound to the specified DataGridView.
/// </summary>
/// <param name="dataGridView">The DataGridView bound to the BindingSource to unfilter.</param>
public static void RemoveFilter(DataGridView dataGridView)
{
if (dataGridView == null)
{
throw new ArgumentNullException("dataGridView");
} // Cast the data source to a BindingSource.
BindingSource data = dataGridView.DataSource as BindingSource; // Confirm that the data source is a BindingSource that
// supports filtering.
if (data == null ||
data.DataSource == null ||
!data.SupportsFiltering)
{
throw new ArgumentException("The DataSource property of the " +
"specified DataGridView is not set to a BindingSource " +
"with a SupportsFiltering property value of true.");
} // Ensure that the current row is not the row for new records.
// This prevents the new row from being added when the filter changes.
if (dataGridView.CurrentRow != null && dataGridView.CurrentRow.IsNewRow)
{
dataGridView.CurrentCell = null;
} // Remove the filter.
data.Filter = null;
} /// <summary>
/// Gets a status string for the specified DataGridView indicating the
/// number of visible rows in the bound, filtered BindingSource, or
/// String.Empty if all rows are currently visible.
/// </summary>
/// <param name="dataGridView">The DataGridView bound to the
/// BindingSource to return the filter status for.</param>
/// <returns>A string in the format "x of y records found" where x is
/// the number of rows currently displayed and y is the number of rows
/// available, or String.Empty if all rows are currently displayed.</returns>
public static String GetFilterStatus(DataGridView dataGridView)
{
// Continue only if the specified value is valid.
if (dataGridView == null)
{
throw new ArgumentNullException("dataGridView");
} // Cast the data source to a BindingSource.
BindingSource data = dataGridView.DataSource as BindingSource; // Return String.Empty if there is no appropriate data source or
// there is no filter in effect.
if (String.IsNullOrEmpty(data.Filter) ||
data == null ||
data.DataSource == null ||
!data.SupportsFiltering)
{
return String.Empty;
} // Retrieve the filtered row count.
Int32 currentRowCount = data.Count; // Retrieve the unfiltered row count by
// temporarily unfiltering the data.
data.RaiseListChangedEvents = false;
String oldFilter = data.Filter;
data.Filter = null;
Int32 unfilteredRowCount = data.Count;
data.Filter = oldFilter;
data.RaiseListChangedEvents = true; Debug.Assert(currentRowCount <= unfilteredRowCount,
"current count is greater than unfiltered count"); // Return String.Empty if the filtered and unfiltered counts
// are the same, otherwise, return the status string.
if (currentRowCount == unfilteredRowCount)
{
return String.Empty;
}
return String.Format("{0}",
currentRowCount, unfilteredRowCount);
//of {1} records found
} #endregion filtering #region button bounds: DropDownButtonBounds, InvalidateDropDownButtonBounds, SetDropDownButtonBounds, AdjustPadding /// <summary>
/// The bounds of the drop-down button, or Rectangle.Empty if filtering
/// is disabled or the button bounds need to be recalculated.
/// </summary>
private Rectangle dropDownButtonBoundsValue = Rectangle.Empty; /// <summary>
/// The bounds of the drop-down button, or Rectangle.Empty if filtering
/// is disabled. Recalculates the button bounds if filtering is enabled
/// and the bounds are empty.
/// </summary>
protected Rectangle DropDownButtonBounds
{
get
{
if (!FilteringEnabled)
{
return Rectangle.Empty;
}
if (dropDownButtonBoundsValue == Rectangle.Empty)
{
SetDropDownButtonBounds();
}
return dropDownButtonBoundsValue;
}
} /// <summary>
/// Sets dropDownButtonBoundsValue to Rectangle.Empty if it isn't already empty.
/// This indicates that the button bounds should be recalculated.
/// </summary>
private void InvalidateDropDownButtonBounds()
{
if (!dropDownButtonBoundsValue.IsEmpty)
{
dropDownButtonBoundsValue = Rectangle.Empty;
}
} /// <summary>
/// Sets the position and size of dropDownButtonBoundsValue based on the current
/// cell bounds and the preferred cell height for a single line of header text.
/// </summary>
private void SetDropDownButtonBounds()
{
// Retrieve the cell display rectangle, which is used to
// set the position of the drop-down button.
Rectangle cellBounds =
this.DataGridView.GetCellDisplayRectangle(
this.ColumnIndex, -, false); // Initialize a variable to store the button edge length,
// setting its initial value based on the font height.
Int32 buttonEdgeLength = this.InheritedStyle.Font.Height + ; // Calculate the height of the cell borders and padding.
Rectangle borderRect = BorderWidths(
this.DataGridView.AdjustColumnHeaderBorderStyle(
this.DataGridView.AdvancedColumnHeadersBorderStyle,
new DataGridViewAdvancedBorderStyle(), false, false));
Int32 borderAndPaddingHeight = +
borderRect.Top + borderRect.Height +
this.InheritedStyle.Padding.Vertical;
Boolean visualStylesEnabled =
Application.RenderWithVisualStyles &&
this.DataGridView.EnableHeadersVisualStyles;
if (visualStylesEnabled)
{
borderAndPaddingHeight += ;
} // Constrain the button edge length to the height of the
// column headers minus the border and padding height.
if (buttonEdgeLength >
this.DataGridView.ColumnHeadersHeight -
borderAndPaddingHeight)
{
buttonEdgeLength =
this.DataGridView.ColumnHeadersHeight -
borderAndPaddingHeight;
} // Constrain the button edge length to the
// width of the cell minus three.
if (buttonEdgeLength > cellBounds.Width - )
{
buttonEdgeLength = cellBounds.Width - ;
} // Calculate the location of the drop-down button, with adjustments
// based on whether visual styles are enabled.
Int32 topOffset = visualStylesEnabled ? : ;
Int32 top = cellBounds.Bottom - buttonEdgeLength - topOffset;
Int32 leftOffset = visualStylesEnabled ? : ;
Int32 left = ;
if (this.DataGridView.RightToLeft == RightToLeft.No)
{
left = cellBounds.Right - buttonEdgeLength - leftOffset;
}
else
{
left = cellBounds.Left + leftOffset;
} // Set the dropDownButtonBoundsValue value using the calculated
// values, and adjust the cell padding accordingly.
dropDownButtonBoundsValue = new Rectangle(left, top,
buttonEdgeLength, buttonEdgeLength);
AdjustPadding(buttonEdgeLength + leftOffset);
} /// <summary>
/// Adjusts the cell padding to widen the header by the drop-down button width.
/// </summary>
/// <param name="newDropDownButtonPaddingOffset">The new drop-down button width.</param>
private void AdjustPadding(Int32 newDropDownButtonPaddingOffset)
{
// Determine the difference between the new and current
// padding adjustment.
Int32 widthChange = newDropDownButtonPaddingOffset -
currentDropDownButtonPaddingOffset; // If the padding needs to change, store the new value and
// make the change.
if (widthChange != )
{
// Store the offset for the drop-down button separately from
// the padding in case the client needs additional padding.
currentDropDownButtonPaddingOffset =
newDropDownButtonPaddingOffset; // Create a new Padding using the adjustment amount, then add it
// to the cell's existing Style.Padding property value.
Padding dropDownPadding = new Padding(, , widthChange, );
this.Style.Padding = Padding.Add(
this.InheritedStyle.Padding, dropDownPadding);
}
} /// <summary>
/// The current width of the drop-down button. This field is used to adjust the cell padding.
/// </summary>
private Int32 currentDropDownButtonPaddingOffset; #endregion button bounds #region public properties: FilteringEnabled, AutomaticSortingEnabled, DropDownListBoxMaxLines /// <summary>
/// Indicates whether filtering is enabled for the owning column.
/// </summary>
private Boolean filteringEnabledValue = true; /// <summary>
/// Gets or sets a value indicating whether filtering is enabled.
/// </summary>
[DefaultValue(true)]
public Boolean FilteringEnabled
{
get
{
// Return filteringEnabledValue if (there is no DataGridView
// or if (its DataSource property has not been set.
if (this.DataGridView == null ||
this.DataGridView.DataSource == null)
{
return filteringEnabledValue;
} // if (the DataSource property has been set, return a value that combines
// the filteringEnabledValue and BindingSource.SupportsFiltering values.
BindingSource data = this.DataGridView.DataSource as BindingSource;
Debug.Assert(data != null);
return filteringEnabledValue && data.SupportsFiltering;
}
set
{
// If filtering is disabled, remove the padding adjustment
// and invalidate the button bounds.
if (!value)
{
AdjustPadding();
InvalidateDropDownButtonBounds();
} filteringEnabledValue = value;
}
} /// <summary>
/// Indicates whether automatic sorting is enabled.
/// </summary>
private Boolean automaticSortingEnabledValue = true; /// <summary>
/// Gets or sets a value indicating whether automatic sorting is enabled for the owning column.
/// </summary>
[DefaultValue(true)]
public Boolean AutomaticSortingEnabled
{
get
{
return automaticSortingEnabledValue;
}
set
{
automaticSortingEnabledValue = value;
if (OwningColumn != null)
{
if (value)
{
OwningColumn.SortMode = DataGridViewColumnSortMode.Programmatic;
}
else
{
OwningColumn.SortMode = DataGridViewColumnSortMode.NotSortable;
}
}
}
} /// <summary>
/// The maximum number of lines in the drop-down list.
/// </summary>
private Int32 dropDownListBoxMaxLinesValue = ; /// <summary>
/// Gets or sets the maximum number of lines to display in the drop-down filter list.
/// The actual height of the drop-down list is constrained by the DataGridView height.
/// </summary>
[DefaultValue()]
public Int32 DropDownListBoxMaxLines
{
get { return dropDownListBoxMaxLinesValue; }
set { dropDownListBoxMaxLinesValue = value; }
} #endregion public properties /// <summary>
/// Represents a ListBox control used as a drop-down filter list
/// in a DataGridView control.
/// </summary>
private class FilterListBox : ListBox
{
/// <summary>
/// Initializes a new instance of the FilterListBox class.
/// </summary>
public FilterListBox()
{
Visible = false;
IntegralHeight = true;
BorderStyle = BorderStyle.FixedSingle;
TabStop = false;
} /// <summary>
/// Indicates that the FilterListBox will handle (or ignore) all
/// keystrokes that are not handled by the operating system.
/// </summary>
/// <param name="keyData">A Keys value that represents the keyboard input.</param>
/// <returns>true in all cases.</returns>
protected override bool IsInputKey(Keys keyData)
{
return true;
} /// <summary>
/// Processes a keyboard message directly, preventing it from being
/// intercepted by the parent DataGridView control.
/// </summary>
/// <param name="m">A Message, passed by reference, that
/// represents the window message to process.</param>
/// <returns>true if the message was processed by the control;
/// otherwise, false.</returns>
protected override bool ProcessKeyMessage(ref Message m)
{
return ProcessKeyEventArgs(ref m);
} } } public class DataGridViewAutoFilterTextBoxColumn : DataGridViewTextBoxColumn
{
/// <summary>
/// Initializes a new instance of the DataGridViewAutoFilterTextBoxColumn class.
/// </summary>
public DataGridViewAutoFilterTextBoxColumn()
: base()
{
base.DefaultHeaderCellType = typeof(DataGridViewAutoFilterColumnHeaderCell);
base.SortMode = DataGridViewColumnSortMode.Programmatic;
} #region public properties that hide inherited, non-virtual properties: DefaultHeaderCellType and SortMode /// <summary>
/// Returns the AutoFilter header cell type. This property hides the
/// non-virtual DefaultHeaderCellType property inherited from the
/// DataGridViewBand class. The inherited property is set in the
/// DataGridViewAutoFilterTextBoxColumn constructor.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Type DefaultHeaderCellType
{
get
{
return typeof(DataGridViewAutoFilterColumnHeaderCell);
}
} /// <summary>
/// Gets or sets the sort mode for the column and prevents it from being
/// set to Automatic, which would interfere with the proper functioning
/// of the drop-down button. This property hides the non-virtual
/// DataGridViewColumn.SortMode property from the designer. The inherited
/// property is set in the DataGridViewAutoFilterTextBoxColumn constructor.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced), Browsable(false)]
[DefaultValue(DataGridViewColumnSortMode.Programmatic)]
public new DataGridViewColumnSortMode SortMode
{
get
{
return base.SortMode;
}
set
{
if (value == DataGridViewColumnSortMode.Automatic)
{
throw new InvalidOperationException(
"A SortMode value of Automatic is incompatible with " +
"the DataGridViewAutoFilterColumnHeaderCell type. " +
"Use the AutomaticSortingEnabled property instead.");
}
else
{
base.SortMode = value;
}
}
} #endregion #region public properties: FilteringEnabled, AutomaticSortingEnabled, DropDownListBoxMaxLines /// <summary>
/// Gets or sets a value indicating whether filtering is enabled for this column.
/// </summary>
[DefaultValue(true)]
public Boolean FilteringEnabled
{
get
{
// Return the header-cell value.
return ((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.FilteringEnabled;
}
set
{
// Set the header-cell property.
((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.FilteringEnabled = value;
}
} /// <summary>
/// Gets or sets a value indicating whether automatic sorting is enabled for this column.
/// </summary>
[DefaultValue(true)]
public Boolean AutomaticSortingEnabled
{
get
{
// Return the header-cell value.
return ((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.AutomaticSortingEnabled;
}
set
{
// Set the header-cell property.
((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.AutomaticSortingEnabled = value;
}
} /// <summary>
/// Gets or sets the maximum height of the drop-down filter list for this column.
/// </summary>
[DefaultValue()]
public Int32 DropDownListBoxMaxLines
{
get
{
// Return the header-cell value.
return ((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.DropDownListBoxMaxLines;
}
set
{
// Set the header-cell property.
((DataGridViewAutoFilterColumnHeaderCell)HeaderCell)
.DropDownListBoxMaxLines = value;
}
} #endregion public properties #region public, static, convenience methods: RemoveFilter and GetFilterStatus /// <summary>
/// Removes the filter from the BindingSource bound to the specified DataGridView.
/// </summary>
/// <param name="dataGridView">The DataGridView bound to the BindingSource to unfilter.</param>
public static void RemoveFilter(DataGridView dataGridView)
{
DataGridViewAutoFilterColumnHeaderCell.RemoveFilter(dataGridView);
} /// <summary>
/// Gets a status string for the specified DataGridView indicating the
/// number of visible rows in the bound, filtered BindingSource, or
/// String.Empty if all rows are currently visible.
/// </summary>
/// <param name="dataGridView">The DataGridView bound to the
/// BindingSource to return the filter status for.</param>
/// <returns>A string in the format "x of y records found" where x is
/// the number of rows currently displayed and y is the number of rows
/// available, or String.Empty if all rows are currently displayed.</returns>
public static String GetFilterStatus(DataGridView dataGridView)
{
return DataGridViewAutoFilterColumnHeaderCell.GetFilterStatus(dataGridView);
} #endregion
} public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
{
public DataGridViewComboEditBoxColumn()
{
DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
this.CellTemplate = obj;
}
public class DataGridViewComboEditBoxCell : DataGridViewComboBoxCell
{
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); ComboBox comboBox = (ComboBox)base.DataGridView.EditingControl; if (comboBox != null)
{
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
comboBox.AutoCompleteMode = AutoCompleteMode.Suggest;
comboBox.Validating += new CancelEventHandler(comboBox_Validating);
}
} //protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
//{
// if (value != null)
// {
// if (value.ToString().Trim() != string.Empty)
// {
// if (Items.IndexOf(value) == -1)
// {
// Items.Add(value);
// //DataGridViewComboBoxColumn col = (DataGridViewComboBoxColumn)OwningColumn;
// //col.Items.Add(value);
// }
// }
// }
// return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
//} void comboBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
DataGridViewComboBoxEditingControl cbo = (DataGridViewComboBoxEditingControl)sender;
if (cbo.Text.Trim() == string.Empty) return; DataGridView grid = cbo.EditingControlDataGridView;
object value = cbo.Text; // Add value to list if not there
if (cbo.Items.IndexOf(value) == -)
{
DataGridViewComboBoxColumn cboCol = (DataGridViewComboBoxColumn)grid.Columns[grid.CurrentCell.ColumnIndex];
// Must add to both the current combobox as well as the template, to avoid duplicate entries
cbo.Items.Add(value);
//cboCol.Items.Add(value);
grid.CurrentCell.Value = value;
}
}
}
}
/// <summary>
/// 调用时所用*注意:筛选后Count数据需要用DataBindingComplete事件
/// </summary>
public class DataGridViewFunction
{
/// <summary>
/// 查询时加载时所用-生成ComBox并返回行数.每查询一次执行一次
/// </summary>
/// <param name="DGV"></param>
/// <returns></returns>
public string GridViewHeaderFilter(DataGridView DGV)
{
string Number = "";//默认数量为0
if (DGV.DataSource != null && DGV.Columns.Count > )
{
foreach (DataGridViewColumn col in DGV.Columns)
{
col.HeaderCell = new
DataGridViewAutoFilter.DataGridViewAutoFilterColumnHeaderCell(col.HeaderCell);
}
DGV.AutoResizeColumns();
DataGridViewAutoFilter.DataGridViewAutoFilterColumnHeaderCell filterCell =DGV.CurrentCell.OwningColumn.HeaderCell as DataGridViewAutoFilter.DataGridViewAutoFilterColumnHeaderCell;
if (filterCell != null)
{
filterCell.ShowDropDownList();
//e.Handled = true;
}
String filterStatus = DataGridViewAutoFilter.DataGridViewAutoFilterColumnHeaderCell.GetFilterStatus(DGV);
if (String.IsNullOrEmpty(filterStatus))
{
Number = DGV.RowCount.ToString();
}
else
{
Number = filterStatus;
}
}
return Number;
}
/// <summary>
/// 返回GridView数据行数
/// </summary>
/// <param name="DGV"></param>
/// <returns></returns>
public string GridViewDataCount(DataGridView DGV)
{
return DGV.RowCount.ToString();
}
/// <summary>
/// DataGridView填充数据
/// </summary>
/// <param name="dt"></param>
/// <param name="DGV"></param>
public void GridViewDataLoad(DataTable dt, DataGridView DGV)
{
DGV.DataSource = null;
BindingSource dataSource = new BindingSource(dt, null); ;
DGV.DataSource = dataSource; } }
}
调用代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DataGridViewAutoFilter; namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
MESDB.MESDB GetDB = new MESDB.MESDB();//作者自用数据库链接接口(WebService)
DataGridViewAutoFilter.DataGridViewFunction Get = new DataGridViewFunction();
/// <summary>
/// 窗体加载事件-并加载数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
string Sql = "select c.Product_ID as '产品编号',f.Pn_Type as '生产类型',concat(c.Hold_Stage,'[',d.Stage_Name,']') as 'Hold站点',c.Stage_OldStatus as '旧状态' ,concat(c.Line_Type,'[',e.Type_Remark,']' )as '所属区域',c.Hold_Rmark as 'Hold原因' , c.Hold_Time as 'Hold时间' ,c.Hold_User as '操作用户' ,c.Stage_Status as '产品状态' ,substr(c.LevelProductName,1,8) as 'UnitP/N',c.LevelProductName as 'Hold品名',g.TESTTIME as 'CowTestTime' ,c.Change_Level as '升/降档',c.Release_Remark as '释放备注' ,c.Release_Time as '释放时间' , c.Release_User as '释放用户',c.Release_Owner as '释放部门',c.Transfer_Owner as '转移理由',c.Transfer_Time as '转移时间' ,c.Transfer_User as '转移用户',c.Exception_Type as '异常归类',c.Level_Handling as '升降档归类',c.Parameter_Type as '异常参数',c.Department_Owner as '责任归类',c.Treat_Remark as '归类备注',c.Remark_User as '归类用户',c.Remark_Time as '归类时间',c.Hold_Type as 'Hold类型' from mes.MES_Chip_Stage as d,mes.MES_Chip_LineType e,mes.MES_Lot_Attribute as f,mes.MES_Qc_Hold as c left join eda.cow_probe_sample_test_summary as g on c.Product_ID=g.CHIP_WaferID where f.Lot_Attribute=substr(c.Product_ID,1,1) and c.Hold_Stage=d.Stage_Code and c.Line_Type=e.Line_Type and c.Line_Type='PV' and c.Transfer_Time between '2016/05/08 17:52:29' and '2016/06/07 17:52:29' ";
DataTable dt = GetDB.MySqlDBSelct(Sql).Tables[];
Get.GridViewDataLoading(dt, dataGridView1);//填充DataGridView
label1.Text = Get.GridViewHeaderFilter(dataGridView1);//标题添加ComBox并返回行数 }
private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{ label1.Text = Get.GridViewDataCount(dataGridView1);//筛选时动态加载行数 }
}
}
c# Winfrom-DataGridView实现筛选功能的更多相关文章
- DataGridView如何实现列标头带数据筛选功能,就象Excel高级筛选功能一样
'近日有本论坛网友问:DataGridView如何实现列标头带数据筛选功能,就象Excel高级筛选功能一样 '今晚正好闲着没事,加之以前也没用到过这个需求,所以就写了个模拟功能,供各位坛友酌情参考. ...
- 织梦CMS实现多条件筛选功能
用织梦实现筛选的功能,其实主要就是运用到了织梦的高级搜索功能,然后用ajax去post替换掉本来的结果就可以了. 其实筛选的话,主要有两个问题需要解决,一个是前台的筛选实现,一个是后台根据前台的点击, ...
- phpcms筛选功能
phpcms论坛的看到的-----做筛选功能-----自定义函数 <?php /** * extention.func.php 用户自定义函数库 * * @copyright (C) 2005- ...
- 求解:php商品条件筛选功能你是怎么做出来的?
求解:php商品条件筛选功能你是怎么做出来的? 2013-09-25 13:43 chenhang607 | 浏览 2756 次 资源共享 求思路或者方法,最好能有些代码 2013-09-25 14: ...
- 【PHP开源产品】Ecshop的商品筛选功能实现分析之一
一.首先,说明一下为什么要对category.php文件进行分析. 原因如下: ①个人对商城类商品筛选功能的实现比较好奇: ②对商城中关于商品的数据表设计比较感兴趣.(该功能涉及到与数据库的交互,而且 ...
- 五指cms筛选功能的实现:
筛选功能的实现: $_POST['page_urlrule'] = 'tuan-{$pinpai}-{$renqun}-{$type}-{$price}-{$area}-{$tese}-{$st}-{ ...
- 【经验】angularjs 实现带查找筛选功能的select下拉框
一.背景 对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!so,为优化用户体验,带查找功能的下拉框是非常非常有必要的.都知道jquery里有 ...
- ECSHOP分类页面筛选功能(按分类下子分类和品牌筛选)
其实分类页面里面本来就有相关的品牌.属性.分类的筛选功能在category.php和模板加上相应的功能即可 1.读出当前分类的所有下级分类 $chlidren_category = $GLOBALS[ ...
- Easyui DataGrid DateRange Filter 漂亮实用的日期区间段筛选功能
自定义扩展Jquery easyui datagrid filter组件实现对日期类型区间段的筛选功能.显示效果如一下 是不是非常实用 引用的jquery 组件是 Date Range Picker ...
随机推荐
- SQLserver 的分页存储过程
-- 1.建立修改学生数据的存储过程 -- 2.建立根据班级Id和学生姓名模糊查询的分页存储过程,要求正确输出总记录数,总页数-- (输入班学生姓名 计算总记录数 计算总页数) -- @name ...
- 学习 SQL Server (5) :视图,索引,事务和锁+T_SQL
--=============== 视图的创建 =================. --create view 视图名 as 查询语句--注意:视图查询中的字段不能重名-- 视图中的数据是‘假数据’ ...
- 关于安装Django包的问题
在Windows的环境下,有些包确实不好安装的,比如reportlab-3.2.0-cp27-none-win32.whl,根据xadmin安装的经验,从这个.whl里把文件夹reportlab解压出 ...
- 有return的情况下try_catch_finally的执行顺序
java异常处理之try_catch_finally 看下面的一个列子: public class TestException { int goabl=1; public TestException( ...
- 前后端分层架构MVC&MVVM
早期 特点 页面由 JSP.PHP 等工程师在服务端生成 JSP 里揉杂大量业务代码 浏览器负责展现,服务端给什么就展现什么,展现的控制在 Web Server 层 优点 简单明快,本地起一个 Tom ...
- LQR要点
新的“A”变成着了这样:Ac = A - KB 基于对象:状态空间形式的系统 能量函数J:也称之为目标函数 Q:半正定矩阵,对角阵(允许对角元素出现0) R:正定矩阵,QR其实就是权重 下面这段话可能 ...
- Erlang模块inet翻译
模块 inet 模块概述 访问TCP / IP协议. 描述 此模块提供对TCP/IP协议的访问. 另请参阅<ERTS用户指南:Inet配置>,以获取有关如何配置用于IP通信的Erlang运 ...
- Oracle 11gR2 待定的统计信息(Pending Statistic)
Oracle 11gR2 待定的统计信息(Pending Statistic) 官档最权威: 发布优化器统计信息的用户界面 管理已发布和待处理的统计信息 实验先拖着.
- 大型Java进阶专题(六)设计模式之代理模式
代理模式 前言 又开始我的专题了,又停滞了一段时间了,加油继续吧.都知道 SpringAOP 是用代理模式实现,到底是怎么实现的?我们来一探究竟,并且自己仿真手写还原部分细节. 代理模式的应用 在生活 ...
- 第 11 篇:基于 drf-haystack 的文章搜索接口
作者:HelloGitHub-追梦人物 在 django 博客教程中,我们使用了 django-haystack 和 Elasticsearch 进行文章内容的搜索.django-haystack 默 ...