在显示新选项卡之前,WinForm TabControl 选项卡页面内容不会更新

WinForm TabControl tab page contents does not update until the new tab is shown

我有一个允许创建新选项卡的选项卡控件。每个新选项卡上都有一个 Web 浏览器控件 CEFSharp。创建新选项卡时,不会显示先前打开的选项卡;这就是我们想要的。

但是新建标签页上的浏览器只是添加到标签页中,并且只是部分运行...直到显示标签页后才进入loading状态

这里是 Tabpage 创建代码:

private void AddNewBrowser()
        {
            Log("Adding New Tab and Browser");

            UiBrowser browser = new UiBrowser();

            TabPage tp = new TabPage();

            tp.Controls.Add(browser);
            customTabControl1.TabPages.Add(tp);
        }

UiBrowser 是一个 UserControl,它包含 CEFSharp 浏览器控件以及一些额外的 UI。

这里是浏览器本身的启动代码。

private void UiBrowser_Load(object sender, EventArgs e)
        {
            Execute();
        }

private void Execute()
        {
            webBrowser = new ChromiumWebBrowser("http://google.co.uk")
            {
                Dock = DockStyle.Fill,
                Text = "Loading...",
                Tag = Tag
            };

            webBrowser.TitleChanged += Browser_TitleChanged;
            webBrowser.AddressChanged += Browser_AddressChanged;
            webBrowser.ConsoleMessage += Browser_ConsoleMessage;
            webBrowser.LoadingStateChanged += Browser_LoadingStateChanged;
            webBrowser.StatusMessage += Browser_StatusMessage;

            browserPanel.Controls.Add(webBrowser);
            Application.DoEvents();
        }

为了清晰起见,代码已经过简化,我还没有在 SO 或其他地方找到解决这个问题的方法。

问题: 如何让浏览器控件在保留在后台的同时加载网页?也就是说,当控件打开时 TabPage 不会向用户显示。

Load event只会在控件第一次可见时发生:

Occurs before the control becomes visible for the first time.

因此请尝试将您的 Execute 方法移动到 UserControl 的构造函数代码中。

没有 "official" 方法可以做到这一点。

但是如果你真的需要它并且不怕使用内部结构,你可以看看我对的回答。

解决方案(或 hack)封装在这个小帮手中

public static class ControlUtils
{
    static readonly Action<Control, bool> CreateControlFunc = (Action<Control, bool>)Delegate.CreateDelegate(typeof(Action<Control, bool>),
        typeof(Control).GetMethod("CreateControl", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(bool) }, null));

    public static void CreateControls(this Control target)
    {
        if (!target.Created)
            CreateControlFunc(target, true);
        else
            for (int i = 0; i < target.Controls.Count; i++)
                target.Controls[i].CreateControls();
    }
}

在表单加载事件结束时,添加以下内容

this.CreateControls();

customTabControl1.CreateControls();

还有这里

private void AddNewBrowser()
{
    Log("Adding New Tab and Browser");

    UiBrowser browser = new UiBrowser();

    TabPage tp = new TabPage();

    tp.Controls.Add(browser);
    customTabControl1.TabPages.Add(tp);

    if (customTabControl1.Created)
        tp.CreateControls();
}