C#中如何动态加载DockPanel

  • Post author:
  • Post category:其他


因工作需要,在WinForm项目中要求实现动态加载DockPanel。

简单研究了下,演示代码如下:

DockPanel runPanel = dockManager1.AddPanel(DockingStyle.Left);
runPanel.Name = “Dock1”;

DockPanel samePanel = null;
//查找相同位置是否已有停靠插件
foreach (DockPanel hasPanel in dockManager1.Panels)
{
if (hasPanel.Name != "Dock1" && hasPanel.Dock = = DockingStyle.Left)
{
    samePanel = hasPanel;
    break;
}
}

if (samePanel != null)
{
    runPanel.DockAsTab(samePanel);
}

runPanel.show();

很简单几行代码,实现了基本意图。看起来问题很快解决。

但是实际应用中发现几个问题:

1、当第一次运行时,dockManager1.AddPanel后dockManager1.Panels.Count值为1;当DockAsTab后,dockManager1.Panels.Count值为3,系统居然自动增加了一个DockPanel。

2、使用DockAsTab方式,新的DockPanel总是在已有DockPanel右边生成,然后再融合进去,用户体验非常差,尤其是主程序中间有Mdi子程序时,总会有屏幕不停闪烁的效果。

这是怎么回事呢?

通过研究DockPanel的相关文档,终于明白DockPanel的运行机制。

在论述下面的一些观点前,先说明笔者使用的是DX11版本带的DockManager和DockPanel控件。

一个典型的DockPanel如下图。它包括DockPanel主体和容器两个部分。DockPanel中要承载其他控件时,控件容器必须建立。

在DX中,实例化一个DockPanel有三个方法。第一种方法示例如下:

DockPanel runPanel = new DockPanel();

该方法有两点需要注意:

Ø        它不会自动建立控件容器,需要使用者手工添加,代码示例如下:


ControlContainer

_dockPanelContainer =

new

DevExpress.XtraBars.Docking.

ControlContainer

()

_dockPanelContainer.Name=

“dockPanel_Container”

;

runPanel.Controls.Add(_dockPanelContainer);

//添加控件

runPanel.ControlContainer.Add(newControl());

Ø        它需要手工注册到DockManager中去

runPanel.Register(dockManager1);

第二种方法是常用的方法,示例如下:

DockPanel runPanel = dockManager1.AddPanel(DockStyle.Left);

它会自动注册DockPanel到DockManager,同时添加一个ControlContainer。

第三种方法示例如下:

DockPanel runPanel = sameDockPanel.AddPanel();

它由一个已存在的DockPanel创建一个新的DockPanel。

该新DockPanel的ParentPanel不是创建者,而是由系统自己建立的一个PanelContainer,该PanelContainer同时被设置为RootPanel。


停靠模式

DockPanel有两种停靠模式,Split和Tab模式。

Split模式界面示例如下图,两个DockPanel根据实际停靠风格并立在一起。

默认情况下,当我们建立好两个DockPanel,将它们直接show出来,它们呈现的就是如下图的Split模式。

Tab模式如下图,两个DockPanel是以分页样式融合在一起。示例代码如下:

using DevExpress.XtraBars.Docking;
// ... 
//创建一个左停靠控件
DockPanel panel1 = dockManager1.AddPanel(DockingStyle.Left);
panel1.Text = "runDockPanel1";
//由panel1添加一个停靠控件;
//如果直接把panel1和panel2都show出来,我们可以看到它们是Split模式
DockPanel panel2 = panel1.AddPanel();
panel2.Text = " runDockPanel2";
//将二者的共同父容器设置为Tab模式
DockPanel container = panel1.ParentPanel;
container.Tabbed = true;

最后演示效果图如下:


在这里需要明确的是:

当某个位置(如左边)只有一个DockPanel时,该DockPanel的ParentPanel和RootPanel都是自己。当存在两个及以上DockPanel时,所有DockPanel的ParentPanel和RootPanel都是由系统生成的一个公共DockPanelContainer作为父容器,该容器容纳所有同位置的DockPanel。

在关闭同位置的DockPanel时,若只剩下一个DockPanel,则DockPanelContainer会被系统自动释放。

明白了上面的这些原理,对解决上面提出的两个问题就找到了答案。

第一个问题如上所述,当同一位置存在两个或两个以上的DockPanel时,系统自动生成一个容器来容纳。

