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

用 C# 打造多分頁網頁瀏覽器:WebBrowser 控件進階應用

     編輯:關於C語言

前言

現代瀏覽器(Chrome、Firefox、Edge)皆採用分頁式介面。本文示範如何在 WinForms 中使用 WebBrowser 控件(基於 MSHTML/IE 引擎)實現多分頁瀏覽、新視窗攔截、列印預覽、原始碼檢視、尋找對話框、網際網路選項等功能,並解析關鍵事件 NewWindow2 的運作機制。

核心架構:動態建立分頁與 WebBrowser 實例


using System;
using System.Windows.Forms;
using AxSHDocVw; // 需參考 Microsoft Web Browser (COM)

public partial class MainForm : Form
{
    private int _tabIndex = 0;

    public MainForm()
    {
        InitializeComponent();
        // 初始建立第一個分頁
        CreateNewTab("about:blank");
    }

    private AxWebBrowser CreateNewWebBrowser()
    {
        var wb = new AxWebBrowser();
        wb.Tag = new BrowserTag { TabIndex = _tabIndex++ };
        wb.Dock = DockStyle.Fill;

        // 訂閱核心事件
        wb.BeforeNavigate2 += Wb_BeforeNavigate2;
        wb.DocumentComplete += Wb_DocumentComplete;
        wb.NavigateComplete2 += Wb_NavigateComplete2;
        wb.NavigateError += Wb_NavigateError;
        wb.NewWindow2 += Wb_NewWindow2;        // 關鍵:攔截新視窗
        wb.ProgressChange += Wb_ProgressChange;
        wb.StatusTextChange += Wb_StatusTextChange;
        wb.TitleChange += Wb_TitleChange;
        wb.CommandStateChange += Wb_CommandStateChange;

        return wb;
    }

    private void CreateNewTab(string url)
    {
        var wb = CreateNewWebBrowser();
        var tab = new TabPage($"分頁 {wb.Tag as BrowserTag}?.TabIndex}");
        tab.Controls.Add(wb);
        tabControl.TabPages.Add(tab);
        tabControl.SelectedTab = tab;
        wb.Navigate(url);
    }

    // 攔截 target="_blank"、window.open() 等新視窗請求
    private void Wb_NewWindow2(object sender, AxSHDocVw.DWebBrowserEvents2_NewWindow2Event e)
    {
        var newWb = CreateNewWebBrowser();
        e.ppDisp = newWb.Application; // 將新視窗導向我們的控件
        newWb.RegisterAsBrowser = true; // 參與視窗名稱衝突檢測
    }

    // 標籤類別:保存分頁專屬狀態
    private class BrowserTag
    {
        public int TabIndex { get; set; }
        public bool CanGoBack { get; set; }
        public bool CanGoForward { get; set; }
    }

    // 其他事件處理器略...
}

關鍵技術點解析

1. NewWindow2 事件

當網頁嘗試開啟新視窗(<a target="_blank">、window.open())時觸發。
e.ppDisp 指定接收新視窗的 IDispatch 介面,將其設為新建立的 AxWebBrowser.Application 即可在同一應用程式內開啟分頁。
RegisterAsBrowser = true 讓該控件參與「已命名視窗」衝突檢測,避免重複開啟同名視窗。

2. 命令執行:IOleCommandTarget

WebBrowser 底層的 MSHTML 文件物件實作 IOleCommandTarget,可執行「檢視原始碼」、「尋找」、「網際網路選項」等編輯器命令。


using System;
using System.Runtime.InteropServices;
using mshtml; // 參考 Microsoft HTML Object Library

// 介面定義
[ComImport, Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleCommandTarget
{
    void QueryStatus(ref Guid pguidCmdGroup, uint cCmds,
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] OLECMD[] prgCmds,
        ref OLECMDTEXT pCmdText);
    void Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdExecOpt,
        ref object pvaIn, ref object pvaOut);
}

[StructLayout(LayoutKind.Sequential)]
struct OLECMD { public uint cmdID; public uint cmdf; }

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct OLECMDTEXT
{
    public uint cmdtextf; public uint cwActual; public uint cwBuf;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] public char rgwz;
}

// 命令群組 GUID (CGID_IWebBrowser)
private static readonly Guid CMD_GUID = new Guid("ED016940-BD5B-11CF-BA4E-00C04FD70816");

private enum BrowserCommand : uint
{
    Find = 1,
    ViewSource = 2,
    Options = 3
}

// 取得目前分頁的 HTMLDocument
private HTMLDocument GetDocument()
{
    var wb = tabControl.SelectedTab?.Controls[0] as AxWebBrowser;
    return wb?.Document as HTMLDocument;
}

// 執行命令
private void ExecCommand(BrowserCommand cmd)
{
    var doc = GetDocument();
    if (doc == null) return;

    var target = (IOleCommandTarget)doc;
    object inObj = null, outObj = null;
    target.Exec(ref CMD_GUID, (uint)cmd, (uint)OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT,
        ref inObj, ref outObj);
}

// 功能按鈕
private void btnViewSource_Click(object sender, EventArgs e) => ExecCommand(BrowserCommand.ViewSource);
private void btnFind_Click(object sender, EventArgs e) => ExecCommand(BrowserCommand.Find);
private void btnOptions_Click(object sender, EventArgs e)
{
    try { ExecCommand(BrowserCommand.Options); }
    catch { /* 選項對話框關閉時會拋 COM 例外,可忽略 */ }
}

3. 列印與列印預覽


private void Print()
{
    var wb = GetCurrentWebBrowser();
    wb?.Print(); // 直接列印
}

private void PrintPreview()
{
    var wb = GetCurrentWebBrowser();
    // WebBrowser 無內建預覽,需自行實作或呼叫 ExecWB
    object missing = Type.Missing;
    wb?.ExecWB(OLECMDID.OLECMDID_PRINTPREVIEW, OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT,
        ref missing, ref missing);
}

4. 頁面屬性對話框


private void ShowPageProperties()
{
    var wb = GetCurrentWebBrowser();
    object missing = Type.Missing;
    wb?.ExecWB(OLECMDID.OLECMDID_PROPERTIES, OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT,
        ref missing, ref missing);
}

完整功能清單

功能實作方式
多分頁瀏覽TabControl + 動態建立 AxWebBrowser
新視窗攔截NewWindow2 事件 + ppDisp 重導向
前進/後退/重新整理/停止GoBack/GoForward/Refresh/Stop 方法
網址列同步NavigateComplete2 事件更新 TextBox
進度列ProgressChange 事件更新 ProgressBar
狀態列文字StatusTextChange 事件
標題更新分頁文字TitleChange 事件
列印/列印預覽Print() / ExecWB(PRINTPREVIEW)
頁面屬性ExecWB(PROPERTIES)
尋找對話框IOleCommandTarget.Exec(FIND)
檢視原始碼IOleCommandTarget.Exec(VIEWSOURCE)
網際網路選項IOleCommandTarget.Exec(OPTIONS)

已知限制與現代替代方案

  • 引擎老舊:WebBrowser 封裝 IE/MSHTML (Trident),不支援現代 HTML5/CSS3/ES6。
  • 相容性:可透過登錄鍵 FEATURE_BROWSER_EMULATION 強制指定文件模式 (IE11 Edge 模式)。
  • 推薦替代:
    • CefSharp / WebView2 (Edge Chromium):現代渲染引擎、支援 ES6、WebAssembly、DevTools 協議。
    • WebView2 為 Microsoft 官方支援、體積小、自動更新、WinForms/WPF 均可用。

遷移建議:從 WebBrowser 到 WebView2


// 1. NuGet 安裝 Microsoft.Web.WebView2
// 2. 設計介面拖放 WebView2 控件
// 3. 初始化
await webView2.EnsureCoreWebView2Async();
// 4. 導航
webView2.CoreWebView2.Navigate("https://example.com");
// 5. 執行腳本
await webView2.CoreWebView2.ExecuteScriptAsync("document.title");
// 6. 攔截新視窗
webView2.CoreWebView2.NewWindowRequested += (s, e) =>
{
    e.NewWindow = newWebView2.CoreWebView2; // 導向新分頁
};

總結

雖然 WebBrowser 屬於上一代技術,但理解其事件模型(NewWindow2)、COM 命令介面(IOleCommandTarget)、分頁狀態管理等核心概念,對於維護舊專案或快速原型開發仍有價值。新專案強烈建議直接採用 WebView2,獲得現代 Web 標準支援與長期維護保障。

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