javascript
在WPF程序中打开网页:使用代理服务器并可进行JS交互
??? 本項目環境:使用VS2010(C#)編寫的WPF程序,通過CefSharp在程序的窗體中打開網頁。需要能夠實現網頁后臺JS代碼中調用的方法,從網頁接收數據,并能返回數據給網頁。運行程序的電腦不允許上網,要求通過局域網內一個指定的代理服務器聯網,并且只有該程序能通過代理服務器打開網頁,直接用瀏覽器或其他應用程序仍然不允許上網(因此不能直接更改本機的LAN設置)。
??? 首先介紹一下CefSharp,它是基于Google瀏覽器的一個組件,是可以用在WPF/WinForm客戶端軟件中的嵌入式瀏覽器。
??? 如果你只需要通過客戶端軟件的一個窗體打開現成的網頁,那么方法還是比較簡單的,你可以直接參考http://***/Article/54798這篇文章。
?
1、配置環境,加載CefSharp動態庫
首先需要下載NuGet插件,它是免費、開源的包管理開發工具,專注于在 .NET 應用開發過程中,簡單地合并第三方的組件庫。使用該工具可以將CefSharp的完整程序包加載到工程中。下載地址:http://xz.cr173.com/soft2/nuget.tools.zip。
本項目是用VS2010編寫的,因此運行NuGet.Tools? for vs2010,安裝后,在VS的“工具”菜單下會多出一項“NuGet程序包管理器”,見下圖所示:
新建工程文件EmbeddedWebBrowser。點擊“管理解決方案的NuGet程序包”,打開如下圖所示的窗體:
在右上角聯機搜索“CefSharp”,下載CefSharp.Wpf和CefSharp.Common。如果你用的不是WPF,而是WinForm,則需要下載CefSharp.WinForms和CefSharp.Common。下載的過程比較慢,網速不佳的情況下大概要一個小時左右。安裝完成后,在工程文件所在目錄下會多出“packages”目錄。
?
2、MainWindow窗體:用于輸入網頁地址和初始化Cef
在工程文件中的MainWindow窗體中,添加一個用于輸入網頁地址的編輯框,和一個用于打開網頁的按鈕。MainWindow.xaml的代碼如下所示:
<Window x:Class="EmbeddedWebBrowser.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow" Height="350" Width="800" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded"><Grid><DockPanel><StackPanel DockPanel.Dock="Top" Orientation="Horizontal"><TextBlock Text="網頁地址:" 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> </Window>該頁面的后臺代碼MainWindow.xaml.cs如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using CefSharp;namespace EmbeddedWebBrowser {/// <summary>/// MainWindow.xaml 的交互邏輯/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}/// <summary>/// 窗體加載事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Window_Loaded(object sender, RoutedEventArgs e){
//默認打開的頁面txtAddress.Text = "http://www.baidu.com/";//txtAddress.Text = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName.Replace("EmbeddedWebBrowser.vshost.exe", "index.html");
//設置代理服務器var setting = new CefSharp.CefSettings();setting.CefCommandLineArgs.Add("--proxy-server", "http://192.168.0.105:3128");
CefSharp.Cef.Initialize(setting, true, false); }/// <summary>/// “Go”按鈕單擊事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>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);}}} }
這里最關鍵的就是:setting.CefCommandLineArgs.Add("--proxy-server", "http://192.168.0.105:3128");這是用來設置代理服務器的IP和端口的。
???? CefSharp.Cef.Initialize(setting, true, false); 用來初始化CEF,即嵌入式瀏覽器。
2016-04-18補充:CefSharp.Cef.Initialize方法在程序里只能使用一次,如果把它寫在一個會多次打開的子頁面,就會報錯:“只能初始化一次”。因此需要將這個方法寫在主程序App.cs里。并且在程序退出前使用:CefSharp.Cef.Shutdown();否則程序關閉之后,可能會由于CefSharp.Cef未關閉,而使得該程序仍然存在后臺進程中(可在任務管理器中查看),影響再次打開程序使用。
?
3、WebPageViewer.xaml:用于打開和顯示網頁
創建一個用戶控件WebPageViewer.xaml,用于打開和顯示網頁,代碼如下所示:
<UserControl x:Class="EmbeddedWebBrowser.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:EmbeddedWebBrowser"xmlns:uc="clr-namespace:EmbeddedWebBrowser"mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"><Grid x:Name="MainGrid"><uc:MaskLoading x:Name="maskLoading"/></Grid> </UserControl>???? 這里的“MaskLoading ”是用來顯示網頁加載時的等待畫面的,下面會進行介紹。
???? 后臺代碼WebPageViewer.xaml.cs如下所示:
using CefSharp; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Net; using CefSharp.Wpf;namespace EmbeddedWebBrowser {/// <summary>/// 用于顯示網頁的控件/// </summary>public partial class WebPageViewer : UserControl, IRequestHandler{/// <summary>/// 用于顯示網頁的自定義控件,構造函數/// </summary>/// <param name="url">網頁地址</param>public WebPageViewer(String url){InitializeComponent();var webView = new CefSharp.Wpf.ChromiumWebBrowser();//注冊一個JS對象webView.RegisterJsObject("hy", new CallbackObjectForJs());//注冊網頁加載事件:在頂級導航完成且內容加載到 WebView 控件中時發生webView.Loaded += new RoutedEventHandler(webView_Loaded);MainGrid.Children.Insert(0, webView);webView.Address = url;}/// <summary>/// 網頁加載完畢的事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>void webView_Loaded(object sender, RoutedEventArgs e){maskLoading.Visibility = Visibility.Collapsed; //隱藏等待畫面(正在加載...) }public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback){throw new NotImplementedException();}public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect){throw new NotImplementedException();}public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){throw new NotImplementedException();}public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback){throw new NotImplementedException();}public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){throw new NotImplementedException();}public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath){throw new NotImplementedException();}public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url){throw new NotImplementedException();}public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback){throw new NotImplementedException();}public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){throw new NotImplementedException();}public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser){throw new NotImplementedException();}public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength){throw new NotImplementedException();}public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, ref string newUrl){throw new NotImplementedException();}public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){throw new NotImplementedException();}}/// <summary>/// 網頁JS中調用的方法/// </summary>public class CallbackObjectForJs{public string action(string message){//MessageBox.Show("測試");return "收到網頁消息:" + message;}} }該類實現IRequestHandler接口,是為了能夠和JS網頁進行交互,從GetAuthCredentials到OnResourceResponse的那幾個空方法都是為了實現這個接口。當然這些在打開百度時是用不到的,接下來會用一個自己編寫的JS網頁做講解。
?
4、與JS網頁之間進行交互(如果只是打開百度等現成的網頁,可以忽略這一項)
先編寫一個網頁index.html,如下所示:
<html> <head> <title>Test Page</title> </head> <body> <p style="color: red">Hello, World!</p> <button onclick = helloWebkit()>test</button> <div><p> :) </p></div> <script type="text/javascript">function helloWebkit() { alert("input:123");var x = hy.action("123");alert(x);} </script> </body> </html>在該網頁上有一個按鈕test,點擊后會彈出提示“input:123”,并調用hy類中的action方法,傳入參數"123"。
將該網頁放到DEBUG目錄下,并將第2步MainWindow.xaml.cs中的網頁地址改為該網頁的本地地址:
txtAddress.Text = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName.Replace("EmbeddedWebBrowser.vshost.exe", "index.html");其中EmbeddedWebBrowser為工程文件名稱。
????? 在第3步的WebPageViewer.xaml.cs中,注冊了一個JS對象"hy": webView.RegisterJsObject("hy", new CallbackObjectForJs());在 CallbackObjectForJs 類中實現了action方法(該方法名全為小寫字母),接收網頁上傳來的參數,并將處理后的數據返回給網頁。
?
5、在網頁加載時顯示等待畫面
??? 第三步的代碼中有用到“MaskLoading ”,MaskLoading.xaml的代碼如下所示:
<UserControl x:Class="EmbeddedWebBrowser.MaskLoading"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:EmbeddedWebBrowser"mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"><Grid Opacity=".85"><TextBlock Text="頁面加載中..." VerticalAlignment="Center" HorizontalAlignment="Center"/></Grid> </UserControl>該頁面沒有任何邏輯,只是為了在網頁未加載完成時顯示“頁面加載中...”的提示信息。后臺代碼MaskLoading.xaml.cs如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes;namespace EmbeddedWebBrowser {/// <summary>/// Interaction logic for MaskLoading.xaml/// </summary>public partial class MaskLoading : UserControl{/// <summary>/// 顯示等待畫面“頁面加載中...”/// </summary>public MaskLoading(){InitializeComponent();}} }?
6、其他注意事項
??? 如果編譯的時候報錯,提示:“無法加載CefSharp.Core.dll組件”,則需要確保電腦上有VC++2013版本的運行庫(2010版本是不行的)。運行庫的下載地址:https://www.microsoft.com/en-us/download/details.aspx?id=40784。點擊紅色的DownLoad按鈕,選擇vcredist_x86.exe。
??? 如果仍然報錯,檢查代碼的生成屬性:在工程文件上右擊,選擇屬性——生成,打開如下圖所示的界面:
目標平臺需要選擇“x86”。
2016-04-18補充:若平臺下拉框中找不到“x86”,需要按下列步驟進行添加。
?
若選擇了平臺x86,運行時仍然報錯,則需要將原有的x86平臺刪除(按下面的步驟打開配置管理器,在活動解決方案平臺中選“編輯”,移除x86),再按下面的步驟重新添加。
?
????? 右擊解決方案--屬性--配置屬性--配置管理器,打開如下圖所示的窗體:
??????????????????????????????????????????????????
新建x86活動平臺后,編譯程序時,可能目標文件會輸出到bin\x86\Debug下。此時需要在工程的屬性里,將輸出路徑改為bin\Debug。
?
????? 如果是64位機,上述所有的x86都需要改為x64,運行庫也需要下載vcredist_x64.exe才行。
????? Winform應用程序的寫法可能會和WPF的有所不同,這里不做討論。
轉載于:https://www.cnblogs.com/xuxiaona/p/5379137.html
總結
以上是生活随笔為你收集整理的在WPF程序中打开网页:使用代理服务器并可进行JS交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云年会人机大战-技术大揭秘
- 下一篇: 2016年4月11日作业(法律法规、标准