欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

程序员文章站 2023-09-28 19:06:41
在很多时候,我们做一些非常规化的界面的时候,往往需要创建一些用户控件,在其中绘制好一些基础的界面块,作为后续重复使用的一个单元,用户控件同时也可以封装处理一些简单的逻辑。在开发Winform各种类型项目,我都时不时需要定制一些特殊的用户控件,以方便在界面模块中反复使用。我们一般是在自定义的用户控件里... ......

在很多时候,我们做一些非常规化的界面的时候,往往需要创建一些用户控件,在其中绘制好一些基础的界面块,作为后续重复使用的一个单元,用户控件同时也可以封装处理一些简单的逻辑。在开发winform各种类型项目,我都时不时需要定制一些特殊的用户控件,以方便在界面模块中反复使用。我们一般是在自定义的用户控件里面,添加各种各样的界面控件元素,或者封装一些特殊的函数处理共外部调用等。本篇随笔主要介绍基于devexpress的winform开发经验,介绍一个类似看板信息的用户控件,并在tabellayout和stacklayout布局控件中进行展示。

1、用户控件界面的处理

 在偶尔的一个场合下,看到一个牙医管家的软件界面做的非常不错,其中有一个预约列表的界面感觉非常好,如下界面所示。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

 其中它的每个用户信息列表里面,都是一个综合信息的展示,非常直观,估计应该是用户自定义控件做的。

在其中里面,有不同的字体,各式图标,以及内容的信息展示, 这个我在devexpress的列表控件里面,没有看到可以如此定义列表内容的,在devexpress的gridview里面有一个看板模板的定义有点接近,但是试了一下,可调性不好,于是放弃寻求其他接近方案,玩遍devexpress的控件后,发现最好的方式应该是自定义用户控件的方式来解决这个界面问题。

花了一点时间,制作了一个用户控件,在其中添加一个layoutcontrol方便控制布局,添加一些标签以及设置了一些图标,得到下图所示。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

  左侧的颜色条由于使用group控件,因此宽度暂时无法调整,如果介意大小,我们可以在其中在创建一个layoutcontrol,然后在其中方式内容即可。

我们改变布局,然后添加一个颜色块,得到类似界面如下所示。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

我们来定义一下用户控件的源码部分,修改其中源码,增加对应的属性,方便动态设置用户控件的相关属性,如颜色块,项目背景色,以及绑定的对象信息等内容。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

 然后在界面加载完毕后,设置对应的信息和颜色信息,如下代码所示。

        /// <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);
        }

完成这些后,我们需要在窗体上对内容进行初始化。

最后我们看看界面的效果如下所示

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 或者下面这样的界面布局。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

如果嫌弃边框红色不好看,我们 可以修改边框为灰色调一点的,这样总体看起来效果如下所示。

 在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 得到和我们最终需要的界面很接近了。

一般除了悬浮鼠标颜色变化外,控件单击后,我们会设置不同的背景色,以示区分。

        /// <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);
        }

如下效果所示。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

2、tabellayout和stacklayout布局控件的介绍和使用

 我们在做winform开发的时候,一般知道,微软传统winform的布局提供两个控件,flowlayoutpanel和tablelayoutpanel,一个是流式布局,一个是表格布局,各有各的用处。流式布局主要就是按照顺序挨个放置控件,表格布局主要按照表格的定义的行列单元格,严格放置控件,表格单元格控制强度更大,而且控件具有拉伸效果。

对于devexpress,我们一般还是倾向于采用它提供给的控件来做界面,可以很好融合它的皮肤效果,相对于winform传统两个布局控件,devexpress提供了两个封装效果相当的控件布局stackpanel和 tablepanel,他们的效果实现大同效果,不过调用的接口不同。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

 对于两个控件,我们希望里面的内容自动出现滚动条,那么设置属性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展现出来的效果。

在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

 

 以上就是界面如何在devexpress开发中使用各种用户控件进行用户控件的创建、以及实现鼠标进入、移出、单击的不同效果,以及实现键盘上下箭头按键的事件选中效果,并介绍devexpress中两个布局控件tabelpanel和stackpanel的正常使用,达到展示控件信息的作用。