首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 打造專業級多頁籤瀏覽器控件:TabControl + WebBrowser 深度整合實戰

     編輯:關於C語言

專案動機:為什麼需要自製多頁籤瀏覽器?

在 WinForms 包裝 B/S 系統時,原生 WebBrowser 控制項缺乏分頁功能,若不處理 Window.Open 或 target="_blank",連結會彈出外部 IE 視窗,破壞應用程式整體性。本文實作一個可複用的多頁籤瀏覽器使用者控制項,核心需求:

  1. 新視窗請求(target="_blank"、window.open、JavaScript 導航)一律在新分頁開啟。
  2. 分頁標題自動同步網頁 <title>,過長自動截斷。
  3. 支援關閉按鈕,最後一個分頁不顯示關閉圖示。
  4. 提供 CreateNewTab(url) 公開方法供外部呼叫。

核心知識點回顧

1. WebBrowser 擴展:攔截 NewWindow 事件

原生 WebBrowser 未暴露 NewWindow2/3 事件,需繼承並覆寫 CreateSink/DetachSink 掛接 DWebBrowserEvents2 COM 介面:

[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
public class ExtendedWebBrowser : WebBrowser
{
    AxHost.ConnectionPointCookie _cookie;
    WebBrowser2EventHelper _helper;

    public event EventHandler<WebBrowserExtendedNavigatingEventArgs> BeforeNewWindow;

    protected override void CreateSink()
    {
        base.CreateSink();
        _helper = new WebBrowser2EventHelper(this);
        _cookie = new AxHost.ConnectionPointCookie(
            ActiveXInstance, _helper, typeof(DWebBrowserEvents2));
    }

    protected override void DetachSink()
    {
        if (_cookie != null) { _cookie.Disconnect(); _cookie = null; }
        base.DetachSink();
    }

    // 內部類別轉發 COM 事件...
}

關鍵事件引數: WebBrowserExtendedNavigatingEventArgs 包含 Url、Cancel 屬性,攔截時設 Cancel = true 並自行導航新分頁。

2. TabControl OwnerDrawFixed:自繪關閉按鈕

設定 DrawMode = OwnerDrawFixed,在 DrawItem 繪製標題與關閉圖示:

private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    var tabRect = tabControl1.GetTabRect(e.Index);
    var g = e.Graphics;

    // 1. 繪製標題文字
    g.DrawString(tabControl1.TabPages[e.Index].Text, Font, SystemBrushes.ControlText, tabRect.X + 3, tabRect.Y + 3);

    // 2. 僅多於 1 個分頁時繪製關閉按鈕
    if (tabControl1.TabCount > 1)
    {
        const int CloseSize = 14;
        var closeRect = new Rectangle(tabRect.Right - CloseSize - 4, tabRect.Y + 2, CloseSize, CloseSize);
        var img = (e.State & DrawItemState.Selected) == DrawItemState.Selected
            ? imageList1.Images["closeSelected"] : imageList1.Images["close"];
        g.DrawImage(img, closeRect);
        // 將 closeRect 存入 Tag 供 MouseDown 判斷
        tabControl1.TabPages[e.Index].Tag = closeRect;
    }
}

完整控制項實作邏輯

1. 建立新分頁 CreateNewTabPage(string url)

private readonly List<ExtendedWebBrowser> _browsers = new List<ExtendedWebBrowser>();

public void CreateNewTabPage(string url)
{
    var web = new ExtendedWebBrowser
    {
        Name = $"WebBrowser{_browsers.Count}",
        Dock = DockStyle.Fill,
        Margin = Padding.Empty
    };
    web.DocumentCompleted += Web_DocumentCompleted;
    web.BeforeNewWindow += Web_BeforeNewWindow;
    web.Navigate(url);
    _browsers.Add(web);

    var tabPage = new TabPage("載入中...")
    {
        Name = $"TabPage{tabControl1.TabCount}",
        Padding = new Padding(0, 3, 0, 0),
        ImageIndex = 0
    };
    tabPage.Controls.Add(web);
    tabControl1.TabPages.Add(tabPage);
    tabControl1.SelectedTab = tabPage;
}

2. 網頁載入完成:更新分頁標題與表單標題

private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var web = (ExtendedWebBrowser)sender;
    string title = web.Document.Title.Trim();
    if (title.Length > 8) title = title.Substring(0, 8) + "...";

    var tabPage = (TabPage)web.Parent;
    tabPage.Text = title;

    if (tabControl1.SelectedTab == tabPage)
        this.Text = web.Document.Title; // 同步表單標題
}

3. 攔截新視窗請求:在新分頁開啟

private void Web_BeforeNewWindow(object sender, WebBrowserExtendedNavigatingEventArgs e)
{
    CreateNewTabPage(e.Url);
    e.Cancel = true; // 取消預設彈出視窗行為
}

4. 滑鼠點擊關閉按鈕:關閉分頁並釋放資源

private void tabControl1_MouseDown(object sender, MouseEventArgs e)
{
    for (int i = 0; i < tabControl1.TabCount; i++)
    {
        if (tabControl1.TabPages[i].Tag is Rectangle closeRect && closeRect.Contains(e.Location))
        {
            var web = _browsers[i];
            web.DocumentCompleted -= Web_DocumentCompleted;
            web.BeforeNewWindow -= Web_BeforeNewWindow;
            web.Dispose();
            _browsers.RemoveAt(i);

            tabControl1.TabPages.RemoveAt(i);
            break;
        }
    }
}

進階擴充建議

  • 右鍵選單: 加入「關閉其他」、「關閉右側」、「複製網址」、「重新整理」等指令。
  • 網址列同步: 監聽 Navigating 事件,將當前分頁 URL 顯示在工具列文字方塊。
  • 下載管理: 處理 FileDownload 事件,整合自訂下載對話框。
  • Edge WebView2 遷移: 新專案建議改用 Microsoft.Web.WebView2,支援現代網標、Chromium 內核、更佳效能與安全性。

結語

透過 ExtendedWebBrowser 攔截 COM 事件 與 TabControl OwnerDrawFixed 自繪 的結合,我們實現了功能完整、體驗流暢的多頁籤瀏覽器控制項。此架構清晰分離「瀏覽器核心」與「分頁管理 UI」,易於維護與擴充,可直接嵌入任何 WinForms 專案作為內嵌瀏覽器外殼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved