首先先介紹一下CefSharp嵌入式瀏覽器,它是基於Google瀏覽器的一個組件,我們可以在WPF/WinForm用戶端軟體中使用它。CefSharp的代碼託管在GitHub上,.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework。
目前最新版本的CefSharp是41.0版本,如果你的用戶端軟體需要支援WIN XP作業系統,建議使用CefSharp.Wpf 1.25.7及之前的版本。可以從Nuget上擷取到具體的內容。在新版本的CefSharp中,已經取消了對WIN XP系統的支援。
具體的實現:(首先引用CefSharp.dll,CefSharp.Wpf.dll 另外將icudt.dll,libcef.dll這兩個Dll放置在bin/Debug或者bin/Release目錄下)
先建立一個UserControl,並繼承IRequestHandler介面,代碼如下:
UI:
<UserControl x:Class="EmbeddedWebBrowserSolution.WebPageViewer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:EmbeddedWebBrowserSolution" xmlns:uc="clr-namespace:EmbeddedWebBrowserSolution" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid x:Name="MainGrid"> <uc:MaskLoading x:Name="maskLoading"/> </Grid></UserControl>
Code:
public partial class WebPageViewer : UserControl, IRequestHandler{ private WebView _view; public WebPageViewer(string url) { InitializeComponent(); CEF.Initialize(new Settings { LogSeverity = LogSeverity.Disable, PackLoadingDisabled = true }); BrowserSettings browserSetting = new BrowserSettings { ApplicationCacheDisabled = true, PageCacheDisabled = true }; _view = new WebView(string.Empty, browserSetting) { Address = url, RequestHandler = this, Background = Brushes.White }; _view.LoadCompleted += _view_LoadCompleted; MainGrid.Children.Insert(0, _view); } private void _view_LoadCompleted(object sender, LoadCompletedEventArgs url) { Dispatcher.BeginInvoke(new Action(() => { maskLoading.Visibility = Visibility.Collapsed; })); } public void View(string url) { if(_view.IsBrowserInitialized) { _view.Visibility = Visibility.Hidden; maskLoading.Visibility = Visibility.Visible; _view.Load(url); } } #region IRequestHandler public bool GetAuthCredentials(IWebBrowser browser, bool isProxy, string host, int port, string realm, string scheme, ref string username, ref string password) { return false; } public bool GetDownloadHandler(IWebBrowser browser, string mimeType, string fileName, long contentLength, ref IDownloadHandler handler) { return true; } public bool OnBeforeBrowse(IWebBrowser browser, IRequest request, NavigationType naigationvType, bool isRedirect) { return false; } public bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse) { return false; } public void OnResourceResponse(IWebBrowser browser, string url, int status, string statusText, string mimeType, WebHeaderCollection headers) { } #endregion}
下一步,在MainWindow上來承載,
UI:
<Grid> <DockPanel> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <TextBlock Text="Address:" Margin="5"/> <TextBox x:Name="txtAddress" Width="350" Margin="5"/> <Button Content="Go" Margin="5" Click="OnGoClick" IsDefault="True"/> </StackPanel> <Grid x:Name="MainGrid"> </Grid> </DockPanel></Grid>Code:private void OnGoClick(object sender, RoutedEventArgs e){ string url = txtAddress.Text; if (!string.IsNullOrWhiteSpace(url)) { WebPageViewer viewer = new WebPageViewer(url); MainGrid.Children.Insert(0,viewer); }}
注意,需要將工程Platform Target設定為X86。
運行效果:
到這裡,一個使用CefSharp來承載Web頁面的例子就算完成了。
相比於WPF內建的WebBrowser,CefSharp在處理JS回掉時,比WebBrowser方便很多。請看下面的例子:
我們有這樣一個HTML頁面:
<!DOCTYPE html><html><head> <title></title> <meta charset="utf-8" /> <script type="text/javascript"> function callback() { callbackObj.showMessage('message from js'); } </script></head><body> <input type="button" value="Click" onclick="callback()" ID="Button"></body></html>
增加一個類,叫做:CallbackObjectForJs
public class CallbackObjectForJs{ public void showMessage(string msg) { MessageBox.Show(msg); }}
注意這個方法的名稱必須小寫。
改造一下WebPageViewer類,在構造後WebView之後,註冊一個JS對象,
//...public WebPageViewer(string url){ InitializeComponent(); CEF.Initialize(new Settings { LogSeverity = LogSeverity.Disable, PackLoadingDisabled = true }); BrowserSettings browserSetting = new BrowserSettings { ApplicationCacheDisabled = true, PageCacheDisabled = true }; _view = new WebView(string.Empty, browserSetting) { Address = url, RequestHandler = this, Background = Brushes.White }; _view.RegisterJsObject("callbackObj", new CallbackObjectForJs()); _view.LoadCompleted += _view_LoadCompleted; MainGrid.Children.Insert(0, _view);} //...
運行效果如下:
通過這樣的方式,我們可以很好的實現Web頁面與用戶端程式之間的互動。
使用CefSharp在.Net程式中嵌入Chrome瀏覽器
有的時候,我們需要在程式中嵌入Web瀏覽器,其實.Net Framework中本身就提供了WebBrowser控制項,本身這個是最簡單易用的方案,但不知道是什麼原因,這個控制項在瀏覽網頁的時候有些莫名的卡頓,有的時候甚至能達到好幾秒,嚴重影響體驗。
這個時候,我們可以考慮使用第三方瀏覽器來代替系統的WebBrowser,常見的方案是使用版本帝Chrome,Chrome本身提供了供第三方程式嵌入的方案Chromium Embedded Framework (CEF),但這個是C++的介面,在.Net程式中使用還是有一定的工作量的。不過目前已經有一些開源的項目完成了這一封裝,其中的一個佼佼者就是CefSharp,WPF和WinForm的封裝都實現了,本文就簡單的介紹一下如何在WPF程式中使用CefSharp來嵌入Chrome瀏覽器。
安裝:
安裝的過程非常簡單,只要使用NuGet安裝CefSharp.Wpf即可。
PM> Install-Package CefSharp.Wpf
安裝過程本身比較常規,不過值得一提的是,這個包非常大,由於整合了x86和x64的版本,整個包(加上幾個依賴的包)達到了200多mb,基於眾所周知的原因,和Nuget的訪問一直不大通暢,有時還抽風整個過程非常漫長,一定要有足夠的耐心以及人品。
修改編譯選項:
由於Chrome是原生程式,目前CefSharp還不能做到32位和64位自動識別,不能使用預設的AnyCPU的編譯選項,需要修改一下組態管理員,改成x86或x64才行。
使用:
使用的過程比較簡單,直接使用如下代碼即可。
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var setting = new CefSharp.CefSettings();
CefSharp.Cef.Initialize(setting, true, false);
var webView = new CefSharp.Wpf.ChromiumWebBrowser();
this.Content = webView;
webView.Address = "http://www.cnblogs.com/TianFang/";
}
我們可以看到在使用Chrome控制項前,有如下一個操作:
var setting = new CefSharp.CefSettings();
CefSharp.Cef.Initialize(setting, true, false);
這個setting變數就是用來存放chrome的全域設定的地方,當需要進行設定的時候,只需要對它進行修改即可。例如,我們要修改緩衝目錄,只需要如下設定即可:
var setting = new CefSharp.CefSettings()
{
CachePath = Directory.GetCurrentDirectory() + @"\Cache",
};
另外,有的設定是通過啟動參數傳入的,這些啟動參數存放在CefCommandLineArgs成員中了,通過字串的形式傳入。例如,我們要給Chrome程式加一個Proxy 伺服器,則可以修改如下:
setting.CefCommandLineArgs.Add("--proxy-server", "http://127.0.0.1:8877");