一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

CefSharp中文幫助文檔

 印度阿三17 2020-12-02

CefSharp是圍繞Chromium嵌入式框架(?Chromium Embedded Framework,CEF)的簡單.Net包裝器。CEF是一個基于Google Chromium項目的開源項目。與Chromium項目本身(主要專注于Google Chrome應用程序開發(fā))不同,CEF專注于促進第三方應用程序中的嵌入式瀏覽器用例。?CEF基于多進程Chromium Content API,因此,當前僅存在Chromium的部分功能。例如,對擴展的支持是有限的,僅實現(xiàn)了一部分Extension API

CefSharp提供三種不同的類型WinForms,WPFOffScreen。在WPFOffScreen版本使用的OffScreen Rendering(OSR)渲染模式。在OSR模式中,每個幀被渲染到緩沖器,然后或者在屏幕上繪制作為的情況下WPF或可作為BitmapOffScreen。所有版本都使用CefSharpCefSharp.Core庫,因此API在這三種風格中,大部分使用的庫都完全相同。這減少了代碼重復并降低了添加新功能的維護負擔,唯一的缺點是該WPF版本并不像它可能的那樣友好(您可以將其ChromiumWebBrowser歸類,并在應用程序中實現(xiàn)所需的任何缺少的部分)。您也可以托管WinFormsWPF使用中的版本號WindowsFormsHost,可能需要繞過該WPF版本的某些限制(CEF尚未在OSR模式中實現(xiàn)完全的觸摸屏支持,在上存在一個開放問題CEF Issue Tracker,如果您需要這樣做,請參與其中)。

發(fā)行說明

有關(guān)每個版本的發(fā)行說明,請訪問https://github.com/cefsharp/CefSharp/releases,如果您有問題或?qū)Ω挠兴闷?,請抽出時間閱讀它們。如果遇到問題,請查看“已知問題”部分,通常會有一些說明包含有關(guān)發(fā)行版的有用信息。

軟件需求

CefSharp使用Visual C (VC )與本機C API交互,因此它只能在Windows上運行。(沒有Windows APP Store版本)。CefSharp在每個第二Chromium版本上發(fā)布版本,例如47、49、51。每個CefSharp版本都有其自己的分支,有關(guān)每個分支的詳細信息和要求,請參見https://github.com/cefsharp/CefSharp#release-branches。Google最近去除了對較早的操作系統(tǒng)的支持,例如Windows XP,Vista及其服務(wù)器版本。如果您要求您的應用程序在這些操作系統(tǒng)上運行,請查看發(fā)行版以獲取更多詳細信息https://github.com/cefsharp/CefSharp/releases

CefSharp要求

筆記:

任何CPU支持

較新的版本現(xiàn)在支持定位AnyCPU,有關(guān)如何實現(xiàn)此功能的詳細信息,請參見https://github.com/cefsharp/CefSharp/issues/1714??梢允褂孟嗤募夹g(shù)將libcef.dll等等移動到磁盤上的其他文件夾或公共位置。

?

需要知道/限制

  • 要指定CachePath用于Cookie的持久性,如保存密碼等,需要默認指定In-Memory Cache(類似于Incogneto)。有關(guān)使用以下內(nèi)容初始化CEF的示例,請參見下面的“初始化和關(guān)閉”部分CachePath。
  • 您可以使用Network.clearBrowserCache清除磁盤緩存,請參閱#3158以獲得有關(guān)執(zhí)行DevTools命令的詳細信息。
  • 在中app.manifest為您的應用添加,以獲取HiDPI支持,應用兼容性(在上運行Windows 10)和中的工具提示WinForms。這些示例包含示例app.manifest文件。這非常重要http:///ceforum/viewtopic.php?f=6&t=14721
  • 類似于日志中的錯誤Check failed: fallback_available == base::win::GetVersion() > base::win::VERSION_WIN8 (1 vs. 0)是您的應用程序需要app.manifest使用相關(guān)compatibility條目的標志。
  • CEFInitialized/Shutdown每個進程只能有一次,請參閱以下部分以獲取完整詳細信息,這是對基礎(chǔ)Chromium框架的限制。
  • Minimal同時為版本WPFWinForms版本添加了設(shè)計師支持57.0.0,有關(guān)詳細信息,請參見#1989(WPF)#1946(WinForms)。設(shè)計人員的支持需要您定位x86(理論上AnyCPU也應該有效,但尚未經(jīng)過測試)。Visual Studio是,x86因此您無法使用該x64版本。對于較舊的版本,不提供設(shè)計人員支持(設(shè)計人員將引發(fā)異常)。
  • 僅在默認的AppDomain中運行,有一些變通辦法,例如https://github.com/flole/CefSharp.AppDomain和?https://github.com/stever/AppHostCefSharp
  • 由于資源有限,一次僅支持一個版本,請參閱https://github.com/cefsharp/CefSharp#release-branches以查看哪個版本為最新版本。如果您使用的是舊版本,則遇到問題,則必須升級到當前支持的版本。
  • 僅在Windows沒有App Store版本上運行。
  • 支持.Net Core,但需要其他步驟,請參見https://github.com/cefsharp/CefSharp.MinimalExample#net-core-support
  • Sandboxing尚未實現(xiàn),因為直接在上添加支持在技術(shù)上是不可行的CefSharp,有關(guān)詳細信息,請參見#697。
  • WinForms屏幕鍵盤上的屏幕可能會受益于disable-usb-keyboard-detect命令行參數(shù)?https://github.com/cefsharp/CefSharp/issues/1691#issuecomment-323603277
  • WPFHigh DPI建議具有監(jiān)視器的用戶.Net 4.6在其目標計算機上安裝,因為其中存在一個錯誤,該錯誤.Net Framework可能會導致MILERR_WIN32ERROR Exception參見#2035的詳細信息
  • CEF當前不支持PNaCl加載所需的內(nèi)容,Google Earth請參見http:///ceforum/viewtopic.php?f=6&t=15761

例子

CefSharp源代碼包含的許多不同的特征的實施例。還有一個MinimalExample項目使用最新的Nuget軟件包提供非常簡單的Browser實現(xiàn)。這MinimalExample是入門的最佳位置,下載此項目并使其運行以作為基礎(chǔ)參考,以確保一切都在您的系統(tǒng)上正常工作。

https://github.com/cefsharp/CefSharp.MinimalExample

記錄中

默認情況下CEF,在應用程序的執(zhí)行文件夾(例如)中維護其自己的日志文件('Debug.log')bin。要禁用日志記錄更改settings.LogSeverity,并更改文件名/路徑,請使用settings.LogFile。

調(diào)試問題時,首先要檢查的地方是此日志文件,因為它包含低級Chromium消息。如果您看到錯誤或警告,搜索http:///ceforum/index.phphttps:///chromiumembedded/cef/issues?status=new&status=open

工藝流程

CEF使用多進程運行。處理窗口創(chuàng)建,繪畫和網(wǎng)絡(luò)訪問的主進程稱為browser進程。通常,此過程與主機應用程序相同,并且大多數(shù)應用程序邏輯將在瀏覽器進程中運行。閃爍呈現(xiàn)和JavaScript執(zhí)行在單獨的render過程中進行。一些應用程序邏輯(例如JavaScript綁定)也將在渲染過程中運行。默認進程模型將為每個唯一的來源(方案 域)生成一個新的渲染過程。將根據(jù)需要生成其他進程,例如處理插件(如Flash)的“插件”進程和處理加速合成的“ gpu”進程。

默認情況CefSharp下,該render進程的默認實現(xiàn)稱為CefSharp.BrowserSubProcess.exe。如上所述,將多次產(chǎn)生此過程以表示單獨的過程。從版本開始,51.0.0可以提供自己的自定義BrowserSubProcess,因為可執(zhí)行文件現(xiàn)在是基礎(chǔ)VC 實現(xiàn)的非常簡單的包裝。

https:///chromiumembedded/cef/issues/2498/add-support-for-site-per-process#comment-54186905包含有關(guān)當前默認流程模型的詳細信息。

線程數(shù)

CEF使用多個線程進行不同級別的處理。例如browser,該過程包含以下通常引用的線程:

  • UI線程是瀏覽器過程中的主線程。默認情況下CefSharp使用,setting.MultiThreadedMessageLoop = true因此該CEF UI線程不同于您的主應用程序線程
  • IO線程在瀏覽器進程中用于處理IPC和網(wǎng)絡(luò)消息
  • FILE線程在瀏覽器進程中用于與文件系統(tǒng)進行交互
  • RENDERER線程是渲染器過程中的主線程

初始化和關(guān)閉

Initialize每個進程(應用程序)只能調(diào)用一次??梢赃\行您的應用程序的多個實例,您需要CachePath為每個實例提供唯一的實例,請參閱CefSettings下文。

有關(guān)如何在運行時更改設(shè)置,隔離瀏覽器實例,為不同實例設(shè)置不同的緩存路徑的詳細信息,請參見請求上下文(瀏覽器隔離)。

重要的是要注意,有必要初始化基礎(chǔ)CEF庫。這可以通過顯式和隱式兩種方式之一來實現(xiàn)。創(chuàng)建新實例時ChromiumWebBrowser,它將檢查CEF是否已初始化,如果尚未初始化,請使用默認值為您初始化。對于那些希望指定一些自定義設(shè)置的用戶,您可以CEF如下所示顯式初始化自己:

public static void Init()
{
    var settings = new CefSettings();

    // Increase the log severity so CEF outputs detailed information, useful for debugging
    settings.LogSeverity = LogSeverity.Verbose;
    // By default CEF uses an in memory cache, to save cached data e.g. to persist cookies you need to specify a cache path
    // NOTE: The executing user must have sufficient privileges to write to this folder.
    settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache");

    Cef.Initialize(settings);
}

對于Cef.Shutdown,ChromiumWebBrowser將鉤住相關(guān)Application Exit事件的WinForms和WPF實例,并且默認情況下調(diào)用Cef.Shutdown()。設(shè)置CefSharpSettings.ShutdownOnExit=false;?禁用此行為。在ChromiumWebBrowser創(chuàng)建事件的第一個實例之前,需要設(shè)置此值,因為事件處理程序已掛接到ChromiumWebBrowser該類的靜態(tài)構(gòu)造函數(shù)中。

重要的是要注意CEF?Initialize/Shutdown?必須在主應用程序線程(通常是UI線程)上調(diào)用。如果您在不同的線程上調(diào)用它們,則您的應用程序?qū)炱稹?/p>

