1. 程式人生 > >在Winform介面使用自定義使用者控制元件及TabelPanel和StackPanel佈局控制元件

在Winform介面使用自定義使用者控制元件及TabelPanel和StackPanel佈局控制元件

在很多時候,我們做一些非常規化的介面的時候,往往需要建立一些使用者控制元件,在其中繪製好一些基礎的介面塊,作為後續重複使用的一個單元,使用者控制元件同時也可以封裝處理一些簡單的邏輯。在開發Winform各種型別專案,我都時不時需要定製一些特殊的使用者控制元件,以方便在介面模組中反覆使用。我們一般是在自定義的使用者控制元件裡面,新增各種各樣的介面控制元件元素,或者封裝一些特殊的函式處理共外部呼叫等。本篇隨筆主要介紹基於DevExpress的Winform開發經驗,介紹一個類似看板資訊的使用者控制元件,並在TabelLayout和StackLayout佈局控制元件中進行展示。

1、使用者控制元件介面的處理

 在偶爾的一個場合下,看到一個牙醫管家的軟體介面做的非常不錯,其中有一個預約列表的介面感覺非常好,如下介面所示。

 

 其中它的每個使用者資訊列表裡面,都是一個綜合資訊的展示,非常直觀,估計應該是使用者自定義控制元件做的。

在其中裡面,有不同的字型,各式圖示,以及內容的資訊展示, 這個我在DevExpress的列表控制元件裡面,沒有看到可以如此定義列表內容的,在DevExpress的GridView裡面有一個看板模板的定義有點接近,但是試了一下,可調性不好,於是放棄尋求其他接近方案,玩遍DevExpress的控制元件後,發現最好的方式應該是自定義使用者控制元件的方式來解決這個介面問題。

花了一點時間,製作了一個使用者控制元件,在其中新增一個LayoutControl方便控制佈局,新增一些標籤以及設定了一些圖示,得到下圖所示。

 

  左側的顏色條由於使用Group控制元件,因此寬度暫時無法調整,如果介意大小,我們可以在其中在建立一個LayoutControl,然後在其中方式內容即可。

我們改變佈局,然後新增一個顏色塊,得到類似介面如下所示。

 

我們來定義一下使用者控制元件的原始碼部分,修改其中原始碼,增加對應的屬性,方便動態設定使用者控制元件的相關屬性,如顏色塊,專案背景色,以及繫結的物件資訊等內容。

 

 然後在介面載入完畢後,設定對應的資訊和顏色資訊,如下程式碼所示。

        /// <summary>
        /// 視窗載入事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserItemControl_Load(object sender, EventArgs e)
        {
            BindData();
            RefreshColor();
        }

        /// <summary>
        /// 根據使用者定義資訊,顯示不同的內容
        /// </summary>
        private void BindData()
        {
            if(this.UserItemInfo != null)
            {
                var info = this.UserItemInfo;
                this.lblCustomerName.Text = info.CustomerName;
                this.lblMobile.Text = info.Mobile;
                this.lblReceiver.Text = info.Receiver;
                this.lblRecordDate.Text = info.RecordDate;
                this.lblRecordNo.Text = info.RecordNo;
                this.lblDealType.Text = "";
                this.lblStar.ImageOptions.ImageIndex = GetStarImageIndex(info.Stars);
                if (!info.IsVip)
                {
                    this.lblVip.Visibility = LayoutVisibility.Never;
                }
            }
        }

        /// <summary>
        /// 重新整理背景色
        /// </summary>
        private void RefreshColor()
        {
            if (ItemBlockColor != Color.Empty)
            {
                this.itemColor.AppearanceItemCaption.BackColor = ItemBlockColor;
            }
            if (ItemBackColor != Color.Empty)
            {
                layoutControl1.BackColor = ItemBackColor;
            }
        }

但我們滑鼠浮動在專案上或者離開的時候,或者單擊某項的時候,我們變換下顏色,方便區分顯示。

        private void layoutControl1_MouseLeave(object sender, EventArgs e)
        {
            if (!this.IsSelected)
            {
                this.layoutControl1.ResetBackColor();
            }
        }

        private void layoutControl1_MouseEnter(object sender, EventArgs e)
        {
            if (!this.IsSelected)
                this.layoutControl1.BackColor = Color.FromArgb(192, 255, 192);
        }

        private void layoutControl1_Click(object sender, EventArgs e)
        {
            this.IsSelected = true;
            OnItemClick?.Invoke(this, e);
        }

完成這些後,我們需要在窗體上對內容進行初始化。

最後我們看看介面的效果如下所示

 或者下面這樣的介面佈局。

如果嫌棄邊框紅色不好看,我們 可以修改邊框為灰色調一點的,這樣總體看起來效果如下所示。

 

 得到和我們最終需要的介面很接近了。

一般除了懸浮滑鼠顏色變化外,控制元件單擊後,我們會設定不同的背景色,以示區分。

        /// <summary>
        /// 是否選中節點
        /// </summary>
        public bool IsSelected
        {
            get
            {
                return m_IsSelected;
            }
            set
            {
                m_IsSelected = value;

                this.ItemBackColor = value ? Color.FromArgb(255, 255, 192) : Color.Transparent;
                this.RefreshColor();
            }
        }

一般列表介面中,我們除了支援滑鼠移動、單擊變色的效果外,我們還希望支援通過鍵盤箭頭上下鍵進行上下瀏覽專案。我們如果需要使用鍵盤的按鍵,需要設定窗體的KeyPreview屬性為True,

然後跟蹤按鍵的事件即可,如下所示。

            this.KeyPreview = true;
            this.KeyUp += FrmKanBan_KeyUp;

按鍵事件捕捉處理如下所示,主要就是判斷選中的使用者控制元件,並對面板的子控制元件的選中效果進行處理。

        private void FrmKanBan_KeyUp(object sender, KeyEventArgs e)
        {
            //單擊滑鼠或者切換按鍵,會觸發使用者控制元件獲得selectItem物件,可以進行箭頭上下移動
            if (selectItem != null)
            {
                var panel = selectItem.Parent;
                if (panel != null)
                {
                    //獲取操作項的索引值
                    int oldIndex = panel.Controls.IndexOf(selectItem);
                    if (e.KeyCode == Keys.Up)
                    {
                        if (oldIndex > 0)
                        {
                            //通過序號獲得新的控制元件,並單擊它觸發選擇事件
                            var newCtrl = panel.Controls[oldIndex - 1];
                            Item_OnItemClick(newCtrl, new EventArgs());
                        }
                    }
                    else if (e.KeyCode == Keys.Down)
                    {
                        if (oldIndex < (panel.Controls.Count - 1))
                        {
                            //通過序號獲得新的控制元件,並單擊它觸發選擇事件
                            var newCtrl = panel.Controls[oldIndex + 1];
                            Item_OnItemClick(newCtrl, new EventArgs());
                        }
                    }
                }
            }
        }

介面中使用者控制元件的切換選中效果,需要先清空之前所有的選擇,然後在設定新的選中控制元件,所以還需要對控制元件觸發單擊事件進行處理,如下所示。

        /// <summary>
        /// 選中的使用者控制元件物件例項
        /// </summary>
        UserItemControl selectItem = null;
        /// <summary>
        /// 單擊使用者控制元件,觸發清除所有標記後,再次設定選中的專案標記
        /// </summary>
        private void Item_OnItemClick(object sender, EventArgs e)
        {
            //清空所有控制元件的選中標記
            var panel = (PanelControl)((Control)sender).Parent;
            foreach (Control ctrl in panel.Controls)
            {
                var item = ctrl as UserItemControl;
                if(item != null)
                {
                    item.IsSelected = false;
                }
            }

            //設定選中控制元件
            selectItem = ((UserItemControl)sender);
            selectItem.IsSelected = true;
            this.Text = selectItem.UserItemInfo.CustomerName + "-選中";

            //如果在面板中遮擋,移動滾動條,可以檢視到完整使用者控制元件介面
            panel.ScrollControlIntoView(selectItem);
        }

如下效果所示。

 

