1. 程式人生 > >Winform系列——好用的DataGridview過濾控制元件(表格的高階搜尋功能)

Winform系列——好用的DataGridview過濾控制元件(表格的高階搜尋功能)

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Data;
using System.ComponentModel;
using Ewin.Client.Frame;
using Ewin.Client.Frame.Controls;
using System.Collections;
using System.Reflection;

namespace Ewin.Client.Frame.UcGrid
{
    
public class DgvFilterManager { #region PRIVATE FIELDS private DgvBaseFilterHost mFilterHost; // The host UserControl to popup private DataGridView mDataGridView; // The DataGridView to which apply filtering private DataView mBoundDataView; //
The DataView to which the DataGridView is bound BindingSource mBindingSource; // The BindingSource, if any, to which the DataGridView is bound private string mBaseFilter = ""; // Developer provided filter expression private int mCurrentColumnIndex = -1
; // Column Index of currently visibile filter private List<DgvBaseColumnFilter> mColumnFilterList; // List of ColumnFilter objects private bool mAutoCreateFilters = true; private bool mFilterIsActive = false; ContextMenuStrip oMenuStrip; #endregion #region EVENTS /// <summary> /// Occurs when a <i>column filter</i> instance for a column is about to be automatically created. /// </summary> /// <remarks> /// Using this event you can set the <see cref="ColumnFilterEventArgs.ColumnFilter"/> /// property to force the <see cref="DgvBaseColumnFilter"/> specialization to use for the /// column. /// This event is raised only if <see cref="DgvFilterManager.AutoCreateFilters"/> is true. /// </remarks> public event ColumnFilterEventHandler ColumnFilterAdding; /// <summary> /// Occurs when a <i>column filter</i> instance is created. /// This event is raised only if <see cref="DgvFilterManager.AutoCreateFilters"/> is true. /// </summary> public event ColumnFilterEventHandler ColumnFilterAdded; /// <summary> /// Occurs when the popup is about to be shown /// </summary> /// <remarks> /// Use this event to customize the popup position. Set the Handled property of the event argument to <c>true</c>. /// </remarks> public event ColumnFilterEventHandler PopupShowing; #endregion #region CONSTRUCTORS /// <summary> /// Initializes a new instance of the <see cref="DgvFilterManager"/> class. /// </summary> public DgvFilterManager() { } /// <summary> /// Initializes a new instance of the <see cref="DgvFilterManager"/> class. /// </summary> /// <param name="dataGridView">The <b>DataGridView</b> to which attach filtering capabilities</param> /// <param name="autoCreateFilters">if set to <c>true</c> automatically creates a <i>column filter</i> for each column</param> public DgvFilterManager(DataGridView dataGridView, bool autoCreateFilters) { this.mAutoCreateFilters = autoCreateFilters; this.DataGridView = dataGridView; } /// <summary> /// Initializes a new instance of the <see cref="DgvFilterManager"/> class. /// </summary> /// <param name="dataGridView">The <b>DataGridView</b> to which attach filtering capabilities.</param> public DgvFilterManager(DataGridView dataGridView) : this(dataGridView, true) { } #endregion #region PROPERTIES /// <summary> /// Gets or sets a value indicating whether the manager must create <i>column filters</i>. /// </summary> /// <value><c>true</c> by default.</value> public bool AutoCreateFilters { get { return mAutoCreateFilters; } set { mAutoCreateFilters = value; } } /// <summary> /// Gets and sets the <i>filter host</i> to use. /// </summary> /// <remarks> /// The default <i>filter host</i> is an instance of <see cref="DgvFilterHost"/> /// </remarks> public DgvBaseFilterHost FilterHost { get { if (mFilterHost == null) { // If not provided, use the default FilterHost FilterHost = new DgvFilterHost(); //FilterHost.AllowDrop = true; //FilterHost.Popup.MouseDown += FilterHost_MouseDown; } return mFilterHost; } set { mFilterHost = value; // initialize FilterManager to this object mFilterHost.FilterManager = this; mFilterHost.Popup.Closed += new ToolStripDropDownClosedEventHandler(Popup_Closed); } } void oForm_DragEnter(object sender, DragEventArgs e) { //當Button被拖拽到WinForm上時候,滑鼠效果出現 if ((e.Data.GetDataPresent(typeof(DgvFilterHost)))) { e.Effect = DragDropEffects.Copy; } } void oForm_DragDrop(object sender, DragEventArgs e) { //拖放完畢之後,自動生成新控制元件 //Button btn = new Button(); //btn.Size = Button1.Size; //btn.Location = this.PointToClient(new Point(e.X, e.Y)); ////用這個方法計算出客戶端容器介面的X,Y座標。否則直接使用X,Y是螢幕座標 //this.Controls.Add(btn); //btn.Text = "按鈕" + count.ToString(); //count = count + 1; } void FilterHost_MouseDown(object sender, MouseEventArgs e) { //左鍵的話,標誌位為true(表示拖拽開始) if ((e.Button == System.Windows.Forms.MouseButtons.Left)) { FilterHost.DoDragDrop(FilterHost, DragDropEffects.Copy | DragDropEffects.Move); //形成拖拽效果,移動+拷貝的組合效果 } } /// <summary> /// Gets and sets the DataGridView to which apply filtering capabilities. /// </summary> /// <remarks> /// <para> /// When a <b>DataGridView</b> is attached, the manager perform the following actions: /// <ul> /// <li>it creates a <i>filter host</i>, that is an instance of the <b>DgvFilterHost</b> class. If you previously provided a /// <i>filter host</i>, this step is skipped.</li> /// <li>it creates an array of <b>DgvBaseColumnFilter</b>, one per column, and initializes each element to a specialization /// of <b>DgvBaseColumnFilter</b>. If <see cref="DgvFilterManager.AutoCreateFilters"/> is false, this step is skipped. /// </li> /// </ul> /// </para> /// <para> /// You can force a specific <i>column filter</i> for a certain column, intervening in this process through the events /// <see cref="DgvFilterManager.ColumnFilterAdding"/> and <see cref="DgvFilterManager.ColumnFilterAdded"/>. You can also intervene, after the entire process, replacing /// a <i>column filter</i> instance in the array with another instance you created. /// </para> /// </remarks> public DataGridView DataGridView { get { return mDataGridView; } set { mDataGridView = value; mColumnFilterList = new List<DgvBaseColumnFilter>(mDataGridView.Columns.Count); FindDataView(); mDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; mDataGridView.CellMouseClick += new DataGridViewCellMouseEventHandler(mDataGridView_CellMouseClick); mDataGridView.CellPainting += new DataGridViewCellPaintingEventHandler(mDataGridView_CellPainting); mDataGridView.ColumnAdded += new DataGridViewColumnEventHandler(mDataGridView_ColumnAdded); mDataGridView.ColumnRemoved += new DataGridViewColumnEventHandler(mDataGridView_ColumnRemoved); if (mDataGridView == null) return; foreach (DataGridViewColumn c in mDataGridView.Columns) { mColumnFilterList.Add(null); CreateColumnFilter(c); } } } /// <summary> /// Gets and sets developer provided filter expression. This expression /// will be "merged" with end-user created filters. /// </summary> /// <value>The base filter.</value> public string BaseFilter { get { return mBaseFilter; } set { mBaseFilter = value; RebuildFilter(); } } /// <summary> /// Gets or sets the <i>column filter</i> control related to the ColumnIndex /// </summary> /// <param name="ColumnIndex">The index of the <b>DataGridView</b> column</param> /// <returns>the <b>DgvBaseColumnFilter</b> related to the <b>DataGridView</b> column</returns> /// <remarks> /// This indexer allow you to get and set the <i>column filter</i> instance for the column. /// You can set one of the standard <i>column filter</i> implementation or an instance /// of your own <b>DgvBaseFilterColumn</b> specialization. /// </remarks> public DgvBaseColumnFilter this[int ColumnIndex] { get { return mColumnFilterList[ColumnIndex]; } set { mColumnFilterList[ColumnIndex] = value; value.Init(this, FilterHost, mDataGridView.Columns[ColumnIndex], mBoundDataView); } } /// <summary> /// Gets or sets the <i>column filter</i> control related to the ColumnName /// </summary> /// <param name="ColumnName">The name of the <b>DataGridView</b> column</param> /// <returns>the DgvBaseColumnFilter related to the <b>DataGridView</b> column</returns> /// <remarks> /// This indexer allow you to get and set the <i>column filter</i> instance for the column. /// You can set one of the standard <i>column filter</i> implementation or an instance /// of your own <b>DgvBaseFilterColumn</b> specialization. /// </remarks> public DgvBaseColumnFilter this[string ColumnName] { get { return mColumnFilterList[mDataGridView.Columns[ColumnName].Index]; } set { this[mDataGridView.Columns[ColumnName].Index] = value; } } #endregion #region DATAGRIDVIEW EVENT HANDLERS private void mDataGridView_ColumnRemoved(object sender, DataGridViewColumnEventArgs e) { mColumnFilterList.RemoveAt(e.Column.Index); } private void mDataGridView_ColumnAdded(object sender, DataGridViewColumnEventArgs e) { FindDataView(); mColumnFilterList.Insert(e.Column.Index, null); CreateColumnFilter(e.Column); } #region 新增修改程式碼 Edit By yangxiaojun System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Resource)); /// <summary> /// Shows the popup when user right-clicks a column header /// </summary> /// <param name="sender">The event source.</param> /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellMouseEventArgs"/> instance containing the event data.</param> protected virtual void mDataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) { //var oForm = mDataGridView.FindForm(); //oForm.AllowDrop = true; //oForm.DragDrop += oForm_DragDrop; //oForm.DragEnter += oForm_DragEnter; if (e.Button == MouseButtons.Right && e.RowIndex == -1 && e.ColumnIndex > -1) { if (oMenuStrip == null) { oMenuStrip = new ContextMenuStrip(); oMenuStrip.Size = new System.Drawing.Size(395, 100); } oMenuStrip.Items.Clear(); //0.升序選單 var oSortClientEnvent = new EventHandler(mMenuStripSort_Click); var oToolAscding = new MyToolStripMenuItem("升序", ((System.Drawing.Image)(resources.GetObject("ascending"))), oSortClientEnvent); oToolAscding.Name = "toolscriptmenuitemasc"; oToolAscding.Size = new System.Drawing.Size(213, 22); oToolAscding.SortKey = this.mDataGridView.Columns[e.ColumnIndex].Name; oToolAscding.SortDirection = ListSortDirection.Ascending; oMenuStrip.Items.Add(oToolAscding); //1.降序選單 var oToolDescending = new MyToolStripMenuItem("降序", ((System.Drawing.Image)(resources.GetObject("descending"))), oSortClientEnvent); oToolDescending.Name = "toolscriptmenuitemdesc"; oToolDescending.Size = new System.Drawing.Size(213, 22); oToolDescending.SortKey = this.mDataGridView.Columns[e.ColumnIndex].Name; oToolDescending.SortDirection = ListSortDirection.Descending; oMenuStrip.Items.Add(oToolDescending); //2.分割線 var oSeparator = new System.Windows.Forms.ToolStripSeparator(); oMenuStrip.Items.Add(oSeparator); //3.過濾選單 var oToolFilter = new MyToolStripMenuItem("過濾...", ((System.Drawing.Image)(resources.GetObject("Filter_Image"))), new EventHandler(mMenuStripFilter_Click)); oToolFilter.ColumnIndex = e.ColumnIndex; oToolFilter.ColumnName = this.mDataGridView.Columns[e.ColumnIndex].Name; oMenuStrip.Items.Add(oToolFilter); //4.取消過濾選單 var oToolCancelFilter = new MyToolStripMenuItem("取消過濾", ((System.Drawing.Image)(resources.GetObject("Filter_Clear_Image"))), new EventHandler(mMenuStripCancelFilter_Click)); oToolCancelFilter.ColumnIndex = e.ColumnIndex; oToolCancelFilter.ColumnName = this.mDataGridView.Columns[e.ColumnIndex].Name; oMenuStrip.Items.Add(oToolCancelFilter); Rectangle r = mDataGridView.GetCellDisplayRectangle(e.ColumnIndex, -1, false); oMenuStrip.Show(mDataGridView, r.X + e.X, r.Y + e.Y); //ShowPopup(e.ColumnIndex); } } //選單單擊排序事件 protected virtual void mMenuStripSort_Click(object sender, EventArgs e) { //MessageBox.Show("測試"); var oToolScript = (((MyToolStripMenuItem)sender)); this.mDataGridView.Sort(this.mDataGridView.Columns[oToolScript.SortKey], oToolScript.SortDirection); } //選單單擊過濾事件 protected virtual void mMenuStripFilter_Click(object sender, EventArgs e) { Ewin.Client.Frame.Forms.EwinTaskWindow.ShowTaskWindow("Edit Filter", FilterHost); var oToolScript = (((MyToolStripMenuItem)sender)); if (mColumnFilterList[oToolScript.ColumnIndex] == null) return; // non-data column SetCurrentFilterIndex(oToolScript.ColumnIndex); //FilterHost.Popup.Show(mDataGridView, 480, 150); // show the filterhost popup near the column FilterHost.Popup.Focus(); var lstCols = mDataGridView.Columns; var lstDataSource = new List<object>(); foreach (DataGridViewColumn oCol in lstCols) { var oColHeadName = oCol.HeaderText.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var comboitem = new { Value = oCol.Name, Text = oColHeadName[0] }; lstDataSource.Add(comboitem); //lstDataSource.Add(oCol.Name); } FilterHost.ComboBoxColumns.DataSource = lstDataSource; FilterHost.ComboBoxColumns.DisplayMember = "Text"; FilterHost.ComboBoxColumns.ValueMember = "Value"; FilterHost.ComboBoxColumns.SelectedValueChanged += ComboBoxColumns_SelectedValueChanged; FilterHost.ComboBoxColumns.SelectedValue = oToolScript.ColumnName; //顯示過濾表示式 SetFilterExpression(); } //取消過濾選單事件 protected virtual void mMenuStripCancelFilter_Click(object sender, EventArgs e) { var oToolScript = (((MyToolStripMenuItem)sender)); //0.指定當前過濾列索引 if (mColumnFilterList[oToolScript.ColumnIndex] == null) return; // non-data column SetCurrentFilterIndex(oToolScript.ColumnIndex); //1.使當前過濾列失效,即Active=false; ActivateFilter(false); } //刪除過濾條件圖示的點選事件 private void oPicBox_Click(object sender, EventArgs e) { //1.根據過來欄位找到過濾欄位索引 var oPicBox = (EwinImgButton)sender; var iFilterIndex = GetFilterIndexByFilterName(oPicBox.Tag.ToString()); if (iFilterIndex == -1) return; //2.設定當前過濾索引 SetCurrentFilterIndex(iFilterIndex); //3.將當前過濾列的Active設為false ActivateFilter(false); //4.設定過濾表示式 SetFilterExpression(); } //選擇列的選擇事件 protected virtual void ComboBoxColumns_SelectedValueChanged(object sender, EventArgs e) { var oSelectedValue = ((ComboBox)sender).SelectedValue.ToString(); var iFilterIndex = GetFilterIndexByFilterName(oSelectedValue); if (iFilterIndex == -1) return; SetCurrentFilterIndex(iFilterIndex); } //根據過濾列的名稱得到過濾列的列索引 private int GetFilterIndexByFilterName(string strFilterName) { int iRes = -1; var lstCols = mDataGridView.Columns; foreach (DataGridViewColumn oCol in lstCols) { if (oCol.Name == strFilterName ||oCol.HeaderText.Contains(strFilterName)) { if (mColumnFilterList[oCol.Index] == null) return -1; // non-data column iRes = oCol.Index; break; } } return iRes; } //設定當前過濾索引 private void SetCurrentFilterIndex(int iIndex) { int OldColumnIndex = mCurrentColumnIndex; mCurrentColumnIndex = iIndex; FilterHost.CurrentColumnFilter = mColumnFilterList[iIndex]; try { //use "try" because old column could have been removed mDataGridView.InvalidateCell(OldColumnIndex, -1); } catch { } } //顯示過濾表示式 public void SetFilterExpression() { var arrFilterText = new List<string>(); foreach (DgvBaseColumnFilter CF in mColumnFilterList) { if (CF == null) continue; if (CF.Active && CF.FilterExpression != "") { arrFilterText.Add(CF.FilterCaption.Replace("\n", " ").Replace("<> ?", "<> NULL").Replace("= ?", "= NULL")); } } //var strRowFilterText = mBoundDataView.RowFilter.Contains("1=1 AND") ? mBoundDataView.RowFilter.Replace("1=1 AND", string.Empty) : mBoundDataView.RowFilter; //var arrFilterText = strRowFilterText.Split(new string[] { " AND " }, StringSplitOptions.RemoveEmptyEntries); var y = 7; //0.先清空表示式再重新繪製控制元件 FilterHost.PanelFilterText.Controls.Clear(); var panelFilterText = new EwinPanel(); panelFilterText.AutoScroll = true; panelFilterText.HorizontalScrollbar = true; panelFilterText.HorizontalScrollbarBarColor = true; panelFilterText.HorizontalScrollbarHighlightOnWheel = false; panelFilterText.HorizontalScrollbarSize = 10; panelFilterText.Location = new System.Drawing.Point(2, 2); panelFilterText.Name = "panelFilterText1"; panelFilterText.Size = new System.Drawing.Size(458, 133); panelFilterText.VerticalScrollbar = true; panelFilterText.VerticalScrollbarBarColor = true; panelFilterText.VerticalScrollbarHighlightOnWheel = false; panelFilterText.VerticalScrollbarSize = 10; panelFilterText.ShowBorder = false; foreach (var strText in arrFilterText) { //1.新增panel var oPanelText = new EwinPanel(); oPanelText.Name = "oPanelText" + y; oPanelText.Location = new System.Drawing.Point(1, y); oPanelText.Size = new System.Drawing.Size(445, 25); oPanelText.ShowBorder = false; //2.向panel裡面新增顯示錶達式的label var oLabelText = new EwinLabel(); oLabelText.Cursor = Cursors.Hand; oLabelText.ForeColor = Color.BlueViolet; oLabelText.AutoSize = true; oLabelText.Location = new System.Drawing.Point(10, 0); oLabelText.Name = "label_filtertext" + y; oLabelText.Text = strText.Trim().Trim(new char[2] { '(', ')' }); oLabelText.Size = new System.Drawing.Size(oLabelText.Text.Length * 8, 25); //3.向panel裡面新增刪除圖示 var oPicBox = new EwinImgButton(); oPicBox.Image = ((System.Drawing.Image)(resources.GetObject("Close_tab"))); oPicBox.Cursor = Cursors.Hand; oPicBox.Location = new Point(oLabelText.Width + 10, 3); oPicBox.Size = new System.Drawing.Size(20, 20); var otooltip = new System.Windows.Forms.ToolTip(); otooltip.SetToolTip(oPicBox, "刪除過濾條件"); oPicBox.Click += oPicBox_Click; oPicBox.Tag = oLabelText.Text.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)[0]; oPanelText.Controls.Add(oPicBox); oPanelText.Controls.Add(oLabelText); y = y + 30; panelFilterText.Controls.Add(oPanelText); //FilterHost.PanelFilterText.Controls.Add(oPanelText); } FilterHost.PanelFilterText.Controls.Add(panelFilterText); panelFilterText.Invalidate(); } #endregion //Based on filters state, call the appropriate protected paint helpers private void mDataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { if (e.RowIndex != -1) return; //skip if it is not the header row //1.繪製e.RowIndex == -1 && e.ColumnIndex == -1處的過濾圖示 //Cell Origin if (e.RowIndex == -1 && e.ColumnIndex == -1 && mFilterIsActive) { OnFilteredGridPaint(sender, e); return; } //2.