一個使用Initialize/Shutdown手動調(diào)用/的示例,WinForms可以將該示例應用于WPF使用該CefSharp.OffScreen包的控制臺應用程序(該OffScreen示例位于https://github.com/cefsharp/CefSharp.MinimalExample是一個很好的起點,其中也有一個示例)主項目存儲庫,它要高級一些)。

public class Program
{
        [STAThread]
        public static void Main()
        {
            //For Windows 7 and above, best to include relevant app.manifest entries as well
            Cef.EnableHighDPISupport();
    
            //We're going to manually call Cef.Shutdown below, this maybe required in some complex scenarios
            CefSharpSettings.ShutdownOnExit = false;

            //Perform dependency check to make sure all relevant resources are in our output directory.
            Cef.Initialize(new CefSettings(), performDependencyCheck: true, browserProcessHandler: null);

            var browser = new BrowserForm();
            Application.Run(browser);
    
            //Shutdown before your application exists or it will hang.
            Cef.Shutdown();
        }
}

綜上所述

  • Cef.Initialize并且Cef.Shutdown每個進程(應用程序)只能調(diào)用一次Initialize,因此僅使用完后CefSharp后才調(diào)用Shutdown
  • Cef.Initialize并且Cef.Shutdown必須在同一線程上調(diào)用。
  • Cef.Initialize如果您創(chuàng)建新ChromiumWebBrowser實例并且尚未調(diào)用,則會為您隱式調(diào)用Cef.Initialize。
  • 對于WinForms和WPF實例,默認情況下ChromiumWebBrowser相關(guān)的Application Exit事件被鉤住,然后默認調(diào)用Cef.Shutdown()方法處理。設(shè)置CefSharpSettings.ShutdownOnExit = false;用于禁用此行為。在ChromiumWebBrowser創(chuàng)建事件的第一個實例之前,需要設(shè)置此值,因為事件處理程序已掛接到ChromiumWebBrowser該類的靜態(tài)構(gòu)造函數(shù)中。
  • 在其中CefSharp.OffScreen,必須Cef.Shutdown()在應用程序存在之前顯式調(diào)用它,否則它將掛起。

CefSettings和BrowserSettings

CefSettings結(jié)構(gòu)允許配置應用程序范圍的CEF設(shè)置。一些通常配置的成員包括:

  • BrowserSubprocessPath 此路徑是子流程啟動的獨立可執(zhí)行文件的路徑。通常,無需更改此設(shè)置。
  • MultiThreadedMessageLoop 在CefSharp中默認值為True,盡管可以將其集成CEF到您的應用程序現(xiàn)有的消息循環(huán)中,請參閱下面的MultiThreadedMessageLoop部分。
  • CommandLineArgsDisabled?設(shè)置為true可禁用使用標準CEF和Chromium命令行參數(shù)配置瀏覽器進程功能的功能。有關(guān)更多信息,請參見“命令行參數(shù)”部分。
  • RootCachePath?所有CefSettings.CachePathRequestContextSettings.CachePath值必須具有相同的根目錄。如果此值為空且CefSettings.CachePath非空,則默認為該CefSettings.CachePath值。如果此值為非空值,那么它必須是絕對路徑。非空RootCachePath可以與空CefSettings.CachePath結(jié)合使用,在您希望瀏覽器連接到以“隱身模式”創(chuàng)建的Global RequestContext(默認)的實例以及使用基于磁盤的緩存使用自定義RequestContext創(chuàng)建的實例的情況下, 。有關(guān)更多詳細信息,請參見下面的RequestContext部分。
  • CachePath?全局瀏覽器緩存的數(shù)據(jù)將存儲在磁盤上的位置。此值是非空的,那么它必須是絕對路徑,該路徑必須等于CefSettings.RootCachePath或子目錄(如果RootCachePath為空,則默認為該值)。如果該值為空,則將在“隱身模式”下創(chuàng)建瀏覽器,在該模式下,將使用內(nèi)存中的緩存進行存儲,并且不會將任何數(shù)據(jù)持久化到磁盤上。如果指定了緩存路徑,則諸如localStorage之類的HTML5數(shù)據(jù)庫將僅在會話之間持久存在??梢?code>RequestContext通過該RequestContextSettings.CachePath值覆蓋單個實例。有關(guān)更多詳細信息,請參見下面的RequestContext部分。
  • Locale?將傳遞給Blink的語言環(huán)境字符串。如果為空,則將使用默認語言環(huán)境“ en-US”。也可以使用“ lang”命令行開關(guān)進行配置。更改此項以同時設(shè)置上下文菜單語言。
  • LogFile?用于調(diào)試日志的目錄和文件名。如果為空,將使用默認名稱“ debug.log”,并將文件寫入應用程序目錄。也可以使用“ log-file”命令行開關(guān)進行配置。
  • LogSeverity?日志嚴重性。僅記錄此嚴重級別或更高級別的消息。也可以使用“ log-severity”命令行開關(guān)進行配置,其值為“ verbose”,“ info”,“ warning”,“ error”,“ error-report”或“ disable”。
  • ResourcesDirPath?資源目錄的標準路徑。如果此值為空,則cef.pak和/或devtools_resources.pak文件必須位于模塊目錄中。也可以使用“ resources-dir-path”命令行開關(guān)進行配置。
  • LocalesDirPath?語言環(huán)境目錄的標準路徑。如果此值為空,則語言環(huán)境目錄必須位于模塊目錄中。在Mac OS X上,始終從應用程序包Resources目錄中加載打包文件的情況下,將忽略此值。也可以使用“ locales-dir-path”命令行開關(guān)進行配置。
  • RemoteDebuggingPort?設(shè)置為1024到65535之間的值以在指定的端口上啟用遠程調(diào)試。例如,如果指定8080,則遠程調(diào)試URL將為http:// localhost:8080??梢詮娜魏蜟EF或Chrome瀏覽器窗口中遠程調(diào)試CEF。也可以使用“ remote-debugging-port”命令行開關(guān)進行配置。

有許多設(shè)置和命令行參數(shù)可能會影響CEF的行為方式。這里有些例子:

public static void Init()
{
    // Specify Global Settings and Command Line Arguments
    var settings = new CefSettings();

    // By default CEF uses an in memory cache, to save cached data e.g. to persist cookies you need to specify a cache path
    // NOTE: The executing user must have sufficient privileges to write to this folder.
    settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache");;

    // There are many command line arguments that can either be turned on or off

    // Enable WebRTC                            
    settings.CefCommandLineArgs.Add("enable-media-stream");
    
    //Disable GPU Acceleration
    settings.CefCommandLineArgs.Add("disable-gpu");

    // Don't use a proxy server, always make direct connections. Overrides any other proxy server flags that are passed.
    // Slightly improves Cef initialize time as it won't attempt to resolve a proxy
    settings.CefCommandLineArgs.Add("no-proxy-server"); 

    Cef.Initialize(settings);
}

些設(shè)置可以應用于特定ChromiumWebBrowser實例。如果您正在使用WPF,則可以BrowserSettings在中指定XAML。

var browser = new ChromiumWebBrowser(url)
{
    BrowserSettings =
    {
        DefaultEncoding = "UTF-8",
        WebGl = CefState.Disabled
    }
};
<!--xmlns:cefSharpCore="clr-namespace:CefSharp;assembly=CefSharp.Core"-->
<!--xmlns:cefSharpWpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"-->

<cefSharpWpf:ChromiumWebBrowser>
    <cefSharpWpf:ChromiumWebBrowser.BrowserSettings>
        <cefSharpCore:BrowserSettings DefaultEncoding="UTF-8"/>
    </cefSharpWpf:ChromiumWebBrowser.BrowserSettings>
</cefSharpWpf:ChromiumWebBrowser>

IBrowser,IFrame和IBrowserHost

IBrowserIFrame對象用于將命令發(fā)送到瀏覽器,并在回調(diào)方法中返回狀態(tài)信息。每個IBrowser對象都有一個代表頂層框架的main?IFrame對象,以及零個或多個sub?IFrame對象。

例如,加載兩個HTML<iframe>的瀏覽器將具有三個IFrame對象(頂級框架和兩個<iframe>)。

要將URL加載到瀏覽器主機中:

browser.MainFrame.LoadUrl(someurl);

CefSharp提供了許多擴展方法,使執(zhí)行常見任務(wù)更加容易。請參閱參考資料WebBrowserExtensions,以獲取這些方法的來源,并更好地了解如何執(zhí)行常見任務(wù)。

IBrowserHost?代表更底層的瀏覽器方法。

處理程序

CefSharp為了方便起見,提供了一些事件,如下所示(有關(guān)所有常見事件以及有關(guān)其用法的詳細信息,請參見IWebBrowser?API文檔):

這些是簡單的事件,僅提供一小部分提供的基礎(chǔ)處理程序CEF。這些事件僅在主瀏覽器中被調(diào)用,對于彈出窗口處理,您可以使用IDisplayHandler和來訪問通知ILoadHandler。

為了確定頁面何時完成加載,我建議在FrameLoadEnd上使用LoadingStateChanged。重要的是要記住,完成的加載不同于完成的渲染。當前尚無確定網(wǎng)頁何時完成渲染的方法(Flash,動態(tài)內(nèi)容,動畫等功能,甚至像移動鼠標或滾動之類的簡單任務(wù)也將導致渲染新幀)。

IDialogHandler,IDisplayHandlerIDownloadHandler,IContextMenuHandlerILifeSpanHandler,ILoadHandlerIRequestHandler是一些更常見的處理程序(參見其余部分的源極/ API DOC)。這些僅以方便的.NET方式包裝基礎(chǔ)CEF處理程序。例如CEF的CefDownloadHandlerIDownloadHandlerCefSharp。實施這些處理程序?qū)⑹鼓軌蛟L問作為CEF基礎(chǔ)的基礎(chǔ)事件和回調(diào)??梢允褂没卣{(diào)以異步方式執(zhí)行許多處理程序的成員。所有處理程序都遵循一致的模式:返回a的處理程序bool詢問您是否要自己處理。如果否,則返回false默認操作。true如果您自己處理,請返回。

它們是您實現(xiàn)并分配給ChromiumWebBrowser實例的基本接口。例如

browser.DownloadHandler = new DownloadHandler();

理想情況下,您應在ChromiumWebBrowser實例化實例后立即設(shè)置處理程序。有關(guān)更多詳細示例,請參見源代碼中的示例項目。當前沒有可用的默認實現(xiàn),因此您必須實現(xiàn)每種方法。(如果您希望提供默認實現(xiàn),請?zhí)峤徽埱笳埱螅?/p>

有關(guān)處理程序的一些一般說明

可以使用來修改響應ResponseFilter。請參閱以下部分。

請求處理Request Handling

CEF支持兩種方法來處理應用程序內(nèi)部的網(wǎng)絡(luò)請求。

  1. ?Scheme Handler方法允許用于靶向特定原點(方案 結(jié)構(gòu)域)的請求的處理程序的注冊。
  2. ?Request Interception?方法允許在處理應用程序的自由裁量權(quán)的任意請求。

使用HTTP(S)方案而不是自定義方案,可以避免一系列潛在的問題。

如果您選擇使用自定義方案(比其他任何事情http://,https://等),你必須用CEF注冊它,這樣它會像預期的那樣。如果您希望自定義方案的行為類似于HTTP(支持POST請求并強制實施HTTP訪問控制(CORS)限制),則應將其注冊為“標準”方案。如果您打算對其他方案執(zhí)行跨域請求或?qū)OST請求發(fā)送XMLHttpRequest到方案處理程序,則應使用HTTP方案而不是自定義方案,以避免潛在的問題。IsSecureIsCorsEnabled參數(shù)最近添加。

處理程序可以使用這兩個內(nèi)置的方案(http://,https://,等)和自定義方案。使用內(nèi)置方案時,請為您的應用程序選擇一個唯一的域名(如myappinternal)。實現(xiàn)ISchemeHandlerFactoryIResourceHandler類來處理請求并提供響應數(shù)據(jù)。有關(guān)IResourceHandler的默認實現(xiàn),請參閱ResourceHandler,它具有許多有用的靜態(tài)幫助器方法。

? ?Scheme Handler

處理程序可與內(nèi)置方案(HTTP,HTTPS等)和自定義方案一起使用。使用內(nèi)置方案時,請為您的應用程序選擇一個唯一的域名(如myappinternal)。實現(xiàn)ISchemeHandlerFactoryIResourceHandler類以處理請求并提供響應數(shù)據(jù)。有關(guān)IResourceHandler的默認實現(xiàn),請參閱ResourceHandler,它具有許多有用的靜態(tài)幫助器方法。

計劃處理程序通過CefSettings.RegisterScheme函數(shù)進行注冊。例如,您可以為“ localfolder:// cefsharp /”請求注冊一個處理程序(下面還有另一個示例,并且在項目源代碼中有一些有效的示例):

settings.RegisterScheme(new CefCustomScheme
{
SchemeName = "localfolder",
DomainName = "cefsharp",
SchemeHandlerFactory = new FolderSchemeHandlerFactory(rootFolder: @"..\..\..\..\CefSharp.Example\Resources",
hostName: "cefsharp", //Optional param no hostname/domain checking if null
defaultPage: "home.html") //Optional param will default to index.html
});

FolderSchemeHandlerFactory是使用一個方案處理從磁盤讀取文件的簡單默認實現(xiàn)。您可以使用自定義方案(換句話說,您可以以形式提供URL?customscheme://folder/yourfile)或標準方案(https://https://)。

實現(xiàn)自己的工廠的示例可能如下所示:

public class CefSharpSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";

private static readonly IDictionary<string, string> ResourceDictionary;

static CefSharpSchemeHandlerFactory()
{
ResourceDictionary = new Dictionary<string, string>
{
{ "/home.html", Resources.home_html },
{ "/bootstrap/bootstrap.min.css", Resources.bootstrap_min_css },
{ "/bootstrap/bootstrap.min.js", Resources.bootstrap_min_js },
{ "/BindingTest.html", Resources.BindingTest },
{ "/ExceptionTest.html", Resources.ExceptionTest },
{ "/PopupTest.html", Resources.PopupTest },
{ "/SchemeTest.html", Resources.SchemeTest }
};
}

public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
//Notes:
// - The 'host' portion is entirely ignored by this scheme handler.
// - If you register a ISchemeHandlerFactory for http/https schemes you should also specify a domain name
// - Avoid doing lots of processing in this method as it will affect performance.
// - Uses the Default ResourceHandler implementation

var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;

string resource;
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
var fileExtension = Path.GetExtension(fileName);
return ResourceHandler.FromString(resource, , mimeType: Cef.GetMimeType(fileExtension));
}

return null;
}
}

提供的ResourceHandlerIResourceHandler的默認實現(xiàn),并且包含許多用于創(chuàng)建類的靜態(tài)幫助器方法。有關(guān)更多詳細信息,請參見下面的“資源處理程序”部分。

使用靜態(tài)方法的一些示例是:

ResourceHandler.FromStream(stream, mimeType);
ResourceHandler.FromString(htmlString, includePreamble:true, mimeType:Cef.GetMimeType(fileExtension));
ResourceHandler.FromFilePath("CefSharp.Core.xml", mimeType);

最后,您必須使用以下代碼注冊此方案處理程序:

public static void Init()
{
// Pseudo code; you probably need more in your CefSettings also.
var settings = new CefSettings();

settings.RegisterScheme(new CefCustomScheme
{
SchemeName = "custom",
SchemeHandlerFactory = new CefSharpSchemeHandlerFactory()
});

Cef.Initialize(settings);
}

計劃注冊必須在調(diào)用之前進行,這一點很重要Cef.Initialize()。

請求攔截Request Interception

IResourceRequestHandler.GetResourceRequestHandler支持攔截任意請求。它使用與方案處理程序方法相同的IResourceHandler類。提供的ResourceHandlerIResourceHandler的默認實現(xiàn),并且包含許多用于創(chuàng)建類的靜態(tài)幫助器方法。有關(guān)更多詳細信息,請參見下面的“資源處理程序”部分。

public class CustomResourceRequestHandler : CefSharp.Handler.ResourceRequestHandler
{
protected override IResourceHandler GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request)
{
//ResourceHandler has many static methods for dealing with Streams, 
// byte[], files on disk, strings
// Alternatively ou can inheir from IResourceHandler and implement
// a custom behaviour that suites your requirements.
return ResourceHandler.FromString("Welcome to CefSharp!", mimeType: Cef.GetMimeType("html"));
}
}

