灰太狼

先有司,赦小过,举贤才

 

山寨版Windows.Forms用户控件

园子里的大虾们总是讨论System.Web的控件,大多数以Web的用户自定义控件为主,却很少有人写些关于Windows.Forms的用户控件或者自定义控件,原因大概是都开发web的,相比之下Windows.Forms的自定义控件的界面难绘制。诶,想起去年为了实现一个Winform程序,自己琢磨用户控件在院子里连点资料都找不到。。。
首先声明,我封装的是Windows.Forms的用户控件,不是自定义控件。至于为什么写用户控件而不是自定义控件,我相信大家都知道用户控件只要继承UserControl即可,拖拽几个Win自带的控件进来写几句即可。我写用户控件的目的是为了提高开发效率,同时为了美观统一,所以界面效果自然是没有控件商的产品漂亮。
当然,最后是有源代码下载,先上几张图图。


图1 标题文本框


图2 弹出窗口


图3 分页表格

 

图4 下拉树

 

怎么开发用户控件很简单,不做介绍,写这篇文章是想向大家介绍一下思想。
通常我们写应用程序的时候,都会出现那种信息录入界面,就像是“标题然后后面紧接着加一个文本框”(见图1),像大众设计的话,肯定是拖拽两个控件进来,一个是Label,一个是TextBox,然后布局一下。其实很多时候我们只用到了简单的一个文本框内容的读取以及一个文本标题的显示,所以很多情况下我们就可以把这两个合并成一个带标题的文本框用户控件,这样就能节省更多的开发时间了。当然还有其他更多的好处就不在这里作过多介绍,读者请看代码自去体会。

以上只是一个非常简单的场合,介绍一个比较复杂点的场合吧。写应用程序的同志们肯定会遇到那种需要弹出窗口进行选择某条记录然后返回到主窗口来进行继续操作的时候(见图2),若像普通设计的话,我们每个这种场合都需要设计同样的工作,所以为了节省工作量,我把这个封装了,为了能让弹出窗口和主窗口进行通讯,我定义了接口并且定义了参数。当然这样是有点局限性,但是能解决很大部分情况。可能大家会问,不会那么简单吧,实际上是不简单,但是只要按照约定进行开发就容易了。
被弹出窗口需要继承的接口(用来触发选择动作以及传递参数使用,PS:实际改成委托更好点,好像其他控件有这么做)
    public interface ISelectButtons
    {
        DialogValue MyDialogValue { get; set; }
        void SetSelect();
    }
弹出主窗口需要将控件MyTextBoxButtonSelect拖拽进来,并设置相关参数,注意一下重要参数:
string DialogAssemblyName,被弹出窗口的命名空间。(为反射作准备)
string DialogAddForm,若新建,被弹出的窗口类名。(为了统一弹出窗口的界面风格,故定义了MyForm用户控件,其他所有与内容相关的都定义成了功能性用户控件)
string DialogAddUserControl,若新建,被弹出的用户控件类名。
同样还有选择的弹出窗口,叫做DialogSelectForm和DialogSelectUserControl。
在这里把控件的部分源代码贴出,下面是点击新建按钮的动作:
        private void buttonAdd_Click(object sender, EventArgs e)
        {
            base.OnClick(e);
            try
            {
                if (String.IsNullOrEmpty(DialogAddForm) && String.IsNullOrEmpty(DialogAddUserControl))
                    return;
                Form f = GetForm(DialogAddForm);
                UserControl u = GetUserControl(DialogAddUserControl);
                MyDialogValue = new DialogValue();
                ((ISelectButtons)u).MyDialogValue = MyDialogValue;
                ((ISelectButtons)u).MyDialogValue.FromValue = GetMyTextBox();
                ((ISelectButtons)u).MyDialogValue.ReturnValue = MyValue;
                f.AutoSize = true;
                f.Controls.Add(u);
                if (u.Tag != null)
                    f.Text = " " + u.Tag.ToString();
                f.ShowDialog();
                if (!String.IsNullOrEmpty(MyDialogValue.ReturnText) && !String.IsNullOrEmpty(MyDialogValue.ReturnValue))
                    SetSelectValue();
            }
            catch (Exception ex)
            {
                ex.Source += String.Format("    DialogAddUserControl:{0}", DialogAddUserControl);
                ExceptionHelper.Exception(ex);
            }
        }

