在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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值