public class CustomRequestHandler : CefSharp.Handler.RequestHandler
{
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
//Only intercept specific Url's
if (request.Url == "http://cefsharp.test/" || request.Url == "https://cefsharp.test/")
{
return new CustomResourceRequestHandler();
}

//Default behaviour, url will be loaded normally.
return null;
}
}

browser.RequestHandler = new CustomRequestHandler();

IWebBrowser.RegisterResourceHandlerIWebBrowser.UnRegisterResourceHandler擴展方法提供提供一種簡單的方法IResourceHandler對于給定的Url。

例如,您可以請求一個虛構(gòu)的URL并提供一個響應,就像該網(wǎng)站是真實的一樣。

資源處理程序ResourceHandler

ISchemeHandlerFactoryIResourceRequestHandler.GetResourceHandler使用IResourceHandler接口來表示響應(流 頭 狀態(tài)碼,等等)。IResourceHandler的默認實現(xiàn)只是ResourceHandler

為了方便起見,ResourceHandler包含許多靜態(tài)方法

使用靜態(tài)方法的一些示例是:

ResourceHandler.FromStream(stream, mimeType);
ResourceHandler.FromString(htmlString, includePreamble:true, mimeType:Cef.GetMimeType(fileExtension));
ResourceHandler.FromFilePath("CefSharp.Core.xml", mimeType);

該源代碼包含ISchemeHandlerFactory的詳細示例。

實施實例ResourceHandler.ProcessRequestAsync。如果需要完全控制,則可以實現(xiàn)IResourceHandler,但是在大多數(shù)情況下,這不是必需的。

//A simple example of a ResourceHandler that downloads a file from the internet.
public class ExampleResourceHandler : ResourceHandler
{
public override CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback)
{
Task.Run(() =>
{
using (callback)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://samples./SWF/zeldaADPCM5bit.swf");

var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();

// Get the stream associated with the response.
var receiveStream = httpWebResponse.GetResponseStream();
var mime = httpWebResponse.ContentType;

var stream = new MemoryStream();
receiveStream.CopyTo(stream);
httpWebResponse.Close();

//Reset the stream position to 0 so the stream can be copied into the underlying unmanaged buffer
stream.Position = 0;

//Populate the response values
ResponseLength = stream.Length;
MimeType = mime;
StatusCode = (int)HttpStatusCode.OK;
Stream = stream;

callback.Continue();
}
});

return CefReturnValue.ContinueAsync;
}
}

響應過濾Response Filtering

IResourceRequestHandler.GetResourceResponseFilter()支持過濾響應請求而接收的數(shù)據(jù)。您可以檢索原始響應數(shù)據(jù),也可以將數(shù)據(jù)追加到響應中,例如在文件末尾注入一些自定義CSS。您可以根據(jù)需要重寫響應??捎糜诮邮杖魏握埱蟮捻憫?,即AJAX(XHRHttpRequest)/ POST / GET。

將響應作為UTF8字符串獲取的基本示例是:

public class CustomResourceRequestHandler : CefSharp.Handler.ResourceRequestHandler
{
private readonly System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();

protected override IResponseFilter GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
return new CefSharp.ResponseFilter.StreamResponseFilter(memoryStream);
}

protected override void OnResourceLoadComplete(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
{
//You can now get the data from the stream
var bytes = memoryStream.ToArray();

if (response.Charset == "utf-8")
{
var str = System.Text.Encoding.UTF8.GetString(bytes);
}
else
{
//Deal with different encoding here
}
}
}

public class CustomRequestHandler : CefSharp.Handler.RequestHandler
{
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
//Only intercept specific Url's
if (request.Url == "http://cefsharp./" || request.Url == "https://cefsharp./")
{
return new CustomResourceRequestHandler();
}

//Default behaviour, url will be loaded normally.
return null;
}
}

browser.RequestHandler = new CustomRequestHandler();

當前,StreamResponseFilter是框架中提供的唯一過濾器。

將dataIn復制到dataOut的簡單響應過濾器。數(shù)據(jù)以塊的形式進行流傳輸,通常大小為64kb。

/// <summary>
/// PassThruResponseFilter - copies all data from DataIn to DataOut.
/// Upstream documentation link
/// https:///ceforum/apidocs3/projects/(default)/CefResponseFilter.html#Filter(void*,size_t,size_t&,void*,size_t,size_t&)
/// </summary>
public class PassThruResponseFilter : IResponseFilter
{
bool IResponseFilter.InitFilter()
{
return true;
}

FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
{
if (dataIn == null)
{
dataInRead = 0;
dataOutWritten = 0;

return FilterStatus.Done;
}

//Calculate how much data we can read, in some instances dataIn.Length is
//greater than dataOut.Length
dataInRead = Math.Min(dataIn.Length, dataOut.Length);
dataOutWritten = dataInRead;

var readBytes = new byte[dataInRead];
dataIn.Read(readBytes, 0, readBytes.Length);
dataOut.Write(readBytes, 0, readBytes.Length);

//If we read less than the total amount avaliable then we need
//return FilterStatus.NeedMoreData so we can then write the rest
if (dataInRead < dataIn.Length)
{
return FilterStatus.NeedMoreData;
}

return FilterStatus.Done;
}

public void Dispose()
{

}
}

