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

基於 VS2005 WebBrowser 控件構建標籤頁瀏覽器完整實戰

     編輯:關於C#

專案背景與核心難點

早期 VS2003 開發瀏覽器最大痛點:**彈出窗口 (window.open) 無法攔截**,導致新窗口仍由系統默認瀏覽器打開。VS2005 引入 WebBrowser.NewWindow 事件,使得**在標籤頁中捕獲並打開彈出鏈接**成為可能,這是本專案的核心技術突破。

功能清單

  • 標籤頁多頁瀏覽(動態增減 TabPage)
  • 彈出窗口自動在新標籤頁打開 (NewWindow 事件)
  • 導航工具欄:後退/前進/刷新/停止/首頁/搜索/地址欄
  • 菜單功能:另存為/打印/打印預覽/頁面設置/屬性/退出
  • 狀態欄:進度條/狀態文本/安全區域圖標
  • 標籤頁雙擊關閉、切換同步地址欄與按鈕狀態

界面佈局 (WinForms 設計器)

  • MenuStrip:頂層菜單
  • 兩個 ToolStrip:工具欄 + 地址欄 (含 ToolStripComboBox)
  • TabControl:瀏覽器主體,每個 TabPage 承載一個 WebBrowser
  • StatusStrip:底部狀態欄 (含 ToolStripProgressBar/ToolStripStatusLabel)
  • 所有控件設置 Dock 屬性適應窗體縮放

核心輔助方法

獲取當前活動 WebBrowser

private WebBrowser GetCurrentBrowser() {
    return (WebBrowser)tabControl1.SelectedTab.Controls[0];
}

URL 規範化處理

private Uri GetUrl(string address) {
    string temp = address.Trim();
    if (!temp.StartsWith("https://") && !temp.StartsWith("https://") && !temp.StartsWith("ftp://"))
        temp = "https://" + temp;
    return Uri.TryCreate(temp, UriKind.Absolute, out var uri) ? uri : new Uri("about:blank");
}

創建新標籤頁 (空白/指定 URL)

private void NewPage(string url = "about:blank") {
    var page = new TabPage("新標籤頁");
    var browser = CreateBrowser();
    browser.Url = GetUrl(url);
    page.Controls.Add(browser);
    tabControl1.TabPages.Add(page);
    tabControl1.SelectedTab = page;
}

private WebBrowser CreateBrowser() {
    var wb = new WebBrowser { Dock = DockStyle.Fill };
    wb.Navigated += Browser_Navigated;
    wb.NewWindow += Browser_NewWindow;
    wb.ProgressChanged += Browser_ProgressChanged;
    wb.StatusTextChanged += Browser_StatusTextChanged;
    return wb;
}

關鍵事件處理

1. NewWindow 事件 —— 核心突破

private void Browser_NewWindow(object sender, CancelEventArgs e) {
    var sourceBrowser = (WebBrowser)sender;
    var newUrl = sourceBrowser.StatusText; // 獲取目標 URL
    
    // 阻止默認彈出行為
    e.Cancel = true;
    
    // 在新標籤頁打開
    var newPage = new TabPage("載入中...");
    var newBrowser = CreateBrowser();
    newBrowser.Navigate(newUrl);
    newPage.Controls.Add(newBrowser);
    tabControl1.TabPages.Add(newPage);
    tabControl1.SelectedTab = newPage;
}
關鍵點:e.Cancel = true 禁止默認彈出;StatusText 在此事件中包含目標 URL;新 WebBrowser 必須重新掛載所有事件。

2. Navigated 事件 —— 同步 UI 狀態

private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) {
    var browser = (WebBrowser)sender;
    var page = (TabPage)browser.Parent;
    
    // 僅更新當前選中標籤的地址欄
    if (browser == GetCurrentBrowser())
        tscbUrl.Text = browser.Url?.ToString() ?? "about:blank";
    
    // 更新標籤標題 (截取前 20 字符)
    page.Text = TruncateTitle(browser.DocumentTitle);
}

3. ProgressChanged / StatusTextChanged

private void Browser_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e) {
    if (e.MaximumProgress > 0) {
        toolStripProgressBar1.Maximum = (int)e.MaximumProgress;
        toolStripProgressBar1.Value = (int)Math.Min(e.CurrentProgress, e.MaximumProgress);
    }
}