2、TabelLayout和StackLayout佈局控制元件的介紹和使用

 我們在做Winform開發的時候,一般知道,微軟傳統Winform的佈局提供兩個控制元件,FlowLayoutPanel和TableLayoutPanel,一個是流式佈局,一個是表格佈局,各有各的用處。流式佈局主要就是按照順序挨個放置控制元件,表格佈局主要按照表格的定義的行列單元格,嚴格放置控制元件,表格單元格控制強度更大,而且控制元件具有拉伸效果。

對於DevExpress,我們一般還是傾向於採用它提供給的控制元件來做介面,可以很好融合它的面板效果,相對於Winform傳統兩個佈局控制元件,DevExpress提供了兩個封裝效果相當的控制元件佈局StackPanel和 TablePanel,他們的效果實現大同效果,不過呼叫的介面不同。

 

 對於兩個控制元件,我們希望裡面的內容自動出現滾動條,那麼設定屬性AutoScroll 為True即可,如下程式碼所示。

panel.AutoScroll = true;

而StackPanel另外需要LayoutDirection,也就是控制元件順序展現的方式,如下程式碼所示。

panel.LayoutDirection = StackPanelLayoutDirection.TopDown;

使用StackPanel面板來測試展示使用者控制元件列表的介面程式碼如下所示。

        /// <summary>
        /// 使用StackPanel對使用者控制元件佈局進行處理
        /// </summary>
        private void InitPanel(StackPanel panel)
        {
            panel.AutoScroll = true;//面板自動出現滾動條
            panel.LayoutDirection = StackPanelLayoutDirection.TopDown;//從上往下展示
            panel.Controls.Clear();//清空介面

            var list = GetInfoList(); //獲取使用者控制元件繫結的物件資訊列表
            for (int i = 0; i < list.Count; i++)
            {
                //定義使用者控制元件例項
                var item = new UserItemControl();
                item.UserItemInfo = list[i];//繫結物件資訊

                item.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                item.ItemBlockColor = colors[i %10]; //變化顏色
                item.OnItemClick += Item_OnItemClick;//觸發選中事件

                panel.Controls.Add(item);
            }
        }

對於表格佈局TablePanel控制元件來說,使用初始化控制元件的方式也差不多,不過有個別地方注意即可。

        /// <summary>
        /// 使用TablePanel對使用者控制元件佈局進行處理
        /// </summary>
        private void InitPanel(TablePanel panel)
        {
            panel.AutoScroll = true;//面板自動出現滾動條
            panel.Controls.Clear();//清空介面
            panel.Rows.Clear();//清空行
            panel.Columns.Clear();//清空列

            //新增列定義(增加一個列即可)
            panel.Columns.Add(new TablePanelColumn(TablePanelEntityStyle.Relative, 55F));
            var list = GetInfoList(); //獲取使用者控制元件繫結的物件資訊列表
            for (int i = 0; i < list.Count; i++)
            {
                //定義行資訊
                panel.Rows.Add(new TablePanelRow(TablePanelEntityStyle.AutoSize, 100F));

                //定義使用者控制元件例項
                var item = new UserItemControl();
                item.UserItemInfo = list[i];
                //定義拉伸效果
                item.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                item.ItemBlockColor = colors[i % 10]; //變化顏色
                item.OnItemClick += Item_OnItemClick;//觸發選中事件

                //先新增控制元件到面板集合中
                panel.Controls.Add(item);
                //設定控制元件的單元格位置
                panel.SetCell(item, i, 0);
            }

            //新增多一行,確保佈局
            panel.Rows.Add(new TablePanelRow(TablePanelEntityStyle.AutoSize, 100F));
        }

新增控制元件的時候,需要注意下面的程式碼,才能正常展示控制元件資訊,否則無法看到使用者控制元件。

                //先新增控制元件到面板集合中
                panel.Controls.Add(item);
                //設定控制元件的單元格位置
                panel.SetCell(item, i, 0);

最後對比下效果,左邊是TablePanel,右邊是StackPanel展現出來的效果。

 

 以上就是介面如何在DevExpress開發中使用各種使用者控制元件進行使用者控制元件的建立、以及實現滑鼠進入、移出、單擊的不同效果,以及實現鍵盤上下箭頭按鍵的事件選中效果,並介紹DevExpress中兩個佈局控制元件TabelPanel和StackPanel的正常使用,達到展示控制元件資訊的作用。