有關(guān)IResourceFilter的CefSharp.Example其他示例實現(xiàn),請參見源代碼中的項目。該功能實現(xiàn)起來非常復雜。提出任何問題之前,請確保您已閱讀并調(diào)試了現(xiàn)有示例。

從磁盤/數(shù)據(jù)庫/嵌入式資源/流中加載HTML / CSS / JavaScript / etc

CefSharp.WebBrowserExtensions類中提供了一些擴展方法,以方便使用。

//Load a data encoded Uri
//NOTE There are limits to the size of a Data Uri, use the overload that takes a Url if you need to load large files
LoadHtml(this IWebBrowser browser, string html, bool base64Encode = false);

//Register a ResourceHandler with the `ResourceRequestHandlerFactory` and calls browser.Load
LoadHtml(this IWebBrowser browser, string html, string url)`;

//Register a resource handler with the `ResourceRequestHandlerFactory`
RegisterResourceHandler(this IWebBrowser browser, string url, Stream stream, string mimeType = 
ResourceHandler.DefaultMimeType);

//Unregister a resource handler with the `ResourceRequestHandlerFactory`
UnRegisterResourceHandler(this IWebBrowser browser, string url);

//In `WinForms` you can pass a `HtmlString` directly into the constructor and have it load as a Data Uri
new ChromiumWebBrowser((CefSharp.Web.HtmlString)"<html><body style='background:red;'>Data Uri Test</body></html>");

有關(guān)data:包含URI本身中的請求正文的已編碼URI的更多信息,請參見https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs

自己生成Data URI將類似于:

const string html = "<html><head><title>Test</title></head><body><h1>Html Encoded in URL!</h1></body></html>";
var base64EncodedHtml = Convert.ToBase64String(Encoding.UTF8.GetBytes(html));
browser.Load("data:text/html;base64,"   base64EncodedHtml);

文件URI(file:///)

我強烈建議不要file:///從本地磁盤加載時使用。應用了不同的安全限制,并且存在許多限制。我建議使用Scheme處理程序或?qū)崿F(xiàn)自己的處理程序IResourceRequestHandlerFactory。(data:特別是對于OffScreen項目而言,加載編碼的URI也非常方便)。

如果您選擇忽略此建議,則必須解決file:///自己遇到的任何問題。ceforum是最好的資源。

代理解析

有兩個用于配置代理服務(wù)器的選項。

  1. CEF使用與Google Chrome相同的命令行標志。
  2. 可以使用IRequestContext.SetPreference在運行時設(shè)置/更改代理設(shè)置。
    • IRequestContext.SetPreference必須在CEF UI線程上調(diào)用。使用Cef.UIThreadTaskFactory在上生成任務(wù)CEF UI Thread。IRequestContextHandler方法已經(jīng)在CEF UI線程上調(diào)用,因此您可以SetPreference直接調(diào)用。
    • 可以逐個指定代理設(shè)置,Request Context從而使您可以ChromiumWebBrowser使用不同的代理來擁有不同的實例。
    • 閱讀下面的“請求上下文”部分,以獲取更多詳細信息和基本代碼示例。

如果代理要求身份驗證,則將使用值為的IRequestHandler.GetAuthCredentials()回調(diào)執(zhí)行以檢索用戶名和密碼。isProxytrue

http:///questions/36095566/cefsharp-3-set-proxy-at-runtime上可以找到使用Preferencesin設(shè)置代理的一些其他示例。CefSharp

請求上下文(瀏覽器隔離)

隔離瀏覽器實例的方法,包括提供自定義緩存路徑,不同的代理設(shè)置,不同的Cookie管理器以及許多其他功能RequestContext。在較新的版本中,PPAPI插件的加載是在該RequestContext級別上進行的。在CEF條款的底層類是CefRequestContext。

以下是一些關(guān)鍵點:

//WinForms Examples - WPF and OffScreen are similar, see notes above.

//Default implementation of RequestContext
//Default settings will be used, this means an in-memory cache (no data persisted)
browser = new ChromiumWebBrowser();
browser.RequestContext = new RequestContext();

//CustomRequestContextHanler needs to implement `IRequestContextHandler`
//Default settings will be used, this means an in-memory cache (no data persisted)
browser = new ChromiumWebBrowser();
browser.RequestContext = new RequestContext(new CustomRequestContextHandler());

//Custom settings and CustomRequestContextHandler
//Use the specified cache path (if empty, in memory cache will be used). To share the global
//browser cache and related configuration set this value to match the CefSettings.CachePath
//value.
var requestContextSettings = new RequestContextSettings { CachePath = cachePath };
browser = new ChromiumWebBrowser();
browser.RequestContext = new RequestContext(requestContextSettings, new CustomRequestContextHandler());

有關(guān)更多詳細示例,請參見項目源。

//When you are already on the CEF UI Thread you can use the following
string errorMessage;
//You can set most preferences using a `.` notation rather than having to create a complex set of dictionaries.
//The default is true, you can change to false to disable
context.SetPreference("webkit.webprefs.plugins_enabled", true, out errorMessage);
//Change the minimum font size to 24pt
context.SetPreference("webkit.webprefs.minimum_font_size", 24, out errorMessage);

//To execute on the CEF UI Thread you can use 
Cef.UIThreadTaskFactory.StartNew(delegate
{
    string errorMessage;
    //Use this to check that settings preferences are working in your code

    //the browser variable is an instance of ChromiumWebBrowser
    var success = browser.RequestContext.SetPreference("webkit.webprefs.minimum_font_size", 24, out errorMessage);
}); 

在OnRequestContextInitialized中設(shè)置首選項(建議使用此方法來設(shè)置代理,因為它將在瀏覽器嘗試加載任何網(wǎng)頁之前被調(diào)用)

public class RequestContextHandler : IRequestContextHandler
{
IResourceRequestHandler IRequestContextHandler.GetResourceRequestHandler(IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
            //Return null for the default behaviour
            return null;
}

bool IRequestContextHandler.OnBeforePluginLoad(string mimeType, string url, bool isMainFrame, string topOriginUrl, WebPluginInfo pluginInfo, ref PluginPolicy pluginPolicy)
{
    //pluginPolicy = PluginPolicy.Disable;
    //return true;

        return false;
}

void IRequestContextHandler.OnRequestContextInitialized(IRequestContext requestContext)
{
//You can set preferences here on your newly initialized request context.
//Note, there is called on the CEF UI Thread, so you can directly call SetPreference

//Use this to check that settings preferences are working in your code
//You should see the minimum font size is now 24pt
string errorMessage;
var success = requestContext.SetPreference("webkit.webprefs.minimum_font_size", 24, out errorMessage);

//You can set the proxy with code similar to the code below
//https:///questions/36095566/cefsharp-3-set-proxy-at-runtime has some additional examples
//var v = new Dictionary<string, object>
//{
//    ["mode"] = "fixed_servers",
//    ["server"] = "scheme://host:port"
//};
//string errorMessage;
//bool success = requestContext.SetPreference("proxy", v, out errorMessage);
}
}

打印

CEF API僅公開了有限的打印支持。當前不支持在Kiosk模式下打?。ù蛴〉?jīng)]有對話框的默認設(shè)置)。建議的解決方法是先打印,PDF然后使用3rd party應用程序來打印PDF。

如果您需要更好的打印支持,則應在上進行討論ceforum。在CEF問題追蹤器上已經(jīng)有公開的討論和未解決的問題。

高DPI顯示/支持

WinForms/WPF需要使使用DPI的桌面應用程序能夠在高DPI顯示器DPI Scale設(shè)置大于的顯示器)上正確運行DPI100%。

注意如果鼠標光標在瀏覽器中的位置不正確,或者瀏覽器顯示帶有渲染/調(diào)整大小的黑框/邊框,則需要制作您的應用程序DPI Aware。應用程序的其他部分也可能會顯得模糊或尺寸不正確。

有許多選項可用于配置流程的DPI意識:

  1. 通過應用程序清單設(shè)置(通常是首選)
  2. 通過app.config僅限WinForms,目標是.Net 4.7及更高版本)
  3. 通過API調(diào)用以編程方式

Windows 10 1703具有其他改進,有關(guān)更多詳細信息,請參見https://blogs./windowsdeveloper/2017/04/04/high-dpi-scaling-improvements-desktop-applications-windows-10-creators-update/

WinForms高DPI

從.NET Framework 4.7開始,Windows Forms包括針對常見的高DPI和動態(tài)DPI方案的增強功能。在.NET Framework的早期版本中,您使用清單添加了高級DPI支持。不再建議使用此方法,因為它會覆蓋app.config文件中定義的設(shè)置。請確保閱讀Windows窗體中的High DPI支持以獲取Microsoft的更多詳細信息。

應用清單

重要事項?如果您要定位.Net 4.7或以上定位,Microsoft建議DPI Awareness通過app.config而不是進行配置app.manifest。請確保閱讀Windows窗體中的High DPI支持以獲取Microsoft的更多詳細信息。

使用應用程序清單設(shè)置默認感知。以下示例是Win 10 1703及更高版本上的PerMonitor DPI Aware和舊版本上的PerMonitor DPI感知。確保閱讀了https://docs.microsoft.com/zh-cn/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows#dpi-awareness-mode,其中討論了不同的DPI Awareness選項。如果您的項目還沒有app.manifest使用Visual Studio New Item模板,則可以使用模板來添加模板,而不是手動添加模板以確保添加文件中的相關(guān)<ApplicationManifest/>條目csproj/vbproj(這是一種特殊類型)。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        <dpiAware>true/PM</dpiAware>
    </windowsSettings>
</application>
</assembly>

以編程方式

在代碼中設(shè)置高DPI,可以使用Cef.EnableHighDPISupport();。輔助方法。這將調(diào)用Chromium?base :: win :: EnableHighDPISupport();?功能。然后,您將擁有與Chromium用途完全相同的設(shè)置。

Cef.EnableHighDPISupport();?必須在應用程序執(zhí)行的最早期就調(diào)用,最好在應用程序入口點(Program.Main)中調(diào)用。

CefSharp.MinimalExample.WinForms項目包含一個工作的例子。

WPF高DPI

應用清單

添加相關(guān)條目,請參閱app.manifest中針對Microsoft的建議打開Windows級每個監(jiān)視器的DPI感知。

有關(guān)工作示例,請參見https://github.com/cefsharp/CefSharp/blob/cefsharp/84/CefSharp.Wpf.Example/app.manifest了解工作示例。如果您的項目還沒有app.manifest使用Visual Studio New Item模板,則可以使用模板來添加模板,而不是手動添加模板以確保添加文件中的相關(guān)<ApplicationManifest/>條目csproj/vbproj(這是一種特殊類型)。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        <dpiAware>true/PM</dpiAware>
    </windowsSettings>
</application>
</assembly>

以編程方式

WPF默認情況下,應用程序具有自動生成的Program.Main入口點,這使得以編程方式設(shè)置更加困難DPI。有關(guān)如何創(chuàng)建的信息,請參見https:///a/26890426/4583726,Program.Main然后可以調(diào)用Cef.EnableHighDPISupport();。。這?必須在你的應用程序執(zhí)行很早就被調(diào)用,最好在您的自定義Program.Main第一個電話。

屏幕外高DPI

添加相關(guān)app.manifest條目或調(diào)用Cef.EnableHighDPISupport()(請參閱上面的示例)。閱讀WinForms以上部分,選擇適合您需求的選項。

高DPI附加信息

Chromium默認情況下,將在單獨的子流程中執(zhí)行所有渲染。特別是GPU Compositor需要有一個DPI Awareness與您的主應用程序匹配的需求。目前,所使用的默認CefSharp.BrowserSubprocess.exe值為Per Monitor DPI Aware。作為一種解決方法,請使用disable-gpu-compositing命令行arg,并將DPI Awareness使用您的主應用程序進程的,而不是由所DPI Awareness指定的GPU Process(用于GPU Compositing)。禁用GPU Compositing可能會對性能產(chǎn)生影響,當https://github.com/cefsharp/CefSharp/issues/2927完成后,將有可能以編程方式設(shè)置DPI Awareness使用的CefSharp.BrowserSubprocess.exe

var settings = new CefSettings();
settings.CefCommandLineArgs.Add("disable-gpu-compositing");
Cef.Initialize(settings);

另外,您可以嘗試使用force-device-scale-factor?命令行標志。

var settings = new CefSettings();
settings.CefCommandLineArgs.Add("force-device-scale-factor", "1");
Cef.Initialize(settings);

多線程消息循環(huán)

CefSharp默認使用setting.MultiThreadedMessageLoop = true。這使您的應用程序能夠非常快速地啟動并運行,需要注意一些重要的事情,但這可能并不適合所有人。

  • 對消息泵使用其他線程。
  • CEF UI線程與應用程序的UI線程不同,這可能導致消息處理中的某些斷開連接。
    • 一個示例是打開菜單,然后在瀏覽器控件中單擊并使菜單保持打開狀態(tài)。
  • 低級Win32消息不會在CEF和之間傳播WinForms

可以將CEF集成到應用程序的現(xiàn)有消息循環(huán)中。將CEF集成到現(xiàn)有消息循環(huán)中的一種非常簡單的實現(xiàn)涉及在UI線程上使用每秒調(diào)用30/60次的計時器。

var settings = new CefSettings();
settings.MultiThreadedMessageLoop = false; //This defaults to true

Cef.Initialize(settings);

- For WPF use [DispatcherTimer](https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatchertimer?view=netframework-4.8)
- For WinForms use [Timer](https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=netframework-4.8)

//Set the timer Interval to 30 times per second, can be increased to 60 if required
//For WPF
timer.Interval = TimeSpan.FromMilliseconds(1000 / 30);
//For WinForms
timer.Interval = 1000 / 30;
timer.Tick  = UiThreadTimerTick;
timer.Start();

//Before closing your app
//Calling Cef.DoMessageLoopWork() after Cef.Shutdown has been called will result in
//an access violation, make sure you stop you timer first.
timer.Tick -= UiThreadTimerTick;
timer.Stop();

private void UiThreadTimerTick(object sender, EventArgs e)
{
    //Must be called on the UI Thread.
    Cef.DoMessageLoopWork();
}

更高級的選項包括設(shè)置CefSettings.ExternalMessagePump = true;。和實現(xiàn)?IBrowserProcessHandler.OnScheduleMessagePumpWork。這樣可以CEF在需要執(zhí)行工作時發(fā)出通知,在某些情況下,這可能會使您的應用程序響應速度更快。有關(guān)其他詳細信息,請參見https://github.com/cefsharp/CefSharp/issues/1748。項目源代碼中包含更多高級示例。

您可以在使用時掛接消息循環(huán)MultiThreadedMessageLoop,盡管這很復雜。項目源代碼包含一個示例,網(wǎng)址https://github.com/cefsharp/CefSharp/blob/v53.0.0/CefSharp.WinForms.Example/BrowserTabUserControl.cs#L224?您可以使用此方法獲取Win32鼠標消息。

彈出窗口

一個常見的請求是控制彈出窗口的創(chuàng)建。實施ILifeSpanHandler.OnBeforePopup以控制如何創(chuàng)建彈出窗口。要完全取消彈出窗口的創(chuàng)建return true;

bool ILifeSpanHandler.OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
    //Set newBrowser to null unless you're attempting to host the popup in a new instance of ChromiumWebBrowser
    newBrowser = null;

    return true; //Return true to cancel the popup creation
}

您可以取消彈出窗口的創(chuàng)建,然后以新的形式打開URL?ChromiumWebBrowser使用此方法您選擇實例中。重要的是要注意,使用此方法將不存在父子關(guān)系。因此,一般不建議這樣做。

實驗選項1:允許您使用中的newBrowser參數(shù)托管彈出窗口OnBeforePopup。有一些已知問題(在GitHub項目上搜索)。如果您使用此方法遇到問題,那么您將必須承擔責任并通過CEF項目解決該問題。同樣重要的是要注意LoadingStateChangedetc不會被彈出窗口調(diào)用。如果使用此方法,請實現(xiàn)相關(guān)的處理程序。

實驗選項2:IWindowInfo.SetAsChild用于指定父句柄。要在WPF中使用此功能,您將需要使用WinForms主機。使用此方法,您將需要處理move和resize事件。大致如下所示:

  • 抓住IBrowserHost從新創(chuàng)建的IBrowser實例表示彈出然后訂閱窗口移動的通知和呼叫NotifyMoveOrResizeStarted
  • SetWindowPos大小更改時在瀏覽器上調(diào)用HWND(隱藏時設(shè)置為0,0以停止渲染)

盡管它們是實驗性的,但是在項目源中有一些示例,并且不能保證它們在起作用。備選案文2的例子不完整,盡管有報告表明它運作良好,盡管此人從未提供過有效的例子。

JavaScript整合

1.如何從.NET調(diào)用JavaScript方法?

//There are a number of extension methods that simplify execution, they all work on the main frame
//They all exists in the CefSharp.WebBrowserExtensions class, make sure you add "using CefSharp;"
browser.ExecuteScriptAsync("document.body.style.background = 'red';");

// When executing multiple statements, group them together in an IIFE
// https://developer.mozilla.org/en-US/docs/Glossary/IIFE
// For Google.com pre-populate the search text box and click the search button
browser.ExecuteJavaScriptAsync("(function(){ document.getElementsByName('q')[0].value = 'CefSharp Was Here!'; document.getElementsByName('btnK')[0].click(); })();");

如果您的網(wǎng)頁包含多個框架,則可以在子框架上執(zhí)行腳本

browser.GetBrowser().GetFrame("SubFrame").ExecuteJavaScriptAsync("document.body.style.background = 'red';");

我什么時候可以開始執(zhí)行JavaScript?

JavaScript只能在V8Context中執(zhí)行。在IRenderProcessMessageHandler.OnContextCreatedIRenderProcessMessageHandler.OnContextReleased提供時,可以執(zhí)行JavaScript的一個邊界。OnContextCreated/OnContextReleased將每幀調(diào)用一次,用于frame.IsMain檢查主幀。

嘗試開始訪問DOM是很誘人的OnFrameLoadStart,而V8Contextwill已創(chuàng)建,您將能夠執(zhí)行DOM尚未完成加載的腳本。如果您需要DOM盡早訪問,請訂閱DOMContentLoaded,JavaScript下面是一些執(zhí)行示例。

browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();

public class RenderProcessMessageHandler : IRenderProcessMessageHandler
{
  // Wait for the underlying JavaScript Context to be created. This is only called for the main frame.
  // If the page has no JavaScript, no context will be created.
  void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
  {
    const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";

    frame.ExecuteJavaScriptAsync(script);
  }
}

//Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
browser.LoadingStateChanged  = (sender, args) =>
{
  //Wait for the Page to finish loading
  if (args.IsLoading == false)
  {
    browser.ExecuteJavaScriptAsync("alert('All Resources Have Loaded');");
  }
}

//Wait for the MainFrame to finish loading
browser.FrameLoadEnd  = (sender, args) =>
{
  //Wait for the MainFrame to finish loading
  if(args.Frame.IsMain)
  {
    args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
  }
};

有關(guān)執(zhí)行的一些注意事項JavaScript

  • 腳本在框架級別執(zhí)行,并且每個頁面至少有一個框架(MainFrame)。
  • IWebBrowser.ExecuteScriptAsync擴展方法是為了向下兼容性,可以使用它作為快捷方式來執(zhí)行js在主框架上。
  • 如果框架不包含JavaScript,則不會V8Context創(chuàng)建任何框架。
  • 對于沒有上下文的框架,一旦框架加載完成,就可以使用創(chuàng)建V8Context?IFrame.ExecuteJavaScriptAsync。
  • DOM不會已完成加載時OnFrameLoadStart被觸發(fā)
  • IRenderProcessMessageHandler.OnContextCreated/OnContextReleased?僅針對主機。

2.如何調(diào)用返回結(jié)果的JavaScript方法?

如果您需要調(diào)用(評估)返回值的JavaScript,請使用以下方法之一:

//An extension method that evaluates JavaScript against the main frame.
Task<JavascriptResponse> response = await browser.EvaluateScriptAsync(script);
//Evaluate javascript directly against a frame
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync(script);

//An extension method that evaluates Javascript Promise against the main frame.
//Uses Promise.resolve to return the script execution into a promise regardless of the return type
//This method differs from EvaluateScriptAsync in that your script **must return** a value
//Examples below
Task<JavascriptResponse> response = await browser.EvaluateScriptAsPromiseAsync(script);

JavaScript代碼是異步執(zhí)行的,因此返回Task,其中包含錯誤消息,結(jié)果和success(bool)標志。這是評估時需要了解的基本知識JavaScript

  • 確保您閱讀了?何時可以開始執(zhí)行JavaScript?。
  • 腳本在框架級別執(zhí)行,并且每個頁面至少有一個框架(MainFrame)。
  • 腳本在渲染過程中執(zhí)行,并通過進行傳輸IPC,返回出于性能原因所需的數(shù)據(jù)。
  • 支持原始數(shù)據(jù)類型:int,double,date,bool和string。
  • 在某種程度上支持對象,并且將以形式返回對象。支持IDictionary<string, object>使用dynamic關(guān)鍵字來簡化訪問屬性值的過程。
  • 您不能直接返回DOM?Element(或任何具有循環(huán)引用的元素),需要創(chuàng)建一個僅包含您需要返回的信息的新對象。
  • 支持包含上面列出的原語和對象的數(shù)組,它們將以形式返回IList<object>
  • Array LikeHTMLCollection這樣的對象不能直接使用Array.from返回并返回數(shù)組
  • 可以返回的對象圖的復雜度受到限制(當前不支持帶有循環(huán)引用的圖),在這種情況下,您可能需要使用JavaScriptJSON.stringify()方法將JavaScript對象轉(zhuǎn)換為JSON字符串,然后將該字符串返回您的.NET代碼。然后,您可以使用類似JSON.NET的方式將該字符串解碼為.NET對象。有關(guān)更多詳細信息,請參見MDN JSON.stringify。有關(guān)與結(jié)合使用的一些指導,請參見https:///a/46881092/4583726。JSON.stringifyHTMLElement
//Start with something simple, the following will return the value 2 as type int
//Don't use the `return` keyword
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync("1   1");

//A javascript IFFE will be evaluated and it's result returned.
//https://developer.mozilla.org/en-US/docs/Glossary/IIFE
//If you want to execute multiple lines of javascript then an IIFE is recommended to
//avoid any variable scoping issues
var script = @"(function() { let val = 1   1; return val; })();";
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync(script);

//If your script uses a Promise then you must use the EvaluateScriptAsPromiseAsync method, it differs slightly
//in that you must return the value.
//The following will return a Promise that after one second resolves with a simple objec
var script = "return new Promise(function(resolve, reject) { setTimeout(resolve.bind(null, { a: 'CefSharp', b: 42, }), 1000); });"
Task<JavascriptResponse> javascriptResponse = await browser.EvaluateScriptAsPromiseAsync(script);
//You can access the object using the dynamic keyword for convenience.
dynamic result = javascriptResponse.Result;
var a = result.a;
var b = result.b;

//EvaluateScriptAsPromiseAsync calls Promise.resolve internally so even if your code doesn't
//return a Promise it will still execute successfully.
var script = @"return (function() { return 1   1; })();";
Task<JavascriptResponse> response = await frame.EvaluateScriptAsPromiseAsync(script);

// An example that gets the Document Height
var task = frame.EvaluateScriptAsync("(function() { var body = document.body, html = document.documentElement; return  Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); })();");

//Continue execution on the UI Thread
task.ContinueWith(t =>
{
    if (!t.IsFaulted)
    {
        var response = t.Result;
        EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message;
    }
}, TaskScheduler.FromCurrentSynchronizationContext());

//HTMLElement/HTMLCollection Examples
//As stated above, you cannot return a HTMLElement/HTMLCollection directly.
//It's best to return only the data you require, here are some examples of using Array.from to convert a HTMLCollection  into an array of objects
//which can be returned to your .Net application.

//Get all the span elements and create an array that contains their innerText
var script = @"Array.from(document.getElementsByTagName('span')).map(x => ( x.innerText));";
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync(script);

//Get all the a tags and create an array that contains a list of objects 
//Second param is the mapping function
var script = @"Array.from(document.getElementsByTagName('a'), x => ({ innerText : x.innerText, href : x.href }));";
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync(script);

//List of Links, click represents a function pointer which can be used to execute the link click)
//In .Net the https://cefsharp./api/86.0.x/html/T_CefSharp_IJavascriptCallback.htm is used
//to represent the function.
var script = @"Array.from(document.getElementsByTagName('a')).map(x => ({ innerText: x.innerText, click: x.click}));";
Task<JavascriptResponse> response = await frame.EvaluateScriptAsync(script);

//Execute the following against google.com to get the `I'm Feeling Lucky` button then click the button in .Net
//NOTE: This is a simple example, you could return an aggregate object consisting of data from multiple html elements.
const string script = @"(function()
{
  let element = document.getElementsByName('btnI')[0];
  let obj = {};
  obj.id = element.id;
  obj.nodeValue = element.nodeValue;
  obj.localName = element.localName;
  obj.tagName = element.tagName;
  obj.innerText = element.innerText;
  obj.click = element.click;
  obj.attributes = Array.from(element.attributes).map(x => ({name: x.name, value: x.value}));

  return obj;
})();";

var javascriptResponse = await browser.EvaluateScriptAsync(script);
dynamic result = javascriptResponse.Result;
var clickJavascriptCallback = (IJavascriptCallback)result.click;
await clickJavascriptCallback.ExecuteAsync();
//Dispose of the click callback when done
clickJavascriptCallback.Dispose();

3.如何將.NET類公開給JavaScript?

JavaScript的綁定(JSB)允許之間的通信JavaScript.Net。當前有兩個不同的實現(xiàn),Async版本和較舊的Sync版本。該Sync版本不再被積極開發(fā),它依賴于WCF該版本不可用.Net Core或即將發(fā)布.Net 5.0。

異步JavaScript綁定(JSB)

概要

  • 用于Native Chromium IPC在瀏覽器進程和渲染進程之間來回傳遞消息,因此非???。

  • 僅基于消息methods是受支持的,Native Chromium IPC并且只能以某種async方式使用(Property不能以異步方式完成獲取/設(shè)置)

  • Methods可以返回簡單對象,structs并且classes受支持,僅將的副本Properties傳輸?shù)?code>JavaScript。就像webservice/ajax打電話一樣,您會得到一個響應對象。

  • JavaScript callbacks通過IJavascriptCallback支持

  • 所有方法調(diào)用都是非阻塞的,并返回可以是的標準JavaScript Promiseawaited。

  • 默認情況下CamelCase,方法名稱會轉(zhuǎn)換為(第一個字母轉(zhuǎn)換為小寫,MyFunction變?yōu)?code>myFunction)。這可以通過在注冊對象之前設(shè)置browser.JavascriptObjectRepository.NameConverter屬性來配置,將其設(shè)置為null以禁用名稱轉(zhuǎn)換,詳細示例如下。

  • JavaScript Binding API詳細介紹了可用的不同方法。

  • Exceptions.Net被抓住,Promise意志將會被抓住rejected

  • 請參閱高級異步JavaScript綁定(JSB)Wiki,請確保您先閱讀此內(nèi)容。

如果您不熟悉這里提供的所有Chromium內(nèi)容,那么async programming可以參考一些非常有用的文章

綁定Async對象JavaScript

CefSharp.BindObjectAsync方法被稱為在Javascript結(jié)合的對象。CefSharp.BindObjectAsync返回一個Promise,當綁定的對象可用時,該Promise將被解決。在全局上下文(window對象的屬性)中創(chuàng)建對象。如果調(diào)用時CefSharp.BindObjectAsync沒有任何參數(shù),則所有已注冊的對象都將被綁定。名稱綁定是更具描述性的選項。

簡單的工作流程如下所示:

  • 第1步:創(chuàng)建一個您希望公開使用javascript的類(不要使用您的Form/WindowControl
  • 步驟2向您的課程注冊一個實例JavaScriptObjectRepository
  • 步驟3使用您要注冊的對象的名稱來調(diào)用(對象只有在Promise解析后才可用。

僅支持方法。如果需要設(shè)置屬性,則創(chuàng)建Get/Set方法。

步驟1建立課程

一個簡單的類如下所示:

public class BoundObject
{
    public int Add(int a, int b)
    {
        return a   b;
    }
}

步驟2向您的課程注冊一個實例JavaScriptObjectRepository

該過程的第二部分是向中注冊對象JavascriptObjectRepository(可通過browser.JavascriptObjectRepository屬性訪問)。您有兩個選項用于在中注冊對象.Net,第一個選項是預先注冊的,通常在創(chuàng)建ChromiumWebBrowser實例后立即完成。第二個選項更加靈活,并允許Resolved在需要時放置對象。

第一種選擇:

//For async object registration (equivalent to the old RegisterAsyncJsObject)
browser.JavascriptObjectRepository.Register("boundAsync", new BoundObject(), true, BindingOptions.DefaultBinder);

第二種選擇(首選)

browser.JavascriptObjectRepository.ResolveObject  = (sender, e) =>
{
var repo = e.ObjectRepository;
if (e.ObjectName == "boundAsync")
{
BindingOptions bindingOptions = null; //Binding options is an optional param, defaults to null
bindingOptions = BindingOptions.DefaultBinder //Use the default binder to serialize values into complex objects
bindingOptions = new BindingOptions { Binder = new MyCustomBinder() }); //Specify a custom binder
repo.NameConverter = null; //No CamelCase of Javascript Names
//For backwards compatability reasons the default NameConverter doesn't change the case of the objects returned from methods calls.
//https://github.com/cefsharp/CefSharp/issues/2442
//Use the new name converter to bound object method names and property names of returned objects converted to camelCase
repo.NameConverter = new CamelCaseJavascriptNameConverter();
repo.Register("boundAsync", new BoundObject(), isAsync: true, options: bindingOptions);
}
};

要在.Net綁定對象時得到通知,JavaScript您可以訂閱ObjectBoundInJavascript事件或ObjectsBoundInJavascript事件(這兩個事件顯然非常相似)。

browser.JavascriptObjectRepository.ObjectBoundInJavascript  = (sender, e) =>
{
var name = e.ObjectName;

Debug.WriteLine($"Object {e.ObjectName} was bound successfully.");
};   

步驟3呼叫CefSharp.BindObjectAsync

<script type="text/javascript">
(async function()
{
await CefSharp.BindObjectAsync("boundAsync");

//The default is to camel case method names (the first letter of the method name is changed to lowercase)
boundAsync.add(16, 2).then(function (actualResult)
{
const expectedResult = 18;
assert.equal(expectedResult, actualResult, "Add 16   2 resulted in "   expectedResult);
});
})();
</script>

進行CefSharp.BindObjectAsync調(diào)用時,將JavascriptObjectRepository查詢以查看是否已注冊具有給定名稱的對象,如果未找到匹配的對象,ResolveObject則引發(fā)該事件。對于不帶任何參數(shù)的CefSharp.BindObjectAsync調(diào)用,則如果已注冊對象,則將它們?nèi)拷壎ǎ绻醋詫ο?,則將ResolveObjectObjectName設(shè)置為All

本節(jié)僅介紹基礎(chǔ)知識,還有許多高級選項,請查看高級異步Javascript綁定。

如果您想查看一個可行的示例,請查看CefSharp MinimalExample Javascript Binding Demo分支,特別是commit


同步JavaScript綁定(JSB)

這是一個遺產(chǎn)功能-任何正在創(chuàng)建新應用程序的人都在使用Async JavaScript Binding(JSB)實現(xiàn),因為它正在積極開發(fā)中。該Sync版本僅會收到針對回歸的錯誤修復。

  • 使用WCF通信服務(wù)(微軟還沒有為支持WCF.Net Core/.Net 5.0,有沒有長遠的未來WCF)。
  • 同時支持方法和屬性
  • 呼叫以某種sync方式執(zhí)行且正在阻塞,長時間運行的呼叫會阻塞Render Process并導致您的應用顯示緩慢或無響應。
  • 支持半復雜的對象結(jié)構(gòu)
  • 有時,該WCF服務(wù)無法完全關(guān)閉,并減慢了應用程序的關(guān)閉速度

綁定對象?JavaScript

綁定是由JavaScript啟動的,當綁定的對象可用時,該CefSharp.BindObjectAsync方法將返回Promise解析的結(jié)果。在全局上下文(window對象的屬性)中創(chuàng)建對象。如果調(diào)用時CefSharp.BindObjectAsync沒有任何參數(shù),則所有已注冊的對象都將被綁定。名稱綁定是更具描述性的選項。

簡單的工作流程如下所示:

  • 第1步創(chuàng)建一個您希望向JavaScript公開的類(不要使用您的Form/WindowControl
  • 步驟2CefSharp.BindObjectAsync使用您要注冊的對象的名稱進行調(diào)用,例如CefSharp.BindObjectAsync("myObject");(對象只有在Promise解析后才能使用。
  • 步驟3JavaScriptObjectRepository

步驟1

public class BoundObject
{
    public string MyProperty { get; set; }
    public void MyMethod()
    {
        // Do something really cool here.
    }
    
    public void TestCallback(IJavascriptCallback javascriptCallback)
    {
        const int taskDelay = 1500;

        Task.Run(async () =>
        {
            await Task.Delay(taskDelay);

            using (javascriptCallback)
            {
                //NOTE: Classes are not supported, simple structs are
                var response = new CallbackResponseStruct("This callback from C# was delayed "   taskDelay   "ms");
                await javascriptCallback.ExecuteAsync(response);
            }
        });
    }
}

步驟2調(diào)用CefSharp.BindObjectAsync,下面Binding的對象示例如下所示:

注意這是一個兩部分的過程,有關(guān)詳細信息,請參見下面的示例

<script type="text/javascript">
(async function()
{
await CefSharp.BindObjectAsync("boundAsync");

boundAsync.div(16, 2).then(function (actualResult)
{
const expectedResult = 8
assert.equal(expectedResult, actualResult, "Divide 16 / 2 resulted in "   expectedResult);
});

boundAsync.error().catch(function (e)
    {
        var msg = "Error: "   e   "("   Date()   ")";
    });
})();

(async () =>
{
await CefSharp.BindObjectAsync("boundAsync");

boundAsync.hello('CefSharp').then(function (res)
{
assert.equal(res, "Hello CefSharp")
});
})();

CefSharp.BindObjectAsync("boundAsync2").then(function(result)
{
boundAsync2.hello('CefSharp').then(function (res)
{
assert.equal(res, "Hello CefSharp")
                // NOTE the ability to delete a bound object
assert.equal(true, CefSharp.DeleteBoundObject("boundAsync2"), "Object was unbound");
assert.ok(window.boundAsync2 === undefined, "boundAsync2 is now undefined");
});
});
</script>

第三步

該過程的第二部分是將對象注冊為JavascriptObjectRepository(可通過browser.JavascriptObjectRepository屬性訪問)。您有兩個選項用于在中注冊對象.Net,第一個選項是預先注冊的,通常在創(chuàng)建ChromiumWebBrowser實例后立即完成。第二個選項更加靈活,并允許Resolved在需要時放置對象。

進行CefSharp.BindObjectAsync調(diào)用時,JavascriptObjectRepositoryis查詢查詢是否已指定給定名稱的對象,如果找不到匹配的對象,ResolveObject則引發(fā)該事件。對于CefSharp.BindObjectAsync不帶任何參數(shù)的調(diào)用,則如果已經(jīng)注冊了對象,則將它們?nèi)拷壎?,如果沒有注冊任何對象,則將ResolveObjectObjectName設(shè)置為All。

//When a 
browser.JavascriptObjectRepository.ResolveObject  = (sender, e) =>
{
var repo = e.ObjectRepository;
if (e.ObjectName == "boundAsync2")
{
BindingOptions bindingOptions = null; //Binding options is an optional param, defaults to null
bindingOptions = BindingOptions.DefaultBinder //Use the default binder to serialize values into complex objects,
bindingOptions = new BindingOptions { Binder = new MyCustomBinder() }); //No camelcase of names and specify a custom binder
//For backwards compatability reasons the default NameConverter doesn't change the case of the objects returned from methods calls.
//https://github.com/cefsharp/CefSharp/issues/2442
//Use the new name converter to bound object method names and property names of returned objects converted to camelCase
repo.NameConverter = new CamelCaseJavascriptNameConverter();
repo.Register("bound", new BoundObject(), isAsync: false, options: bindingOptions);
}
};

在實際的JS代碼中,您將使用這樣的對象(默認為CamelCase Javascript Names,可通過JavascriptObjectRepository.NameConverter進行控制,請參見上面的示例)。

bound.myProperty; // use this syntax to access the property
bound.myMethod(); // use this to call the method.
bound.testCallback(callback); //Pass a function in to use as a callback

請注意:

  • 不要注冊表格/窗口/控件。如果需要,創(chuàng)建一個類并代理調(diào)用。
  • 默認情況下,方法和屬性都更改為camelCase(即首字母小寫)以使其在JavaScript代碼中自然使用。禁用將browser.JavascriptObjectRepository.NameConverter設(shè)置為null
  • 屬性支持復雜對象(如果適用),因此您現(xiàn)在可以執(zhí)行bound.subObject.myFunction()bound.subObject.myProperty = 1
  • 現(xiàn)在可以通過IBinder接口實現(xiàn)對函數(shù)的復雜對象支持,您可以實現(xiàn)自己的或使用DefaultBinder例如repo.Register("bound", new BoundObject(), BindingOptions.DefaultBinder);

RegisterAsyncJsObject

此方法已刪除。請參閱異步JavaScript綁定(JSB)。

RegisterJsObject

這已被刪除。請參閱同步JavaScript綁定(JSB)

Adobe Flash Player(Pepper Flash)

注意:現(xiàn)在不建議使用Flash,并且Chromium將刪除支持,有關(guān)更多詳細信息,請參閱https://www./flash-roadmap#TOC-Upcoming-Changes。從版本開始,81默認情況下現(xiàn)在已禁用它,請參見https://github.com/cefsharp/CefSharp/issues/3048#issuecomment-592263009

CefSharp可以從Adobe下載可以自動發(fā)現(xiàn)并加載的Pepper Flash的系統(tǒng)范圍安裝。從下拉列表中選擇FP for Opera and Chromium-PPAPI版本。要測試Flash是否正常運行,只需加載http://www.adobe.com/software/flash/about/。

注意首次打開Flash時,將短暫顯示控制臺窗口,顯示NOT SANDBOXED。有一個問題Chromium問題跟蹤,但不幸的是Google已經(jīng)將其標記為WontFix。一些聰明的人一起破解了一些解決方法。它們很復雜,我從未嘗試過。請訪問https://github.com/cefsharp/CefSharp/issues/1259中的鏈接以獲取詳細信息。

屏幕外渲染(OSR)

WPF和OffScreen版本使用OffScreen Rendering(OSR)渲染模式。在OSR模式每幀被渲染到緩沖器中,然后在屏幕上或者繪制為在WPF的情況下,或提供作為BitmapOffScreen

WPF

對于WPF控件,用戶輸入(鼠標單擊/移動和按鍵)將通過IBrowserHost界面上的方法轉(zhuǎn)發(fā)到基礎(chǔ)瀏覽器。可以訪問每個Bitmap渲染的對象。

應特別注意ChromiumWebBrowser在內(nèi)托管ViewBox。這遠非理想,因為渲染了每一幀,然后進行后處理來調(diào)整圖像的大小/縮放。這會嚴重影響性能,并且通常會降低質(zhì)量(通常很模糊)。您可以使用調(diào)整調(diào)整大小的質(zhì)量RenderOptions.SetBitmapScalingMode。最好避免使用ViewBox。您可以通過調(diào)整來縮放瀏覽器中包含的內(nèi)容ZoomLevel,這是迄今為止性能最高的選項。

屏幕外

對于CefSharp.OffScreen包裝,將每個幀渲染到Bitmap并暴露以供使用。如果希望通過鍵盤或鼠標與瀏覽器進行交互,則可以使用IBrowser主機界面上的方法。模擬按鍵和鼠標單擊/移動可能非常復雜。您可以使用WPF控件作為開始示例,因為它使用相同的方法(添加調(diào)試以查看所需的事件順序)。按鍵和鼠標的點擊/移動通常由多個部件,up/down與許多其它可能的組合。

用戶代理

您可以通過設(shè)置https://cefsharp./api/86.0.x/html/P_CefSharp_CefSettingsBase_UserAgent.htm來指定自定義UserAgent

UserAgent可以在運行時使用DevTools協(xié)議來改變看到https:///a/64543667/4583726的一個例子。

您可以在中修改User-AgentHTTP標頭IResourceRequestHandler.OnBeforeResourceLoad,這對于每個請求都需要完成。它不做的是UserAgent將瀏覽器報告更改為JavaScript。

public class CustomResourceRequestHandler : CefSharp.Handler.ResourceRequestHandler
{
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
{
//Set the header by name, override the existing value
request.SetHeaderByName("user-agent", "MyBrowser CefSharp Browser", true);

return CefReturnValue.Continue;
}
}

public class CustomRequestHandler : CefSharp.Handler.RequestHandler
{
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
//Where possible only intercept specific Url's
//Load https://www./detect/what-is-my-user-agent in the browser and you'll
//see our custom user agent
if (request.Url == "https://www./detect/what-is-my-user-agent")
{
return new CustomResourceRequestHandler();
}

//Default behaviour, url will be loaded normally.
return null;
}
}

browser.RequestHandler = new CustomRequestHandler();

開發(fā)工具

您可以從CefSharp中打開DevTools。并非所有功能都起作用。任何缺少的東西都需要在CEF中實施。

browser.ShowDevTools();

您可以將Chrome連接到正在運行的實例。這可能會為您提供更多選項(不幸的是,并非Chrome中存在所有選項)。

var settings = new CefSettings();
settings.RemoteDebuggingPort = 8088;
Cef.Initialize(settings);

http://localhost:8088在Chrome中打開。

屏幕截圖

底層的CEF Web瀏覽器不是特別適合于截屏。以下是一些注意事項和警告:

屏幕外/ WPF

無論OffscreenWPF使用的屏幕外著色(OSR),其中每一幀被渲染為位圖。它仍然是一個網(wǎng)絡(luò)瀏覽器,并不是特別適合這種情況。這里有一些注意事項:

  • 降低幀頻以使其更容易捕獲幀可能值得考慮
  • 頁面加載完成后,您需要等待一段時間,以允許瀏覽器呈現(xiàn)
  • 當前尚無確定網(wǎng)頁何時完成渲染的方法(Flash,動態(tài)內(nèi)容,動畫等功能,甚至像移動鼠標或滾動之類的簡單任務(wù)也將導致渲染新幀)。
  • 一種確定何時大致完成渲染的破解方法是讓計時器在每次渲染幀時重置,如果沒有其他幀渲染,則計時器將歸檔(不理想)

WinForms

這是在Windows下拍攝屏幕快照的一些示例

Win32內(nèi)存不足

使用32bit版本時,請確保您的應用程序支持大地址(處理大于2gb的地址)

根據(jù)http:///ceforum/viewtopic.php?f=6&t=15120#p34802中的建議,現(xiàn)在看來有必要在32位應用程序運行時在應用程序可執(zhí)行文件上設(shè)置“大地址感知”鏈接器設(shè)置。遇到高內(nèi)存負載。

https://msdn.microsoft.com/zh-CN/library/wz223b1z.aspx

CefSharp附帶的默認x86 SubProcess可以識別大型地址,您也應該使應用程序識別。

將大地址感知鏈接器設(shè)置應用于可執(zhí)行文件后,如果仍然遇到完全相同的問題,請在http:///ceforum/viewtopic.php?f=6&t=15120上討論您的問題。

使用PostData加載URL

有兩種加載URL的方法Post Data,第一種是修改現(xiàn)有的Request。在下面的示例中,Request如果我們訪問http:///post,我們會將發(fā)布數(shù)據(jù)添加到

public class CustomRequestHandler : CefSharp.Handler.RequestHandler
{
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
//Where possible only intercept specific Url's
//Load http:///post in the browser and you'll
//see the post data
if (request.Url == "http:///post")
{
return new CustomResourceRequestHandler();
}

//Default behaviour, url will be loaded normally.
return null;
}
}

public class CustomResourceRequestHandler : CefSharp.Handler.ResourceRequestHandler
{
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
{
//Modify the request to add post data
//Make sure to read https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
var postData = new PostData();

postData.AddData("test=123&data=456");

request.Method = "POST";
request.PostData = postData;
//Set the Content-Type header to whatever suites your requirement
request.SetHeaderByName("Content-Type", "application/x-www-form-urlencoded", true);
//Set additional Request headers as required.

return CefReturnValue.Continue;
}
}

//Load http:///post in the browser to see the post data
browser = new ChromiumWebBrowser("http:///post");
browser.RequestHandler = new CustomRequestHandler();

第二種方法是使用IFrame.LoadRequest,僅當您首次成功執(zhí)行導航后才能使用此方法。例如,您必須先導航到google.com,然后才能調(diào)用IFrame.LoadRequest。加載about:blank是不夠的,因為它是特例,并且不會產(chǎn)生渲染過程。

public void LoadCustomRequestExample()
{
var frame = browser.GetMainFrame();

//Create a new request knowing we'd like to use PostData
var request = frame.CreateRequest(initializePostData:true);
request.Method = "POST";
request.Url = "http:///post";
        //Set AllowStoredCredentials so cookies are sent with Request
        request.Flags = UrlRequestFlags.AllowStoredCredentials;
request.PostData.AddData("test=123&data=456");

frame.LoadRequest(request);
}

browser.LoadUrlWithPostData擴展方法可用于簡單的情況下,它會調(diào)用LoadRequest并針對具有相同的限制進行了成功的導航應用。

拼寫檢查

默認情況下CefSettings.Locale將指示使用哪個字典,默認為en-US??梢栽谶\行中配置拼寫檢查的許多方面,enable/disable在運行中進行更改dictionary,甚至啟用多個詞典。使用RequestContext.SetPreference(有關(guān)RequestContext如何設(shè)置首選項的詳細信息,請參閱本文檔的部分)。

只能使用spellcheck.dictionaries首選項(重要的是使用復數(shù)版本)?動態(tài)地更改拼寫檢查https:///chromiumembedded/cef/issues/2222/spell-checking-language-cannot-be-changed#comment-38338016

這是一些有用的鏈接

http:///ceforum/viewtopic.php?f=6&t=14911&p=33882&hilit=spellcheck#p33882?https://cs./chromium/src/components/spellcheck/browser/pref_names.cc?type = cs&q =%22spellcheck.dictionary%22&l = 11?https://cs./chromium/src/components/spellcheck/browser/pref_names.cc?type=cs&q="spellcheck.dictionary"&l=15

并非所有語言都支持拼寫檢查,請參閱https:///ceforum/viewtopic.php?f=6&t=16508#p40684

Web組裝

在較新的版本中默認為啟用,請參見https://www./feature/5453022515691520

對于較舊的版本,您需要手動啟用,WebAssembly請參見https:///chromiumembedded/cef/issues/2101/add-webassembly-support

settings.javascript_flags?轉(zhuǎn)換為?settings.JavascriptFlags = "--expose-wasm";

異常處理

捕獲非托管異常非常困難,并且CEF可能處于損壞狀態(tài),需要您的應用程序終止并重新啟動。由于這是一個一般的編程主題,因此不在本文的CefSharp特別討論范圍之內(nèi),因此有一些資源可幫助您開始自己進行研究。

http:///questions/233255/how-does-setunhandledexceptionfilter-work-in-net-winforms-applications?https://msdn.microsoft.com/zh-CN/library/windows/desktop/ms680634(v = vs.85).aspx?https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Application.cs,8243b844777a16c3?https://referencesource.microsoft.com/#System。 Windows.Forms / winforms / Managed / System / WinForms / Application.cs,3192

在混合的本地/ CLR環(huán)境中捕獲未處理的異常?http://www./blog/?p=1440

依賴檢查

CefSharp?有一個非常簡單的類,用于檢查是否存在所有相關(guān)的非托管資源。

//Perform dependency check to make sure all relevant resources are in our output directory.
//https://cefsharp./api/86.0.x/html/M_CefSharp_Cef_Initialize_1.htm
Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);

//Manually check
//https://cefsharp./api/86.0.x/html/T_CefSharp_DependencyChecker.htm
DependencyChecker.AssertAllDependenciesPresent(cefSettings.Locale, cefSettings.LocalesDirPath, cefSettings.ResourcesDirPath, cefSettings.PackLoadingDisabled, cefSettings.BrowserSubprocessPath);

這不是100%萬無一失的,如果您遇到問題并且所有資源都存在,請禁用依賴性檢查。在某些情況下,它不起作用。

https://github.com/cefsharp/CefSharp/wiki/Output-files-description-table-(Redistribution)

多媒體(音頻/視頻)

CEF并且隨后CefSharp僅支持免費提供的音頻和視頻編解碼器。要查看CefSharp您所使用的版本支持,ChromiumWebBrowser實例中打開http:///。

  • MP3專利已過期,因此受65.0.0病房支持。
  • H264/AAC被歸類為Proprietary Codecs并且不受支持,它們要求您獲得許可。喜歡Netflix/Twitter/Instagram使用的網(wǎng)站H264,其視頻因此無法播放。請參閱https://www./licensing/h264-patent-license,以獲取Free Software Foundation有關(guān)該主題的一些評論。

CEF對的支持編譯H264/AAC超出了該項目的范圍。以下內(nèi)容僅供參考,請不要尋求支持CEF。

屏幕(虛擬)鍵盤

WinForms版本已經(jīng)內(nèi)置在屏幕鍵盤的支持,它已經(jīng)報道,有時它并不總是正確彈出,使用disable-usb-keyboard-detect命令行參數(shù)?https://github.com/cefsharp/CefSharp/issues/1691#issuecomment-323603277報道解決這個問題。

WPF屏幕版本(虛擬)開始,它沒有內(nèi)置的支持,從版本開始,73VirtualKeyboardRequested事件現(xiàn)在會在您的應用程序應顯示虛擬鍵盤時提供通知。不幸的是,Windows 7, 8.1 and 10由于沒有.Net API顯示虛擬鍵盤的功能,因此很難提供支持的默認實現(xiàn)。Windows 10 Onlyhttps://github.com/cefsharp/CefSharp/commit/0b57e526158e57e522d46671404c557256529416中添加了一個示例如果您需要支持,Windows 8 and 10https://github.com/maximcus/WPFTabTip可能會有用。對于Windows 7?https:///questions/1168203/incorporating-the-windows-7-onscreen-keyboard-into-a-wpf-app有一些建議。

?

來源:https://www./content-4-771401.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    色婷婷成人精品综合一区| 国产精品亚洲欧美一区麻豆| 欧美中文字幕一区在线| 熟妇人妻av中文字幕老熟妇| 色涩一区二区三区四区| 国产日产欧美精品大秀| 欧美日韩国产精品黄片| 九九九热视频免费观看| 欧美日韩黑人免费观看| 在线观看视频国产你懂的| 欧美丰满人妻少妇精品| 激情丁香激情五月婷婷| 福利视频一区二区在线| 深夜视频在线观看免费你懂| 精品欧美日韩一区二区三区| 97人妻精品免费一区二区| 玩弄人妻少妇一区二区桃花| 日韩国产中文在线视频| 日韩中文无线码在线视频| 国产精品第一香蕉视频| 亚洲专区一区中文字幕| 色综合视频一区二区观看| 日本99精品在线观看| 国产在线小视频你懂的| 91福利免费一区二区三区| 自拍偷女厕所拍偷区亚洲综合| 日韩特级黄色大片在线观看| 亚洲国产性生活高潮免费视频| 亚洲中文字幕在线观看黑人| 国内外免费在线激情视频| 在线亚洲成人中文字幕高清| 在线免费不卡亚洲国产| 日本高清中文精品在线不卡| 日韩免费av一区二区三区| av在线免费播放一区二区| 欧美中文日韩一区久久| 中文字幕高清免费日韩视频| 国产一区二区精品丝袜| 日韩精品你懂的在线观看| 中文字幕在线五月婷婷| 日韩1区二区三区麻豆|