⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listviewfilter.cs

📁 This control is another extension to the now standard and widely used ListView control. I have inclu
💻 CS
📖 第 1 页 / 共 4 页
字号:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace ListViewFilter
{

  #region Namespace specific enumerations

  /// <summary>
  /// Data type of column content
  /// </summary>
  public enum LVFDataType
  {
    String,
    Number,
    Date
  }


  /// <summary>
  /// Type of comparison requested by the filter
  /// </summary>
  public enum LVFFilterType
  {
    Equal,
    NotEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual
  }


  #endregion

  /// <summary>
  /// This is a specialization of a ListView control that defaults to
  /// details mode and includes the ability to filter data on column
  /// headers and to specify column data sort comparison type. 
  /// </summary>
  public class ListViewFilter : System.Windows.Forms.ListView
  {

    #region Private class data

    private bool         hdr_filter = false;              // Display column filters
    private int          srt_column = 0;                  // Sort column
    private bool         srt_sorder = true;               // Sort ascending/descending
    private LVFDataType  srt_datype = LVFDataType.String; // Sort data type comparison
    private bool         flt_ignore = false;              // Ignore case on filter
    private Color        col_scolor = Color.WhiteSmoke;   // Shade color
    private bool         col_shaded = true;               // Display shade color
    private ArrayList    itm_filtrs = new ArrayList();    // Array of LVFFliters active
    private ArrayList    itm_filtrd = new ArrayList();    // Filtered out items
    private ArrayList    itm_holder = new ArrayList();    // Held out items
    private int          mnu_column = 0;                  // Filter button column
    private float        cmp_float1 = float.MaxValue;     // float value for compare
    private float        cmp_float2 = float.MaxValue;     // float value for compare
    private DateTime     cmp_datim1 = DateTime.MaxValue;  // date value for compare
    private DateTime     cmp_datim2 = DateTime.MaxValue;  // date value for compare

    /// <summary>
    /// Instance pointer to the header control interface
    /// </summary>
    private ListViewFilterHeader hdr_contrl = null;

    /// <summary>
    /// Filter data structure for individual column data.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)] internal struct LVFFilter 
    {
      internal int           Column;
      internal LVFFilterType Compare;
      internal LVFDataType   Type;
      internal string        Text;
    }

    /// <summary>
    /// This is the context menu and items that appear when a filter
    /// button is clicked.  This allows customizations for a column.
    /// </summary>
    private ContextMenu mnu_filter = new ContextMenu();
    private MenuItem mnu_datype = new MenuItem( "&Data type" );
    private MenuItem mnu_alignt = new MenuItem( "&Alignment" );
    private MenuItem mnu_clearf = new MenuItem( "&Clear filter" );
    private MenuItem mnu_ignore = new MenuItem( "&Ignore case" );
    private MenuItem mnu_strflt = new MenuItem( "&String" );
    private MenuItem mnu_nbrflt = new MenuItem( "&Number" );
    private MenuItem mnu_datflt = new MenuItem( "&Date" );
    private MenuItem mnu_alignl = new MenuItem( "&Left" );
    private MenuItem mnu_alignr = new MenuItem( "&Right" );
    private MenuItem mnu_alignc = new MenuItem( "&Center" );

    #endregion

    #region Windows API interfaces
    [DllImport("user32.dll")] internal static extern int SendMessage( IntPtr hWnd, W32_LVM msg, int wParam, int lParam );
    [DllImport("user32.dll")] internal static extern int SendMessage( IntPtr hWnd, W32_LVM msg, int wParam, ref LVITEM hditem );
    [DllImport("user32.dll")] internal static extern int SendMessage( IntPtr hWnd, W32_LVM msg, int wParam, ref RECT hditem );
    #endregion 

    #region Constructor and Dispose methods

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    /// <summary>
    /// Constructor, nothing done here but InitializeComponent as usual.
    /// </summary>
    public ListViewFilter()
    {

      // This call is required by the Windows.Forms Form Designer.
      InitializeComponent();

    }


    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">True if really disposing?</param>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if( components != null )
          components.Dispose();
      }
      base.Dispose( disposing );
    }


    #endregion

    #region Component Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// NOTE: We have modified this method to include the context
    /// menu and items creation as if this was a form control.
    /// </summary>
    private void InitializeComponent()
    {
      // 
      // ListViewFilter
      // 
      this.Name = "ListViewFilter";
      this.View = View.Details;
      this.ListViewItemSorter = new ListViewFilterSorter( this );
      //
      // mnu_filter
      //
      this.mnu_filter.MenuItems.AddRange( new System.Windows.Forms.MenuItem[]
        { this.mnu_datype, this.mnu_alignt, this.mnu_clearf, this.mnu_ignore } );
      this.mnu_filter.Popup += new System.EventHandler( this.ContextMenuPopup );
      // 
      // mnu_datype
      // 
      this.mnu_datype.Index = 0;
      this.mnu_datype.MenuItems.AddRange( new System.Windows.Forms.MenuItem[] 
        { this.mnu_strflt, this.mnu_nbrflt, this.mnu_datflt } );
      // 
      // mnu_alignt
      // 
      this.mnu_alignt.Index = 1;
      this.mnu_alignt.MenuItems.AddRange( new System.Windows.Forms.MenuItem[] 
        { this.mnu_alignl, this.mnu_alignr, this.mnu_alignc } );
      // 
      // mnu_clearf
      // 
      this.mnu_clearf.DefaultItem = true;
      this.mnu_clearf.Index = 2;
      this.mnu_clearf.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_refrsh
      // 
      this.mnu_ignore.Index = 3;
      this.mnu_ignore.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_strflt
      // 
      this.mnu_strflt.Index = 0;
      this.mnu_strflt.RadioCheck = true;
      this.mnu_strflt.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_nbrflt
      // 
      this.mnu_nbrflt.Index = 1;
      this.mnu_nbrflt.RadioCheck = true;
      this.mnu_nbrflt.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_datflt
      // 
      this.mnu_datflt.Index = 2;
      this.mnu_datflt.RadioCheck = true;
      this.mnu_datflt.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_alignl
      // 
      this.mnu_alignl.Index = 0;
      this.mnu_alignl.RadioCheck = true;
      this.mnu_alignl.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_alignr
      // 
      this.mnu_alignr.Index = 1;
      this.mnu_alignr.RadioCheck = true;
      this.mnu_alignr.Click += new System.EventHandler( this.MenuItemClick );
      // 
      // mnu_alignc
      // 
      this.mnu_alignc.Index = 2;
      this.mnu_alignc.RadioCheck = true;
      this.mnu_alignc.Click += new System.EventHandler( this.MenuItemClick );

    }


    #endregion

    #region Overridden System.Windows.Forms.Control methods
    
    /// <summary>
    /// When the handle changes we need to recreate the Filter
    /// Header instance.  The previous (if any) header instance
    /// was tied to a handle that is now gone.
    /// </summary>
    /// <param name="e">Event</param>
    protected override void OnHandleCreated(System.EventArgs e)
    {
      base.OnHandleCreated(e);

      // now that we have a handle, create the HeaderControl instance
      hdr_contrl = new ListViewFilterHeader( this, hdr_filter,
        srt_column, srt_sorder );

    }

    /// <summary>
    /// When our handle is removed we give the hdr_contrl a little
    /// help by telling him now is a good time to release its handle.
    /// From now on, we do not have a hdr_contrl instance active
    /// so we set hdr_contrl to null and don't use it until reset.
    /// </summary>
    /// <param name="e">Event</param>
    protected override void OnHandleDestroyed(System.EventArgs e)
    {

      // free and then delete the ListViewFilterHeader control
      if ( hdr_contrl != null )
      {
        hdr_contrl.ReleaseHandle();
        hdr_contrl = null;
      }

      // do this AFTER we tell the ListViewFilterHeader to release
      base.OnHandleDestroyed(e);

    }


    /// <summary>
    /// Only three windows messages are trapped here: WM_ERASEBKGND 
    /// since the OnPaintBackground doesn't work for the ListView,
    /// WM_NOTIFY so that we can get all the ListViewFilterHeader
    /// notificiations, and OCM_NOTIFY for our own notifications.
    /// </summary>
    /// <param name="m">Message</param>
    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
      base.WndProc(ref m);

      // determine if we want to process this message type
      switch ( m.Msg )
      {

        // erase background causes us to repaint the shaded sort column.
        case (int)W32_WM.WM_ERASEBKGND:

          // there has to be a header and we have to be in Details mode
          if ( col_shaded && ( hdr_contrl != null ) && ( this.View == View.Details ) )
          {

            // get the 'fake' size information from the header
            // column.  this is only the Width and Left (as Height).
            Size z = hdr_contrl.SizeInfo[ srt_column ];

            // get a temporary graphics object to fill the rectangle.
            // NOTE: it would be nice to g.ReleaseHdc( m.WParam ) but
            // it doesn't work for some reason, it may not be needed...
            Graphics g = Graphics.FromHdc( m.WParam );
            g.FillRectangle( new SolidBrush( col_scolor ),
              z.Height, Top, z.Width, Height );

          }
          break;

        // notify messages can come from the header and are used 
        // for column sorting and item filtering if wanted
        case (int)W32_WM.WM_NOTIFY:

          // get the notify message header from this message LParam
          NMHEADER h1 = (NMHEADER)m.GetLParam( typeof( NMHEADER ) );

          // process messages ONLY from our header control
          if ( ( hdr_contrl != null ) && ( h1.hdr.hwndFrom == hdr_contrl.Handle ) )
            NotifyHeaderMessage( h1 );

          break;

        // internal ListView notify messages are reflected to us via OCM
        case (int)W32_OCM.OCM_NOTIFY:
          
          // get the notify message header from this message LParam
          NMHEADER h2 = (NMHEADER)m.GetLParam( typeof( NMHEADER ) );

          // process ONLY messages that are to this ListView control
          if ( h2.hdr.hwndFrom == Handle ) 
          {

            // process only specific ListView notify messages
            switch ( h2.hdr.code )
            {
              
              // draw message, we return a result for the drawstate
              case (int)W32_NM.NM_CUSTOMDRAW:
                NMLVCUSTOMDRAW d = (NMLVCUSTOMDRAW)m.GetLParam( typeof( NMLVCUSTOMDRAW ) );
                m.Result = (IntPtr)NotifyCustomDraw( d );
                break;

            }
          }
          break;

      }
    }

   
    #endregion

    #region Private methods

    /// <summary>
    /// NM_CUSTOMDRAW processing for the ListView control.  Here all
    /// we really want to do is redraw the shaded background for the
    /// column that is currently sorted, let the base do the work.
    /// </summary>
    /// <param name="d">NMLVCUSTOMDRAW to process</param>
    /// <returns>Return the result of the draw stage</returns>
    private W32_CDRF NotifyCustomDraw( NMLVCUSTOMDRAW d )
    {

      // determine the draw stage and set return value
      switch ( d.nmcd.dwDrawStage )
      {

        // first request, ask for each item notification if we shade columns
        case (int)W32_CDDS.CDDS_PREPAINT:
          if ( col_shaded && ( this.View == View.Details ) )
            return W32_CDRF.CDRF_NOTIFYITEMDRAW;
          break;

        // next request, ask for each sub item notification for this item
        case (int)W32_CDDS.CDDS_ITEMPREPAINT:
          return W32_CDRF.CDRF_NOTIFYSUBITEMDRAW;

        // here is the real work, and it is simply ensuring that the
        // correct backcolor is set for the shaded column.  we let the
        // regular windows control drawing do the real work.
        case (int)W32_CDDS.CDDS_SUBITEMPREPAINT:

          // ensure that this is a valid item/subitem request
          if ( d.nmcd.dwItemSpec < this.Items.Count )
          {

            // get a reference to the item to be rendered
            ListViewItem i = this.Items[ d.nmcd.dwItemSpec ];

            // is this for a a base item set it's backcolor
            if ( d.iSubItem == 0 ) 
              i.BackColor = ( d.iSubItem == srt_column ) 
                ? col_scolor : this.BackColor;

            // ensure that the subitem exits before changing it
            else if ( ( d.iSubItem < i.SubItems.Count ) &&
              ( i.SubItems[ d.iSubItem ] != null ) ) 
              i.SubItems[ d.iSubItem ].BackColor = 
                ( d.iSubItem == srt_column ) ? col_scolor : this.BackColor;

          }
          break;
      }

      // let default drawing do the actual rendering
      return W32_CDRF.CDRF_DODEFAULT;

    }


    /// <summary>
    /// When the header control sends a notification we need to 
    /// process the click to sort, button click for options menu,
    /// and filter change to update the items currently visible.
    /// </summary>
    /// <param name="h">NMHEADER</param>
    private void NotifyHeaderMessage( NMHEADER h )
    {

      // process only specific header notification messages
      switch ( h.hdr.code )
      {

        // a header column was clicked, do the sort
        case (int)W32_HDN.HDN_ITEMCLICKA:
        case (int)W32_HDN.HDN_ITEMCLICKW:
          hdr_contrl.SortColumn = srt_column = h.iItem;
          srt_sorder = hdr_contrl.SortOrder;
          srt_datype = hdr_contrl.DataType[ srt_column ];
          this.Sort();
          break;

        // a filter button was clicked display the popup menu
        // to handle setting filter options for the column
        case (int)W32_HDN.HDN_FILTERBTNCLICK:
          mnu_column = h.iItem;
          mnu_filter.Show( this, PointToClient( MousePosition ) );
          break;

        // a filter content changed, update the items collection
        case (int)W32_HDN.HDN_FILTERCHANGE:

          // if this is for item -1 then this is a clear all filters
          if ( h.iItem < 0 ) itm_filtrs.Clear();

          // if we are filtered this is a real filter data change
          else if ( hdr_filter ) FilterBuild( h.iItem );

          // update the items array with new filters applied
          FilterUpdate();
          break;

      }
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -