Winform系列——好用的DataGridview过滤控件(表格的高级搜索功能)

     上一篇  Winform系列——好看的DataGridView折叠控件 中主要介绍了DataGridview的表格多级折叠功能。这章主要介绍下最近封装的另一个DataGridview表格高级过滤的功能。此功能也是参照codeproject上面的源码改写的,代码可能有源码的内容,也有本人改写过的,所以看上去可能有点乱。废话不多说,上图:

 1、一般的DataGridview效果:

 

2、增加了列上面右键效果:

 

3、升序和降序就没什么说的了,看看点击过滤的效果吧:

 

4、取消某一个字段过滤的方式有两种:

 

 

5、取消所有字段的过滤:

 

   

      大致效果就如上了。代码有点乱,如果有时间我会整理下,有兴趣的可以看看。

1、向外暴露的使用类:这个类主要功能是通过构造函数 public DgvFilterManager(DataGridView dataGridView, bool autoCreateFilters){}将DataGridview对象传进来,然后再给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.如果过滤框显示,绘制过滤列表头的边框
            //if (FilterHost.Popup.Visible)
            //{
            //    OnHighlightedColumnPaint(sender, e);
            //}

            //3.绘制过滤列表头的样式
            if (e.ColumnIndex == -1) return;
            if (mColumnFilterList[e.ColumnIndex] != null && mColumnFilterList[e.ColumnIndex].Active)
            {
                OnFilteredColumnPaint(sender, e);
            }
        }


        /// <summary>
        /// Paints a funnel icon in the cell origin when some column is filtered.
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
        /// <remarks>
        /// Override this method to provide your own painting
        /// </remarks>
        protected virtual void OnFilteredGridPaint(object sender, DataGridViewCellPaintingEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.White, e.CellBounds);
            e.Paint(e.CellBounds, e.PaintParts & ~DataGridViewPaintParts.Background);
            Rectangle r = new Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4);
            e.Graphics.DrawImage(FunnelPicture, (e.CellBounds.Width - FunnelPicture.Width) / 2, (e.CellBounds.Height - FunnelPicture.Height) / 2, FunnelPicture.Width, FunnelPicture.Height);
            e.Graphics.DrawRectangle(Pens.Black, r);

            e.Handled = true;

            //e.Paint(e.CellBounds, DataGridViewPaintParts.All);
            //e.Graphics.DrawImage(FunnelPicture, (e.CellBounds.Width - FunnelPicture.Width) / 2, (e.CellBounds.Height - FunnelPicture.Height) / 2, FunnelPicture.Width, FunnelPicture.Height);
            //e.Handled = true;
        }

        /// <summary>
        /// Performs customized column header painting when the popup is visibile. 
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
        /// <remarks>
        /// Override this method to provide your own painting
        /// </remarks>
        protected virtual void OnHighlightedColumnPaint(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (e.ColumnIndex != mCurrentColumnIndex || e.RowIndex != -1) return;
            e.Paint(e.CellBounds, DataGridViewPaintParts.All);
            Rectangle r = new Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4);
            e.Graphics.DrawRectangle(Pens.Yellow, r);
            e.Handled = true;
        }

        /// <summary>
        /// Performs customized column header painting when the column is filtered.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
        /// <remarks>
        /// Override this method to provide your own painting
        /// </remarks>
        protected virtual void OnFilteredColumnPaint(object sender, DataGridViewCellPaintingEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.Orange, e.CellBounds);
            e.Paint(e.CellBounds, e.PaintParts & ~DataGridViewPaintParts.Background);
            Rectangle r = new Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4);
            e.Graphics.DrawRectangle(Pens.Orange, r);
            e.Handled = true;

        }

        #endregion


        #region FILTERHOST MANAGING

        //Forces column header repaint when popup is closed, cleaning customized painting performed by OnHighlightedColumnPaint
        private void Popup_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            mDataGridView.InvalidateCell(mCurrentColumnIndex, -1);   // Force header repaint (to hide the selection yellow frame)
        }


        /// <summary>
        /// Shows the popup.
        /// </summary>
        /// <param name="ColumnIndex">Index of the column.</param>
        public void ShowPopup(int ColumnIndex)
        {
            if (mColumnFilterList[ColumnIndex] == null) return; // non-data column
            int OldColumnIndex = mCurrentColumnIndex;
            mCurrentColumnIndex = ColumnIndex;
            Rectangle r = mDataGridView.GetCellDisplayRectangle(ColumnIndex, -1, false); // get the header size info
            FilterHost.CurrentColumnFilter = mColumnFilterList[ColumnIndex];
            try
            {
                //use "try" because old column could have been removed
                mDataGridView.InvalidateCell(OldColumnIndex, -1);
            }
            catch { }
            ColumnFilterEventArgs e = new ColumnFilterEventArgs(mDataGridView.Columns[ColumnIndex], mColumnFilterList[ColumnIndex]);
            if (PopupShowing != null) PopupShowing(this, e);
            if (!e.Handled) FilterHost.Popup.Show(mDataGridView, r.X + r.Width - 4, r.Y - 10); // show the filterhost popup near the column
            FilterHost.Popup.Focus();

            mDataGridView.InvalidateCell(mCurrentColumnIndex, -1);  // Force header repaint (to show a selection yellow frame)

        }

        #endregion


        #region COLUMN FILTERS MANAGING


        /// <summary>
        /// Activates / Deactivates the filter for the column specified by ColumnIndex.
        /// </summary>
        /// <param name="Active">The active state to set</param>
        /// <param name="ColumnIndex">Index of the column.</param>
        public void ActivateFilter(bool Active, int ColumnIndex)
        {
            this[ColumnIndex].Active = Active;
            RebuildFilter();
        }



        /// <summary>
        /// Activates / Deactivates the filter for the column specified by ColumnName.
        /// </summary>
        /// <param name="Active">The active state to set</param>
        /// <param name="ColumnName">Name of the column.</param>
        public void ActivateFilter(bool Active, string ColumnName)
        {
            this[ColumnName].Active = Active;
            RebuildFilter();
        }


        /// <summary>
        /// Activates / Deactivates the filter for the current, that is last right-clicked, column.
        /// </summary>
        /// <param name="Active">The active state to set</param>
        public void ActivateFilter(bool Active)
        {
            if (mCurrentColumnIndex == -1) return;
            this[mCurrentColumnIndex].Active = Active;
            if (Active) this[mCurrentColumnIndex].FilterExpressionBuild();
            RebuildFilter();
        }



        /// <summary>
        /// Activates / Deactivates all filters.
        /// </summary>
        /// <param name="Active">The active state to set</param>
        public void ActivateAllFilters(bool Active)
        {
            foreach (DgvBaseColumnFilter CF in mColumnFilterList)
            {
                if (CF == null) continue;
                CF.Active = Active;
                if (Active) CF.FilterExpressionBuild();
            }
            RebuildFilter();
        }



        /// <summary>
        /// Rebuilds the whole filter expression.
        /// </summary>
        /// <remarks>
        /// The whole filter expression is the conjunction of each <i>column filter</i> and the <see cref="BaseFilter"/>. 
        /// Call this method to refresh and apply the whole filter expression.
        /// </remarks>
        public void RebuildFilter()
        {
            mFilterIsActive = false;
            string Filter = "";
            foreach (DgvBaseColumnFilter CF in mColumnFilterList)
            {
                if (CF == null) continue;
                if (CF.Active && CF.FilterExpression != "")
                {
                    Filter += " AND (" + CF.FilterExpression + ")";
                    CF.DataGridViewColumn.HeaderText = CF.FilterCaption;
                }
                else
                {
                    CF.DataGridViewColumn.HeaderText = CF.OriginalDataGridViewColumnHeaderText;
                }

            }
            if (Filter != "")
            {
                mFilterIsActive = true;
                Filter = (mBaseFilter == "") ? "1=1 " + Filter : mBaseFilter + " " + Filter;
            }
            else
                Filter = mBaseFilter;

            // Apply the filter only if any changes occurred
            try
            {
                if (mBindingSource != null)
                {
                    if (mBindingSource.Filter != Filter) mBindingSource.Filter = Filter;
                }
                else
                {
                    if (mBoundDataView.RowFilter != Filter) mBoundDataView.RowFilter = Filter;
                }
            }
            catch { Console.WriteLine("Invalid filter: " + Filter); }

        }


        #endregion


        #region HELPERS

        // Checks if the DataGridView is data bound and the data source finally resolves to a DataView.
        private void FindDataView()
        {
            mBindingSource = null;
            object DataSource = mDataGridView.DataSource;
            string DataMember = mDataGridView.DataMember;

            string ExceptionMsg = "DataGridViewFilter can only work with bound DataGridView. The DataSource must be a DataSet, a DataTable, a DataView or a BindingSource which is bound to a DataSet, a DataTable or a DataView ";

            while (!(DataSource is DataView))
            {

                if (DataSource == null)
                {
                    return;
                }

                if (DataSource is BindingSource)
                {
                    mBindingSource = (BindingSource)DataSource;
                    DataMember = ((BindingSource)DataSource).DataMember;
                    DataSource = ((BindingSource)DataSource).DataSource;
                    continue;
                }
                if (DataSource is DataSet)
                {
                    DataSource = ((DataSet)DataSource).Tables[DataMember];
                    DataMember = "";
                    continue;
                }
                if (DataSource is DataTable)
                {
                    DataSource = ((DataTable)DataSource).DefaultView;
                    break;
                }
                if (DataSource is IList)
                {
                    var oTable = Fill(DataSource);
                    DataSource = oTable == null ? new DataView() : oTable.DefaultView;
                    break;
                }
                //other types are not allowed
                throw new Exception(ExceptionMsg);
            }
            mBoundDataView = (DataView)DataSource;
        }

        private DataTable Fill(object obj)
        {
            if (!(obj is IList))
            {
                return null;
            }
            var objlist = obj as IList;
            if (objlist == null || objlist.Count <= 0)
            {
                return null;
            }
            var tType = objlist[0];
            DataTable dt = new DataTable(tType.GetType().Name);
            DataColumn column;
            DataRow row;
            System.Reflection.PropertyInfo[] myPropertyInfo = tType.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var t in objlist)
            {
                if (t == null)
                {
                    continue;
                }
                row = dt.NewRow();
                for (int i = 0, j = myPropertyInfo.Length; i < j; i++)
                {
                    System.Reflection.PropertyInfo pi = myPropertyInfo[i];
                    string name = pi.Name;
                    if (dt.Columns[name] == null)
                    {
                        var coltype = pi.PropertyType;
                        if (coltype.Name == "Nullable`1")
                        {
                            //coltype = typeof(System.DBNull);
                            column = new DataColumn(name);
                        }
                        else
                        {
                            column = new DataColumn(name, coltype);
                        }
                        dt.Columns.Add(column);
                    }
                    row[name] = pi.GetValue(t, null);
                }
                dt.Rows.Add(row);
            }
            return dt;
        }


        //The funnel picture
        private static Image mFilterPicture;


        /// <summary>
        /// Gets a funnel picture.
        /// </summary>
        public static Image FunnelPicture
        {
            get
            {
                if (mFilterPicture == null)
                {
                    System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DgvFilterHost));
                    mFilterPicture = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
                }
                return mFilterPicture;
            }
        }


        private void CreateColumnFilter(DataGridViewColumn c)
        {
            if (mBoundDataView == null) return;
            if (!mAutoCreateFilters) return;
            //Raise the event about column filter creation
            ColumnFilterEventArgs e = new ColumnFilterEventArgs(c, null);
            if (ColumnFilterAdding != null) ColumnFilterAdding(this, e);
            //if not provided, by an event handler, proceed with standard filter creation
            if (e.ColumnFilter == null)
            {
                Type DataType = null;
                if (c.DataPropertyName != "")
                {
                    DataType = mBoundDataView.Table.Columns[c.DataPropertyName].DataType;

                    switch (c.GetType().Name)
                    {
                        case "DataGridViewComboBoxColumn":
                            e.ColumnFilter = new DgvComboBoxColumnFilter();
                            break;
                        case "DataGridViewCheckBoxColumn":
                            e.ColumnFilter = new DgvCheckBoxColumnFilter();
                            break;
                        case "DataGridViewTextBoxColumn":
                            if (DataType == typeof(DateTime))
                            {
                                e.ColumnFilter = new DgvDateColumnFilter();
                            }
                            else
                                e.ColumnFilter = new DgvTextBoxColumnFilter();
                            break;
                    }
                }
            }
            mColumnFilterList[c.Index] = e.ColumnFilter;
            if (e.ColumnFilter != null)
            { // == null when non-data column
                if (ColumnFilterAdded != null) ColumnFilterAdded(this, e);
                e.ColumnFilter.Init(this, FilterHost, c, mBoundDataView);
            }
        }

        #endregion



    }
}
View Code

 