private void Browser_StatusTextChanged(object sender, EventArgs e) {
    var browser = (WebBrowser)sender;
    if (browser == GetCurrentBrowser())
        toolStripStatusLabel1.Text = browser.StatusText;
}

工具欄與菜單命令 (均委託當前 WebBrowser)


// 導航
backButton.Click += (s,e) => { GetCurrentBrowser().GoBack(); UpdateNavButtons(); };
forwardButton.Click += (s,e) => { GetCurrentBrowser().GoForward(); UpdateNavButtons(); };
refreshButton.Click += (s,e) => GetCurrentBrowser().Refresh();
stopButton.Click += (s,e) => GetCurrentBrowser().Stop();
homeButton.Click += (s,e) => GetCurrentBrowser().GoHome();
searchButton.Click += (s,e) => GetCurrentBrowser().GoSearch();

// 地址欄回車/Go 按鈕
gotoButton.Click += (s,e) => GetCurrentBrowser().Navigate(GetUrl(tscbUrl.Text));
tscbUrl.KeyDown += (s,e) => { if (e.KeyCode == Keys.Enter) GetCurrentBrowser().Navigate(GetUrl(tscbUrl.Text)); };

// 菜單功能 (WebBrowser 內置對話框)
saveasToolStripMenuItem.Click += (s,e) => GetCurrentBrowser().ShowSaveAsDialog();
printToolStripMenuItem.Click += (s,e) => GetCurrentBrowser().ShowPrintDialog();
printPreToolStripMenuItem.Click += (s,e) => GetCurrentBrowser().ShowPrintPreviewDialog();
pageSetupToolStripMenuItem.Click += (s,e) => GetCurrentBrowser().ShowPageSetupDialog();
propeToolStripMenuItem.Click += (s,e) => GetCurrentBrowser().ShowPropertiesDialog();

// 更新後退/前進按鈕啟用狀態
private void UpdateNavButtons() {
    var wb = GetCurrentBrowser();
    backButton.Enabled = wb.CanGoBack;
    forwardButton.Enabled = wb.CanGoForward;
}

TabControl 事件:切換同步與關閉邏輯

private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) {
    var wb = GetCurrentBrowser();
    tscbUrl.Text = wb.Url?.ToString() ?? "about:blank";
    tabControl1.SelectedTab.Text = TruncateTitle(wb.DocumentTitle);
    UpdateNavButtons();
}

private void tabControl1_DoubleClick(object sender, EventArgs e) {
    // 至少保留一個標籤
    if (tabControl1.TabPages.Count <= 1) {
        GetCurrentBrowser().Navigate("about:blank");
        tabControl1.SelectedTab.Text = "空白頁";
        return;
    }
    
    // 隱藏 TabControl 防止切換閃爍
    tabControl1.Visible = false;
    var wb = GetCurrentBrowser();
    wb.Dispose(); // 釋放非託管資源 (ActiveX 底層)
    tabControl1.TabPages.Remove(tabControl1.SelectedTab);
    tabControl1.SelectedTab = tabControl1.TabPages[tabControl1.TabPages.Count - 1];
    tabControl1.Visible = true;
}

初始化與啟動

private void Form1_Load(object sender, EventArgs e) {
    NewPage(); // 默認打開首頁 (GoHome 在 CreateBrowser 中調用)
}

已知限制與避坑指南

  • ⚠️ StatusText 在某些 JS 彈出 (javascript:void(0)) 中無法獲取真實 URL,導致新標籤頁打開失敗。
  • ⚠️ WebBrowser 底層基於 IE 内核 (MSHTML),不支持現代 Web 標準 (ES6+, CSS Grid, WebGL 等)。
  • ⚠️ 必須調用 Dispose() 釋放底層 ActiveX 資源,否則內存洩漏嚴重。
  • ✅ 現代替代方案:WebView2 (Edge Chromium 內核) —— 支持現代 Web、獨立運行時、NuGet 安裝 (Microsoft.Web.WebView2)、同樣支持標籤頁架構。

專案結構速覽

TabBrowser/
├── Form1.cs              // 主邏輯 (含所有事件處理)
├── Form1.Designer.cs     // 設計器生成代碼 (控件初始化)
├── Program.cs            // 入口
└── Resources/            // 圖標等資源
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved