1. 程式人生 > >WinForm輕鬆實現自定義分頁

WinForm輕鬆實現自定義分頁

以前都是做web開發,最近接觸了下WinForm,發現WinForm分頁控制元件好像都沒有,網上搜索了一下,發現有很多網友寫的分頁控制元件,分頁效果應該都能實現吧,只是其風格都不是很符合我想要的。做web的時候,我習慣了Extjs的Grid分頁效果,所以也想在WinForm中做個類似的效果,所以咬咬牙,做個山寨版本的吧,雖然自己寫費時費力,在專案進度考慮中不是很可取,但是還是特別想山寨一回,做自己喜歡的風格。

按照慣例,還是先看看實現效果圖吧(有圖有真像,才好繼續下文呀)

應用效果:(效果有點難看,因為我是剛裝的

xp系統,還是經典主題,如果換成Win7系統或其他主題,效果還是會很不錯的)

 

我們要做的就是上圖顯示的一個自定義控制元件,這個效果參考自我做

web開發使用的Extjs之Grid的分頁效果(如下圖)

 

Extjs的動畫效果我們暫時就不實現了,這裡只做個外觀看起來想像即可,完全一樣就脫離“山寨”概念了,總要比人家差點吧,誰讓咱是模仿呢!

言歸正傳,我們現在就看看具體怎麼實現吧:

第一步:先佈局

注:我們建立的是使用者自定義控制元件,而不是WinForm窗體

就是先做出個顯示效果,這個佈局很簡單,在這就不多說,重點就是“首頁、前一頁、後一頁、末頁”圖示,每個圖示分兩種,一是能點選的高亮效果,一個是灰色不不能點選。以下是套圖:(大家如果不喜歡,可以去做成自己喜歡的風格圖片)

第二步:編寫分頁程式碼

佈局好了,那麼第二步我們就要程式碼實現正確顯示文字資訊,分頁事件,每頁條數選擇事件,公開屬性和事件。以下是完整程式碼:

/// <summary>

    /// 宣告委託

    /// </summary>

    /// <param name="e"></param>

    public delegate void EventPagingHandler(EventArgs e);

 

    public partial class Paging : UserControl

    {

 

 

        public Paging()

        {

            InitializeComponent();

        }

 

        public event EventPagingHandler EventPaging;

 

        #region 公開屬性

 

 

        private int _pageSize = 50;

        /// <summary>

        /// 每頁顯示記錄數(預設50)

        /// </summary>

        public int PageSize

        {

            get

            {

                return _pageSize;

            }

            set 

            {

                if (value > 0)

                {

                    _pageSize = value;

                }

                else

                {

                    _pageSize = 50;

                }

                this.comboPageSize.Text = _pageSize.ToString();

            }

        }

        private int _currentPage = 1;

        /// <summary>

        /// 當前頁

        /// </summary>

        public int CurrentPage

        {

            get 

            {

                return _currentPage;

            }

            set 

            {

                if (value > 0)

                {

                    _currentPage = value;

                }

                else

                {

                    _currentPage = 1;

                }

                

            }

        }

        private int _totalCount = 0;

        /// <summary>

        /// 總記錄數

        /// </summary>

        public int TotalCount

        {

            get

            {

                return _totalCount;

            }

            set 

            {

                if (value>=0)

                {

                    _totalCount = value;

                } 

                else

                {

                    _totalCount = 0;

                }

                this.lblTotalCount.Text = this._totalCount.ToString();

                CalculatePageCount();

                this.lblRecordRegion.Text = GetRecordRegion();

            }

        }

 

        private int _pageCount = 0;

        /// <summary>

        /// 頁數

        /// </summary>

        public int PageCount

        {

            get

            {

                return _pageCount;

            }

            set 

            {

                if (value>=0)

                {

                    _pageCount = value;

                } 

                else

                {

                    _pageCount = 0;

                }

                this.lblPageCount.Text = _pageCount + "";

            }

        }

 

       #endregion

 

        /// <summary>

        /// 計算頁數

        /// </summary>

        private void CalculatePageCount()

        {

            if (this.TotalCount>0)

            {

                this.PageCount = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(this.TotalCount) / Convert.ToDouble(this.PageSize)));

            }

            else

            {

                this.PageCount = 0;

            }

        }

 

        /// <summary>

        /// 獲取顯示記錄區間(格式如:1-50)

        /// </summary>

        /// <returns></returns>

        private string GetRecordRegion()

        {

            if (this.PageCount == 1) //只有一頁

            {

                return "1-" + this.TotalCount.ToString();

            }

            else  //有多頁

            {

                if(this.CurrentPage==1) //當前顯示為第一頁

                {

                    return "1-"+this.PageSize;

                }

                else if(this.CurrentPage==this.PageCount) //當前顯示為最後一頁

                {

                    return ((this.CurrentPage-1)*this.PageSize+1) +"-"+this.TotalCount;

                }

                else //中間頁

                {

                    return ((this.CurrentPage-1) * this.PageSize+1)   + "-" + this.CurrentPage  * this.PageSize;

                }

              
            }

        }

 

 

        /// <summary>

        /// 資料繫結

        /// </summary>

        public void Bind()

        {

            if (this.EventPaging != null)

            {

                this.EventPaging(new EventArgs());

            }

            if (this.CurrentPage>this.PageCount)

            {

                this.CurrentPage = this.PageCount;

            }

            this.txtBoxCurPage.Text = this.CurrentPage+"";

            this.lblTotalCount.Text = this.TotalCount+"";

            this.lblPageCount.Text = this.PageCount+"";

            this.lblRecordRegion.Text = GetRecordRegion();

            if (this.CurrentPage==1)

            {

                this.btnFirst.Enabled = false;

                this.btnPrev.Enabled = false;

                this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;

                this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled;

            }

            else

            {

                this.btnFirst.Enabled = true;

                this.btnPrev.Enabled = true;

                this.btnFirst.Image = global::CHVM.Properties.Resources.page_first;

                this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev;

            }

            if (this.CurrentPage == this.PageCount)

            {

                this.btnNext.Enabled = false;

                this.btnLast.Enabled = false;

                this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled;

                this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled;

            } 

            else

            {

                this.btnNext.Enabled = true;

                this.btnLast.Enabled = true;

                this.btnNext.Image = global::CHVM.Properties.Resources.page_next;

                this.btnLast.Image = global::CHVM.Properties.Resources.page_last;

            }

            if (this.TotalCount==0)

            {

                this.btnFirst.Enabled = false;

                this.btnPrev.Enabled = false;

                this.btnNext.Enabled = false;

                this.btnLast.Enabled = false;

                this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;

                this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled;

                this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled;

                this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled;

            }

 

        }

 

        private void btnFirst_Click(object sender, EventArgs e)

        {

            this.CurrentPage = 1;

            this.Bind();

        }

 

        private void btnPrev_Click(object sender, EventArgs e)

        {

            this.CurrentPage -= 1;            

            this.Bind();

        }

 

        private void btnNext_Click(object sender, EventArgs e)

        {

            this.CurrentPage += 1;

            this.Bind();

        }

 

        private void btnLast_Click(object sender, EventArgs e)

        {

            this.CurrentPage = this.PageCount;

            this.Bind();

        }

 

        /// <summary>

        ///  改變每頁條數

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void comboPageSize_SelectedIndexChanged(object sender, EventArgs e)

        {

            this.PageSize = Convert.ToInt32(comboPageSize.Text);

            this.Bind();

        }

 

}

 

這裡重點提兩點:一是圖片切換:

this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;

Image物件是在Properties.Resource.resx中自動生成的,程式碼如下:

        internal static System.Drawing.Bitmap page_first {

            get {

                object obj = ResourceManager.GetObject("page-first", resourceCulture);

                return ((System.Drawing.Bitmap)(obj));

            }

        }

        

        internal static System.Drawing.Bitmap page_first_disabled {

            get {

                object obj = ResourceManager.GetObject("page_first_disabled", resourceCulture);

                return ((System.Drawing.Bitmap)(obj));

            }

    }

二是應用了委託事件:我們在這定義了一個分頁事件

public event EventPagingHandler EventPaging;

在資料繫結方法中實現它:

/// <summary>

        /// 資料繫結

        /// </summary>

        public void Bind()

        {

            if (this.EventPaging != null)

            {

                this.EventPaging(new EventArgs());

            }

            //… 以下省略

}

這裡需要大家對C#的委託和事件有一定的瞭解,不清楚的可以直接使用,或者先去查閱相關參考資料,這裡我們就不談委託機制了。

 

第三步:應用

值得一提的是,WinForm並不能直接把使用者自定控制元件往Windows窗體中拖拽,而自動生成例項(ASP.NET是可以直接拖拽的)。那麼如果我們需要在應用中使用,只能自己修改Desginer.cs程式碼了。

先宣告:

private CHVM.PagingControl.Paging paging1;

然後在InitializeComponent()方法中例項化:

this.paging1 = new CHVM.PagingControl.Paging();

    // 

    // paging1

    // 

    this.paging1.CurrentPage = 1;

    this.paging1.Location = new System.Drawing.Point(3, 347);

    this.paging1.Name = "paging1";

    this.paging1.PageCount = 0;

    this.paging1.PageSize = 50;

    this.paging1.Size = new System.Drawing.Size(512, 30);

    this.paging1.TabIndex = 8;

 this.paging1.TotalCount = 0; 

//在這裡註冊事件

this.paging1.EventPaging += new CHVM.PagingControl.EventPagingHandler(this.paging1_EventPaging);

加完後就能看到效果了,相當於託了一個分頁控制元件的效果:(如下圖所示)

最後在事件中加入分頁事件需要執行的程式碼:


/// <summary>

        /// 分頁事件

        /// </summary>

        /// <param name="e"></param>

        private void paging1_EventPaging(EventArgs e)

        {

            GvDataBind();   //DataGridView資料繫結

        }

        /// <summary>

        /// 查詢

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnQuery_Click(object sender, EventArgs e)

        {

            paging1_EventPaging(e);

        }

        /// <summary>

        /// gvOperateLogList 資料邦定

        /// </summary>

        private void GvDataBind()

        {

            PagingCondition paging = new PagingCondition()

            {

                startIndex=paging1.CurrentPage,

                pageSize = paging1.PageSize

            };

            MultiCondition condition = new MultiCondition();

            condition.DateSign="FOperateTime";

            condition.BeginDate = dtBegin.Value;

            condition.EndDate = dtEnd.Value;

            if (comboOperator.Text != "")

            {

                condition.Dict.Add("FOperator", comboOperator.Text);

            }

            if (comboType.Text != "")

            {

                condition.Dict.Add("FType", comboType.Text);

            }

            if (comboObject.Text != "")

            {

                condition.Dict.Add("FOptObject", comboObject.Text);

            }

            if (txtBoxContent.Text != "")

            {

                condition.Dict.Add("FContent", txtBoxContent.Text);

            }

            DataTable dt = GetByCondition(paging, condition);

            paging1.TotalCount = Convert.ToInt32(dt.TableName);

            gvOperateLogList.DataSource = dt;

            gvOperateLogList.Columns.Clear();

            var dict = GetGvColumnsDict();

            DataGridViewHelp.DisplayColList(gvOperateLogList, dict);

        }

注:MultiCondition、PagingCondition是我專門針對分頁綜合查詢定義的兩個類,興趣的話可以去了解一下:

Extjs+LINQ輕鬆實現高階綜合查詢:

其他:

/// <summary>

        /// gv顯示列設定

        /// </summary>

        /// <returns></returns>

        public Dictionary<string, string> GetGvColumnsDict()

        {

            Dictionary<string, string> dict = new Dictionary<string, string>();

            dict.Add("FTYPE", "操作型別");

            dict.Add("FOPTOBJECT", "操作物件");

            dict.Add("FCONTENT", "操作內容");

            dict.Add("FOperator", "操作人員");

            return dict;

        }

 

DataGridViewHelp.DisplayColList是一個靜態方法,為一個輔助類:

        /// <summary>

        /// 替換列表

        /// </summary>

        /// <param name="dgv">類表名稱</param>

        /// <param name="dic">資料</param>

        /// <param name="isRM">是否顯示序列號</param>

        public static void DisplayColList(DataGridView dgv, Dictionary<string, string> dic)//, bool isRM

        {

            _dgv = dgv;

            dgv.RowsDefaultCellStyle.BackColor = Color.FromArgb(255, 255, 255);//第一行   

            dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(231, 232, 239);//第二行   

            dgv.GridColor = Color.FromArgb(207, 208, 216);//

            dgv.RowTemplate.Height = 25;//列寬

            dgv.AllowUserToAddRows=false;//無空行

            dgv.CellBorderStyle = DataGridViewCellBorderStyle.SingleVertical;

            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            dgv.AllowUserToOrderColumns = true;

            dgv.RowPostPaint += new DataGridViewRowPostPaintEventHandler(dgv_RowPostPaint);

            dgv.CellPainting += new DataGridViewCellPaintingEventHandler(dgv_CellPainting);//列頭樣式

            dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);//選中行樣式

 

            foreach (KeyValuePair<string, string> cl in dic)

            {

                dgv.AutoGenerateColumns = false;

                DataGridViewTextBoxColumn obj = new DataGridViewTextBoxColumn();

                obj.DataPropertyName = cl.Key;

                obj.HeaderText = cl.Value;

                obj.Name = cl.Key;

                obj.Width = 100;

                //obj.DefaultCellStyle.Padding.All = 10;

                obj.Resizable = DataGridViewTriState.True;

                dgv.Columns.AddRange(new DataGridViewColumn[] { obj });

            }

        }

到此實現就全部完成了,執行效果後就是前面所示的效果!也可以動態修改每頁條數。

說在最後,改功能簡單是簡單,但是涉及到很多知識點,委託、事件、

DataGridView資料動態繫結,綜合查詢,我這裡用的是Oracle資料庫,如果用LINQ語法的話查詢資料會比較方便,寫起程式碼也會顯得很優雅。

/// <summary>        /// 獲取條件查詢資料        /// </summary>        /// <param name="paging"></param>        /// <param name="conditon"></param>        /// <returns></returns>        private DataTable GetByCondition(PagingCondition paging, MultiCondition conditon)        {            string strSql = "select * from TOperateLog ";            string strSqlGetCount = "select count(1) from TOperateLog ";            string strWhere = " where 1=1 ";            if (conditon != null)            {                if (conditon.DateSign == "FOperateTime") //操作日期                {                    if (conditon.BeginDate != DateTime.MinValue)                    {                        strWhere += string.Format(" and FOperateTime>='{0}'", conditon.BeginDate.ToString("yyyy-MM-dd HH:mm:ss"));                    }                    if (conditon.EndDate != DateTime.MaxValue)                    {                        strWhere += string.Format(" and FOperateTime<='{0}'", conditon.EndDate.AddDays(1).ToString("yyyy-MM-dd HH:mm:ss"));                    }                }                var dict = conditon.Dict;                if (dict != null)                {                    foreach (var key in dict.Keys)                    {                        if (key.Equals("FType")) //操作型別                        {                            strWhere += string.Format(" and FType='{0}'", dict[key]);                        }                        if (key.Equals("FOperator")) //操作人員                        {                            strWhere += string.Format(" and FOperator='{0}'", dict[key]);                        }                        else if (key.Equals("FOptObject")) //操作物件                        {                            strWhere += string.Format(" and FOptObject='{0}'", dict[key]);                        }                        else if (key.Equals("FContent")) //操作內容                        {                            strWhere += string.Format(" and FContent like '%{0}%'", dict[key]);                        }                    }                }            }            strWhere += " order by FOperateTime ";            strSql += strWhere;            strSqlGetCount += strWhere;            if (paging != null)            {                if (paging.needPaging)                {                    //strSql = string.Format("select * from ( {0} ) where ROWNUM>={1} and ROWNUM<={2}", strSql, paging.startIndex, paging.startIndex + paging.pageSize-1);                    strSql = string.Format("select * from (select T.*,RowNum  RN from ({0})T where ROWNUM <={1}) where RN>={2} ",strSql, paging.startIndex + paging.pageSize - 1,paging.startIndex);                }            }            DataTable dt = DataCon.Query(strSql).Tables[0];            dt.TableName = DataCon.GetSingle(strSqlGetCount)+"";            return dt;        }

來自:http://www.cnblogs.com/markli/p/3863173.html