2、DgvBaseFilterHost这个用户控件作为弹出过滤框的基类,代码如下:

public class DgvBaseFilterHost : UserControl {

        #region EVENTS

        /// <summary>
        /// Occurs when the current visible <i>column filter</i> is changed.
        /// </summary>
        public event EventHandler CurrentColumnFilterChanged;

        #endregion


        #region PRIVATE FIELDS

        private ToolStripDropDown mPopup;
        private DgvFilterManager mFilterManager;
        private DgvBaseColumnFilter mCurrentColumnFilter = null;
        private Size mSizeDifference;

        #endregion


        #region PROPERTIES


        /// <summary>
        /// Return the effective area to which <i>column filters</i> will be added.
        /// </summary>
        public virtual Control FilterClientArea { get { return this; } }

        public virtual ComboBox ComboBoxColumns { get; set; }

        public virtual Panel PanelFilterText { set; get; }



        /// <summary>
        /// Gets the <b>ToolStripDropDown</b> object used to popup the <i>filter host</i>
        /// </summary>
        public ToolStripDropDown Popup
        {
          get { 
              if (mPopup==null) {
                mPopup = new ToolStripDropDown();
                ToolStripControlHost ControlHost = new ToolStripControlHost(this);
                ControlHost.Padding = Padding.Empty;
                ControlHost.Margin = Padding.Empty;
                ControlHost.AutoSize = false;
                mPopup.Padding = Padding.Empty;
                mPopup.Items.Add(ControlHost);
                mPopup.Region = this.Region;
              }
              return mPopup; 
          }
        }


        
        /// <summary>
        /// Gets or sets the <i>filter manger</i> 
        /// </summary>
        public DgvFilterManager FilterManager {
            set { mFilterManager = value; }
            get { return mFilterManager; }
        }
                    

        
        /// <summary>
        /// Gets or sets the currently visibile <i>column filter</i> control
        /// </summary> 
        public DgvBaseColumnFilter CurrentColumnFilter {
            get { return mCurrentColumnFilter; }
            set {
                  // Called once: store the original size difference of the filterhost and the filterClientArea
                  if (mSizeDifference == Size.Empty) { 
                      mSizeDifference = System.Drawing.Size.Subtract(this.Size, FilterClientArea.Size);
                      this.MinimumSize = this.Size;
                  }
                  if (mCurrentColumnFilter != null) mCurrentColumnFilter.Visible = false;
                  mCurrentColumnFilter = value;
                  DoAutoFit();
                  if (CurrentColumnFilterChanged != null) {
                      EventArgs e = new EventArgs();
                      CurrentColumnFilterChanged(this, e);
                  }
                  mCurrentColumnFilter.Visible = true;
            }
        }


        /// <summary>
        /// Gets the original size difference of the <i>filter host</i> and the <see cref="DgvBaseFilterHost.FilterClientArea"/>.
        /// </summary>
        public Size SizeDifference {
            get { return mSizeDifference; }
        }

        #endregion


        #region HELPERS

        /// <summary>
        /// Performs growing / shrinking of the <i>filter host</i> to best fit the current visibile <i>column filter</i>.
        /// </summary>
        /// <remarks>
        /// Ovverride this method to provide your own resize logic.
        /// </remarks>
        protected virtual void DoAutoFit() {
            Size NewHostSize = Size.Add(mSizeDifference, mCurrentColumnFilter.Size);
            NewHostSize.Width = Math.Max(NewHostSize.Width, this.MinimumSize.Width);
            NewHostSize.Height= Math.Max(NewHostSize.Height, this.MinimumSize.Height);
            this.Size = NewHostSize;

            FilterClientArea.Size = Size.Subtract(NewHostSize, mSizeDifference);
            AlignFilter();
        }

        /// <summary>
        /// Aligns the <i>column filter</i> into the filter client area.
        /// </summary>
        /// <remarks>
        /// Ovverride this method to provide your own alignment logic.
        /// </remarks>
        protected void AlignFilter() { 
            int x = 0; // VFilterAlignmentType.Left:
            int y = 0; // HFilterAlignmentType.Top:
            switch (mCurrentColumnFilter.VFilterAlignment){
                case VFilterAlignment.Right:
                    x = FilterClientArea.Width - mCurrentColumnFilter.Width;
                 break;
                case VFilterAlignment.Center:
                    x = (FilterClientArea.Width - mCurrentColumnFilter.Width) / 2;
                 break;
            }

            switch (mCurrentColumnFilter.HFilterAlignment) {
                case HFilterAlignment.Bottom:
                    y = FilterClientArea.Height - mCurrentColumnFilter.Height;
                    break;
                case HFilterAlignment.Middle:
                    y = (FilterClientArea.Height - mCurrentColumnFilter.Height) / 2;
                    break;
            }
            //mCurrentColumnFilter.Location = new Point(x, y);

            mCurrentColumnFilter.Location = new Point(150, 20);
        }

        /// <summary>
        /// Returns a region based on the transparency color of a bitmap.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        /// <param name="transparencyColor">The transparency color.</param>
        /// <returns>A region</returns>
        public static Region BitmapToRegion(Bitmap bitmap, Color transparencyColor) {
            if (bitmap == null)
                throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");

            int height = bitmap.Height;
            int width = bitmap.Width;

            GraphicsPath path = new GraphicsPath();

            for (int j = 0; j < height; j++)
                for (int i = 0; i < width; i++) {
                    if (bitmap.GetPixel(i, j) == transparencyColor)
                        continue;

                    int x0 = i;

                    while ((i < width) && (bitmap.GetPixel(i, j) != transparencyColor))
                        i++;

                    path.AddRectangle(new Rectangle(x0, j, i - x0, 1));
                }

            Region region = new Region(path);
            path.Dispose();
            return region;
        }

        /// <summary>
        /// Registers the a combo box.
        /// </summary>
        /// <param name="comboBox">The combo box.</param>
        /// <remarks>
        /// When the user clicks on an <b>ComboBox</b> item that is outside of the
        /// host area, this cause an unwanted closing of the <i>filter host</i>. 
        /// If you use a <b>ComboBox</b> in a customized <i>column filter</i>, 
        /// be sure to call this method in your filter intitialitazion code.
        /// </remarks>
        public void RegisterComboBox (ComboBox comboBox){
            comboBox.DropDown += new EventHandler(onDropDown);
            comboBox.DropDownClosed += new EventHandler(onDropDownClosed);
        }

        private void onDropDown(object sender, EventArgs e)
        {
            //this.Popup.AutoClose = false;
        }

        private void onDropDownClosed(object sender, EventArgs e)
        {
            //this.Popup.AutoClose = true;
        }

        #endregion


    }
View Code

3、DgvBaseFilterHost的实现类

[ToolboxItem(false)]
    public partial class DgvFilterHost : DgvBaseFilterHost {

        /// <summary>
        /// Initializes a new instance of the <see cref="DgvFilterHost"/> class.
        /// </summary>
        public DgvFilterHost() {
            InitializeComponent();
            this.CurrentColumnFilterChanged += new EventHandler(DgvFilterHost_CurrentColumnFilterChanged);
            //不用点击非弹出框就关闭
            this.Popup.AutoClose = false;
        }

        void DgvFilterHost_CurrentColumnFilterChanged(object sender, EventArgs e) {
            //lblColumnName.Text = CurrentColumnFilter.OriginalDataGridViewColumnHeaderText;
        }

        /// <summary>
        /// Return the effective area to which the <i>column filters</i> will be added.
        /// </summary>
        /// <value></value>
        public override Control FilterClientArea {
            get {
                return this.panelFilterArea;
            }
        }

        public override ComboBox ComboBoxColumns
        {
            get
            {
                return this.comboBox_Cols;
            }
            //set
            //{
            //    this.comboBox_Cols = value;
            //}
        }

        public override Panel PanelFilterText
        {
            get
            {
                return this.panelFilterText;
            }
            //set
            //{
            //    this.panelFilterText = value;
            //}
        }

        private void tsOK_Click(object sender, EventArgs e) {
            //FilterManager.ActivateFilter(true);
            FilterManager.RebuildFilter();
            //this.Popup.Close();
            this.FindForm().Hide();
        }

        private void tsRemove_Click(object sender, EventArgs e) {
            FilterManager.ActivateFilter(false);
            this.Popup.Close();
        }

        private void tsRemoveAll_Click(object sender, EventArgs e) {
            FilterManager.ActivateAllFilters(false);
            FilterManager.SetFilterExpression();
            //this.Popup.Close();
        }

        private void pictureBox2_Click(object sender, EventArgs e)
        {
            this.Popup.Close();
        }

        private void pictureBox3_Click(object sender, EventArgs e)
        {
            //0.激活当前过滤列并过滤
            FilterManager.ActivateFilter(true);

            //1.重新绑定过滤条件
            FilterManager.SetFilterExpression();
        }


    }
View Code

 

4、DgvBaseColumnFilter这个用户控件作为过滤列选项的基类,代码如下:

/// <summary>
    /// Specifies how the <i>column filter</i> control is horizontally aligned inside the <i>filter host</i>.
    /// </summary>
    public enum HFilterAlignment { Top, Bottom, Middle }


    /// <summary>
    /// Specifies how the <i>column filter</i> control is vertically aligned inside the <i>filter host</i>.
    /// </summary>
    public enum VFilterAlignment { Left, Right, Center }


    /// <summary>
    /// The base class from which to derive effective <i>column filter</i> classes
    /// </summary>
    /// <remarks>
    /// The purpose of a <i>column filter</i> control is to contain visual elements allowing the end user to construct a filter.
    /// When inheriting from it, you can work just like creating any other user control. 
    /// This class is a derivation of <b>UserControl</b> and provide functionalities to 
    /// cooperate with DgvFilterManager. 
    /// <para>
    /// NOTE: 
    /// This class must be intended as an abstract class. However, declaring it as abstract,
    /// would generate errors whitin the designer when designing derived classes.
    /// </para>
    /// <para>
    /// You should override <see cref="DgvBaseColumnFilter.OnFilterExpressionBuilding"/> to provide a filter expression construction 
    /// logic and to set the values of the <see cref="DgvBaseColumnFilter.FilterExpression"/> and <see cref="DgvBaseColumnFilter.FilterCaption"/> properties. 
    /// </para>
    /// </remarks>      
    public class DgvBaseColumnFilter : UserControl {

        #region EVENTS

        /// <summary>
        /// Occurs before the filter expression is about to be built.
        /// </summary>
        public event CancelEventHandler FilterExpressionBuilding;


        /// <summary>
        /// Occurs when the filter column is about to be initialized.
        /// </summary>
        public event CancelEventHandler FilterInitializing;

        #endregion


        #region PRIVATE FIELDS

        private VFilterAlignment mVFilterAlignment = VFilterAlignment.Center;
        private HFilterAlignment mHFilterAlignment = HFilterAlignment.Middle;
        private DgvBaseFilterHost mFilterHost;
        private DgvFilterManager mFilterManager;
        private DataGridViewColumn mDataGridViewColumn;
        private DataView mBoundDataView;
        private Type mColumnDataType;
        private string mOriginalDataGridViewColumnHeaderText;
        private bool mActive;
        private bool mFilterApplySoon = true;

        private string mFilterExpression = "";
        private string mFilterCaption = "";

        #endregion


        #region PROPERTIES


        /// <summary>
        /// Gets or sets a value indicating whether filter apply soon after a user performs some changes.
        /// </summary>
        /// <value><c>true</c> (default) if to apply soon; otherwise, <c>false</c>.</value>
        public bool FilterApplySoon {
            get { return mFilterApplySoon; }
            set { mFilterApplySoon = value; }
        }

        /// <summary>
        /// Gets and sets the filter expression.
        /// </summary>
        /// <remarks>
        /// It's the filter expression on the column. Its value is used by the <see cref="DgvFilterManager"/> to build the whole filter expression.
        /// In inherited class, set its value in the override of <see cref="DgvBaseColumnFilter.OnFilterExpressionBuilding"/>.
        /// The filter expression must follow the rules of the DataView <see cref="System.Data.DataView.RowFilter"/> property.
        /// </remarks>
        public string FilterExpression {
            get { return mFilterExpression; }
            set { mFilterExpression = value; }
        }

        /// <summary>
        /// Gets and sets the caption to show in the column header when the filter is active.
        /// </summary>
        /// <remarks>
        /// Represents the caption to show in the column header when the filter is active.
        /// In inherited class, set its value in the override of <see cref="DgvBaseColumnFilter.OnFilterExpressionBuilding"/>.
        /// </remarks>
        public string FilterCaption { 
            get { return ( (mActive && mFilterExpression!="") ? mFilterCaption : mOriginalDataGridViewColumnHeaderText) ; }
            set { mFilterCaption = value; }
        }


        /// <summary>
        /// Gets or sets a value indicating whether the filter is active.
        /// </summary>
        /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
        public bool Active {
          get { return (mActive); }
          set { mActive = value; }
        }

        /// <summary>
        /// Specifies how the <i>column filter</i> control is horizontally aligned inside the <i>filter host</i>.
        /// </summary>
        public HFilterAlignment HFilterAlignment {
            get { return mHFilterAlignment; }
            set { mHFilterAlignment = value; 
            }
        }


        /// <summary>
        /// Specifies how the <i>column filter</i> control is vertically aligned inside the <i>filter host</i>.
        /// </summary>
        public VFilterAlignment VFilterAlignment {
            get { return mVFilterAlignment; }
            set { mVFilterAlignment = value; }
        }



        /// <summary>
        /// Gets the <b>DataView</b> acting as the data source of the <b>DataGridView</b> to which this <i>column filter</i> is applied.
        /// </summary>
        public DataView BoundDataView { get { return mBoundDataView; }}


        /// <summary>
        /// Gets the <i>filter host</i> control in which this <i>column filter</i> is shown.
        /// </summary>
        public DgvBaseFilterHost FilterHost { get { return mFilterHost; }}


        /// <summary>
        /// Gets the <i>filter manager</i>.
        /// </summary>
        public DgvFilterManager FilterManager { get { return mFilterManager; }}


        /// <summary>
        /// Gets the <b>DataGridView</b> column to which this <i>column filter</i> is applied.
        /// </summary>
        /// <value>The data grid view column.</value>
        public DataGridViewColumn DataGridViewColumn { get { return mDataGridViewColumn; }}


        /// <summary>
        /// Gets the type of the data bound to the <b>DataGridView</b> column.
        /// </summary>
        public Type ColumnDataType { get { return mColumnDataType; }}



        /// <summary>
        /// Gets the original <b>DataGridView</b> column header text.
        /// </summary>
        public string OriginalDataGridViewColumnHeaderText { get { return mOriginalDataGridViewColumnHeaderText; } }


        #endregion


        #region FILTER INITIALIZATION, EXPRESSION BUILDING, EVENT MANAGING

        /// <summary>
        /// Called by the <i>filter manager</i>, inits the <i>column filter</i> and raises the FilterInitializing event.
        /// </summary>
        /// <param name="FilterManager">The <i>filter manager</i>.</param>
        /// <param name="FilterHost">The filter host.</param>
        /// <param name="gridColumn">The DataGridView column.</param>
        /// <param name="boundDataView">The bound data view.</param>
        public void Init(DgvFilterManager FilterManager, DgvBaseFilterHost FilterHost, DataGridViewColumn gridColumn,DataView boundDataView){
            this.mFilterManager = FilterManager;
            this.mFilterHost = FilterHost;
            this.mDataGridViewColumn = gridColumn;
            this.mBoundDataView = boundDataView;
            this.mOriginalDataGridViewColumnHeaderText = gridColumn.HeaderText;
            if (gridColumn.DataPropertyName != "")
                this.mColumnDataType = boundDataView.Table.Columns[gridColumn.DataPropertyName].DataType;
            else
                this.mColumnDataType = typeof(string);
            FilterHost.FilterClientArea.Controls.Add(this);
            FilterHost.Location = new System.Drawing.Point(0, 0);
            this.Visible = false;
            CancelEventArgs e = new CancelEventArgs(false);
            OnFilterInitializing(this, e);
        }

        /// <summary>
        /// Raises the <see cref="DgvBaseColumnFilter.FilterInitializing"/> event
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        /// <remarks>
        /// When this <i>column filter</i> control is added to the <i>column filters</i> array of the <i>filter manager</i>, 
        /// the latter calls the <see cref="DgvBaseColumnFilter.Init"/> method which, in turn, calls this method. 
        /// You can ovverride this method to provide initialization code. 
        /// </remarks>
        protected virtual void OnFilterInitializing(object sender, CancelEventArgs e) {
            // Ovverride to add custom init code
            if (FilterInitializing != null) FilterInitializing(sender, e);
        }

        /// <summary>
        /// Forces the rebuilt of filter expression
        /// </summary>
        /// <remarks>
        /// This method is called by <see cref="DgvFilterManager"/> when popup is closed, to 
        /// force recreation of the filter expression. 
        /// </remarks>
        public void FilterExpressionBuild() {
            CancelEventArgs e = new CancelEventArgs(false);
            OnFilterExpressionBuilding(this,e);
        }

        /// <summary>
        /// Raises the <see cref="DgvBaseColumnFilter.FilterExpressionBuilding"/> event
        /// </summary>
        /// <param name="sender">The event source.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        /// <remarks>
        /// Override <b>OnFilterExpressionBuilding</b> to provide a filter expression construction 
        /// logic and to set the values of the <see cref="DgvBaseColumnFilter.FilterExpression"/> and <see cref="DgvBaseColumnFilter.FilterCaption"/> properties.
        /// The <see cref="DgvFilterManager"/> will use these properties in constructing the whole filter expression and to change the header text of the filtered column.
        /// </remarks>
        protected virtual void OnFilterExpressionBuilding(object sender,CancelEventArgs e) {
            if (FilterExpressionBuilding != null) FilterExpressionBuilding(sender, e);
        }



        #endregion


        #region HELPERS

        /// <summary>
        /// Escapes a string to be suitable for filter expression.
        /// </summary>
        /// <param name="s">The string to escape.</param>
        /// <returns>The escaped string</returns>
        public static string StringEscape(string s){
            char[] sarray = s.ToCharArray();
            StringBuilder sb = new StringBuilder(s.Length * 2);
            foreach (char c in sarray) {
                switch (c){
                    case '%': case '*': case '[': case ']':
                        sb.Append("[" + c + "]");
                        break;
                    case '\'':
                        sb.Append("''");
                        break;
                    default:
                        sb.Append(c);
                        break;
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns the string representation of the passed value, based on target type.
        /// </summary>
        /// <param name="value">The value to be formatted.</param>
        /// <param name="targetType">The target type.</param>
        /// <returns>The string representation of the passed value</returns>
        public static string FormatValue(object value,Type targetType){
            if (targetType == typeof(string)) return "'" + value.ToString() + "'";
            try {
                value = Convert.ChangeType(value, targetType);
            } catch { return ""; }

            if (targetType == typeof(bool)) return ((bool)value) ? "1" : "0";
            if (targetType == typeof(DateTime)) return "'" + ((DateTime)value).ToString("yyyy'-'MM'-'dd") +"'";
            //Numeric types
            return ((IFormattable)value).ToString(null, NumberFormatInfo.InvariantInfo);
        }

        /// <summary>
        /// Returns a null condition string to be used in filter expression.
        /// </summary>
        /// <param name="DataColumnName">Name of the data column.</param>
        /// <returns>A string to be used in the filter expression representing a null condition</returns>
        public static string GetNullCondition (string DataColumnName){
            return "ISNULL(CONVERT(" + DataColumnName+ ",'System.String'),'NULLVALUE') = 'NULLVALUE'";
        }

        /// <summary>
        /// Returns a not null condition string to be used in filter expression.
        /// </summary>
        /// <param name="DataColumnName">Name of the data column.</param>
        /// <returns>A string to be used in the filter expression representing a not null condition</returns>
        public static string GetNotNullCondition (string DataColumnName){
            return "ISNULL(CONVERT(" + DataColumnName+ ",'System.String'),'NULLVALUE') <> 'NULLVALUE'";
        }

        #endregion

    }
View Code

5、DgvBaseColumnFilter的实现类有多个,分别定义不同类型的过滤列:

   5.1、Textbox原型的过滤子类

   5.2、ComboBox原型的过滤子类

 

 

应博友要求,附上源码。源码下载

源码可能和贴图上面不太一样,是因为贴图上面是和我们项目样式相关的,项目太大,无法贴上来。源码是测试功能用的,原来从别处下载下来改写了下,但功能和贴图上面是差不多的,有兴趣的可以看看。

 

posted @ 2015-06-29 14:41  懒得安分  阅读(19300)  评论(15编辑  收藏  举报