第二个问题,当在使用DockAsTab前,两个DockPanel是Split模式,之后才变为Tab模式。解决方法就是使用已存在的DockPanel建立新的DockPanel,然后把二者的ParentPanel设置为Tab模式。

另外在这里提一下,DockPanel中默认只能放置UserControl,如果使用Form类型,需要把TopLevel设置下,但是放置在DockPanel中的Form太有个性了。

一个典型的Tab模式DockPanel如上图。

最后,贴出部分实际代码供大家参考:

        /// <summary>
        /// 建立停靠控件t
        /// </summary>
        /// <param name="sCaption">标题</param>
        /// <param name="sName">名称</param>
        /// <param name="ctl">控件实例</param>
        /// <param name="dock">停靠位置?</param>
        /// <param name="dockManager">停靠管理器</param>
        /// <param name="IsNew">是否多次新建窗口</param>
        /// <returns>停靠对象</returns>
        [DisplayName("建立停靠控件")]
        public static DockPanel CreateCtl(string sCaption, string sName, Control ctl, enum_DockLocation dock,
 DockManager dockManager, bool IsNew = false)
        {
            try
            {
                DockManager runDockManager = dockManager;
                DockPanel newDockPanel = null;
                //查找当前列表中是否已有同名的dockpanel
                DockPanel oldPaneled = null;

                runDockManager.BeginUpdate();

                //如果是多次新建窗口,则不查找已有Dock
                if (!IsNew)
                {
                    oldPaneled = GetHaveDockPanel(runDockManager, sName);
                }
             

                if (oldPaneled == null)
                {
                    DockingStyle dockStyle = DockingStyle.Float;
                    switch (dock)
                    {
                        case enum_DockLocation.Left:
                            dockStyle = DockingStyle.Left;
                            break;                          
                        case enum_DockLocation.Buttom:
                            dockStyle = DockingStyle.Bottom;
                            break;
                        case enum_DockLocation.Right:
                            dockStyle = DockingStyle.Right;
                            break;
                        case enum_DockLocation.Center:
                            dockStyle = DockingStyle.Fill;
                            break;
                        default:
                            break;
                    }

                    DockPanel samePaneled = GetSameDockPanel(runDockManager, dockStyle, sName);
                    if (samePaneled != null)
                    {
                        newDockPanel = samePaneled.AddPanel();
                        newDockPanel.Dock = DockingStyle.Fill;
                    }
                    else
                    {
                        newDockPanel = runDockManager.AddPanel(dockStyle);
                    }

                    if (newDockPanel != null)
                    {
                        newDockPanel.ID = new System.Guid();
                        newDockPanel.Name = sName;
                        newDockPanel.Text = sCaption;
                        //newDockPanel.Options.ShowAutoHideButton = false;

                        if (ctl is Form)
                        {
                            Form srcForm = ctl as Form;
                            ctl = ControlLoader.CopyForm2Control(srcForm);
                        }
                        ctl.Dock = DockStyle.Fill;
                        ctl.Visible = true;
                        newDockPanel.Width = ctl.Width;
                        newDockPanel.Height = ctl.Height;
                        newDockPanel.Controls.Add(ctl);

                        //浮动停靠窗体处理
                        if (newDockPanel.Dock.Equals(DockingStyle.Float))
                        {
                            newDockPanel.FloatForm.Size = ctl.Size;
                            newDockPanel.FloatForm.StartPosition = FormStartPosition.CenterScreen;
                            newDockPanel.FloatForm.AutoSizeMode = AutoSizeMode.GrowOnly;
                            newDockPanel.FloatForm.AutoSize = true;
                        }

                        newDockPanel.ClosingPanel += new DockPanelCancelEventHandler(ClosingPanel);
                        newDockPanel.ClosedPanel += new DockPanelEventHandler(ClosedPanel);
                    }
                }
                else
                {
                    newDockPanel = samePaneled;
                }
                //在DockManager中注册当前插件
                newDockPanel.Register(runDockManager);

                if (newDockPanel.ParentPanel != null)
                {
                    newDockPanel.ParentPanel.Tabbed = true;
                }

                newDockPanel.Visibility = DockVisibility.Visible;
                newDockPanel.Visible = true;

                runDockManager.EndUpdate();

                return newDockPanel;
            }
            catch (Exception ex)
            {
                caCom.XLogErr(ex.Message);
                return null;
            }
        }

部分图片截取自DX网站,若有侵权,概不负责。



版权声明:本文为36原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。