不要以为到了这里我的山寨版用户控件就没了,其实不然,还有很多很多东西,拿出来分享给大家,希望能让大家看懂,看不懂的就不能理解我的一番苦心,诶,能理解我的人太少了,曾经很长一段时间号称孤狼,最近才把真名换出来。好了不多说了,这里介绍一下大家常用的DataGridView列表展示情景(见图3),我封装了一个即能分页又能导出Excel的控件,而且里面的功能跟业务毫无关系,当然要用它也要按照约定来进行开发,即它的容器(窗口)需要实现接口IPagination。
接口代码很简单:
    public interface IPagination
    {
        void BindData();
        //void SelectRow(); //(PS:此处为什么注释,不记得了。反正去年写的时候是想实现行选择动作来触发什么事件的,今年没事才拿出来给大家分享。)
    }
MyDataGridView有几个参数需要重视:
int PageSize
int CurrentPageIndex
int RowsTotalCount
Object DataSource
贴出一下MyDataGridView用户控件的部分代码:
        public int GetPageCount()
        {
            if ((RowsTotalCount == 0) || (PageSize == 0))
                return 0;
            int i = RowsTotalCount / PageSize;
            if (RowsTotalCount % PageSize > 0)
                i++;
            return i;
        }

        private IPagination FindControlIPagination()
        {
            Control c = this.Parent;
            while (c != null)
            {
                if (c is IPagination)
                    break;
                c = c.Parent;
            }
            if (!(c is IPagination))
                throw new Exception("No IPagination Control in this UserControl or Form.");
            return c as IPagination;
        }

        public void DataBind()
        {
            dataGridViewDefault.DataSource = DataSource;
            toolStripLabelRowsTotalCount.Text = String.Format("共计:{0}条 {1}条/页", RowsTotalCount, PageSize);
            toolStripLabelCurrentPage.Text = String.Format("{0}/{1}", CurrentPageIndex, GetPageCount());
            SetEnabled();
        }

        private void ReDataBind()
        {
            IPagination page = FindControlIPagination();
            page.BindData();
        }

恩恩,写到这里本打算就此收笔了,但是突然看到了一个曾经折腾了好久才搞出来的一个控件DropDownTreeView,这个控件是实现了下拉树选择功能(见图4),与其他用户控件比,比较特殊点就是他不是继承自UserControl,而是来自于ComboBox,然而其实ComboBox是间接继承自Control,所以DropDownTreeView可以定义自己的TreeView控件来进行展示与承载数据,唯一需要处理的就是找到Windows句柄获取点击ComboBox的动作来进行展收树,看部分代码:
        private void ShowDropDown()
        {
            if (dropDown != null)
            {
                treeViewHost.Size = new Size(DropDownWidth - 2, DropDownHeight);
                dropDown.Show(this, 0, this.Height);
            }
        }

        protected override void WndProc(ref Message m)
        {
            try
            {
                if (m.Msg == WM_LBUTTONDBLCLK || m.Msg == WM_LBUTTONDOWN)
                {
                    ShowDropDown();
                    return;
                }
                base.WndProc(ref m);
            }
            catch (Exception ex)
            {
                CHF.Windows.Command.ExceptionHelper.Exception(ex);
            }
        }

算了,算了,再看就写不完了,贴出一下我的类库里有多少个用户控件,很多都是见了名字就能知道什么意思的。

 

 

最后贴出原代码:下载山寨版Windows.Form用户控件CHF.Windows.FormControl


至于调用的Demo,我就不便把我整个项目代码都给出来,毕竟它已经在市面上还活着呢http://soft.bxren.cn
(给了几个调用的Demo文件,但是会报错,因为我没有给出完整的Demo部分,我相信大虾们能通过源码看出效果来)

由于是早期做程序用的,也没有特意去进行重构和包装,但是很实用。这次拿出来也是临时应付,也没有作很好的介绍和修剪代码,不会用就问,本人脸皮厚,好不好用我也不害臊,反正砖头砸我头不会疼~ 不信试试。。。。

posted on 2009-07-07 21:37  灰太狼2号  阅读(3043)  评论(22编辑  收藏  举报

导航