经常我们需要在一个控件的工作区上动态添加新的控件,例如在panel控件上动态添加我们自定义的UserControl,并且希望按照我们所希望的顺序显示。
- 比较简单的方法:用Dock = DockStyle.Top布局
panel.Controls.Add(new CustomUserControl(){ Dock = DockStyle.Top });
用Dock = DockStyle.Top实现动态添加的好处就是,当panel工作区大小改变时(如控件的滚动条、边框、标题栏和菜单大小变动引起工作区大小改变,这里当panel里的控件数多到屏幕显示不下时就会出现滚动条,相应的工作区大小就变小了),里面的控件会自动做相应的比例的增减。
但是,有一个缺点是,因为用的是DockStyle.Top属性值,后面添加的控件会显示在前面,就是倒序显示。当然,你可能会想,那我将要显示的控件都放到一个List里面,然后倒着添加,它不就按正常顺序显示了。可是,如果你添加控件是不是批量的,也就是可能这会加一个过会再加一个呢?或者你又想,我用DockStyle.Bottom属性值。是的,用DockStyle.Bottom后它的确按你要的顺序显示了,但是,你会发现,当你添加的控件不足以填充满panel的整个工作区时,上面就露出一大块未填充的区域,难看极了。
可是,还有什么办法吗?既要能够按序显示控件,又要能够不定时地添加。
- 自己绘制
我想不出好的办法了,所以我用了比较笨的办法(大牛如果有更好的办法,多多指教),就是自己绘制。
自己绘制,用panel.Controls.Add(new CustomUserControl())不指定布局方式,就会发现显示的永远是最后一个添加的控件,因为这样添加的控件,都是默认新加的控件的Location值是(0,0)。
所以,添加时要指定新控件的位置,Location = new Point(0, count * CustomUserControl.Height)。count是上层控件已有的控件数,这里认为要添加的都是同一类自定义的控件,所以简单用count * CustomUserControl.Height计算。
好了,新加的控件是显示了,但是你会发现新加的控件的宽度没有填充满上层控件的整个工作区,并且不会随上层控件大小的变化而成比例变化。
这里,我是这样实现的,我指定新加的控件的宽度等于上层控件的宽度,即CustomUserControl.Width = panel.Size.Width; 但是,之后,我发现当新加的控件数多到屏幕显示不下时,以后新加的控件有些部分被panel的滚动条覆盖了。这是因为我指定自定义的控件的宽度为panel的宽度,其实应该指定为panel的工作区的宽度。控件都有自己的工作区,控件的工作区是控件的边界减去非工作区元素(如滚动条、边框、标题栏和菜单)。改成CustomUserControl.Width = panel.ClientSize.Width;问题解决。
之后,问题又出现了,当上层控件工作区大小变化时(例如,加了Splitter),新加的控件没有随它的变化而成比例变化。所以,我又想到了Anchor属性,于是,我试了一下:CustomUserControl.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right; 问题解决。
整个示例代码:
int count = panel.Controls.Count;
UserControl c = new CustomUserControl(){ Width = panel.ClientSize.Width, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right };
c.Location = new Point(0, count * c.Height);