wpf 如何从 CefSharp 3 在本机浏览器中打开链接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31241240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to open a link in a native browser from CefSharp 3
提问by Ahamed Salik
I have a requirement to open a link in a native browser from CefSharp 3. I need to run the whole application in CefSharp 3's chromium browser except a form. when I click the form's link button (Eg - Register button. It has a link to the registration form) I need to open this link in the native browser (Eg - Internet Explorer).
我需要在 CefSharp 3 的本机浏览器中打开一个链接。我需要在 CefSharp 3 的 Chrome 浏览器中运行整个应用程序,除了表单。当我单击表单的链接按钮(例如 - 注册按钮。它有一个指向注册表的链接)时,我需要在本机浏览器(例如 - Internet Explorer)中打开此链接。
Can we achieve this in CefSharp?
我们可以在 CefSharp 中实现这一目标吗?
I searched the google as well as stack overflow. But unable to find a solution.
我搜索了谷歌以及堆栈溢出。但是找不到解决办法。
Thanks in advance.
提前致谢。
回答by Ahamed Salik
As suggested by holroy I have implemented the OnBeforeNavigation() method in the RequestHandler class in CefSharp.Example package.
正如 holroy 所建议的,我已经在 CefSharp.Example 包的 RequestHandler 类中实现了 OnBeforeNavigation() 方法。
This is the working code,
这是工作代码,
bool IRequestHandler.OnBeforeBrowse(IWebBrowser browserControl,
IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// If the url is Google open Default browser
if (request.Url.Equals("http://google.com/"))
{
// Open Google in Default browser
System.Diagnostics.Process.Start("http://google.com/");
return true;
}else
{
// Url except Google open in CefSharp's Chromium browser
return false;
}
}
I hope this will help to some one else in future.
我希望这会在未来对其他人有所帮助。
Thanks,
谢谢,
回答by Murat Aykanat
First you need to create a custom BrowserRequestHandlerclass such as this:
首先,您需要创建一个自定义BrowserRequestHandler类,例如:
public class BrowserRequestHandler : IRequestHandler
{
public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// Open in Default browser
if (!request.Url.StartsWith("file:"))
{
System.Diagnostics.Process.Start(request.Url);
return true;
}
return false;
}
public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
WindowOpenDisposition targetDisposition, bool userGesture)
{
return false;
}
public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl,
ISslInfo sslInfo, IRequestCallback callback)
{
callback.Dispose();
return false;
}
public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
{
throw new Exception("Plugin crashed!");
}
public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IRequestCallback callback)
{
return CefReturnValue.Continue;
}
public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port,
string realm, string scheme, IAuthCallback callback)
{
callback.Dispose();
return false;
}
public bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port,
X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
{
callback.Dispose();
return false;
}
public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
{
throw new Exception("Browser render process is terminated!");
}
public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize,
IRequestCallback callback)
{
callback.Dispose();
return false;
}
public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response,
ref string newUrl)
{
var url = newUrl;
newUrl = url;
}
public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
{
return url.StartsWith("mailto");
}
public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
{
}
public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
return false;
}
public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IResponse response)
{
return null;
}
public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IResponse response, UrlRequestStatus status, long receivedContentLength)
{
}
}
The important part in this code is:
这段代码的重要部分是:
public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// Open in Default browser
if (!request.Url.StartsWith("file:"))
{
System.Diagnostics.Process.Start(request.Url);
return true;
}
return false;
}
In my case, I was opening locally saved HTML files in CEF, and if those locally saved HTML files had external links, they would open up in the default browser.
就我而言,我在 CEF 中打开本地保存的 HTML 文件,如果这些本地保存的 HTML 文件有外部链接,它们将在默认浏览器中打开。
Now that you created the custom BrowserRequestHandler, you need to assign it to the browser.
现在您创建了 custom BrowserRequestHandler,您需要将其分配给浏览器。
If you are using MVVM, you can create a BrowserRequestHandlerin your model and assign it to the RequestHandlerdependency property of the browser control. But in my case there were timing issues as I had several browser instances in dynamically opening tabs and browsers were not opening fast enough and throwing errors.
如果您使用的是 MVVM,则可以BrowserRequestHandler在模型中创建一个并将其分配给RequestHandler浏览器控件的依赖项属性。但就我而言,存在计时问题,因为我在动态打开选项卡时有几个浏览器实例,并且浏览器打开速度不够快并引发错误。
So the second option is to set up a Loaded event using the interactivity namespace like this:
所以第二个选项是使用交互命名空间设置一个 Loaded 事件,如下所示:
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding BrowserLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</wpf:ChromiumWebBrowser>
After this you can get the browser in your view model (or do this in a manager class), and set its RequestHandlerto your custom BrowserRequestHandlerlike this:
在此之后,您可以在视图模型中获取浏览器(或在管理器类中执行此操作),并将其设置RequestHandler为您的自定义,BrowserRequestHandler如下所示:
browser.RequestHandler = new BrowserRequestHandler();
回答by holroy
It seems like it possible through use of the OnBeforeNavigation or OnBeforeBrowse events. See following references from "CEF Forum":
似乎可以通过使用 OnBeforeNavigation 或 OnBeforeBrowse 事件来实现。请参阅“CEF 论坛”中的以下参考资料:
- How to have link open in user's default browser
- CEF 3 Open all link targets externally
- Open external browser from link
A suggested implementation of the OnBeforeNavigation method (from Sending information from Chromium Embeded (Javascript) to a containing C++ application):
OnBeforeNavigation 方法的建议实现(从将信息从 Chromium Embeded (Javascript) 发送到包含的 C++ 应用程序):
//declare (i.e. in header)
virtual bool OnBeforeNavigation(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
NavigationType navigation_type, bool is_redirect) OVERRIDE;
//implementation
bool CClientApp::OnBeforeNavigation(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
NavigationType navigation_type, bool is_redirect)
{
CefString cefval = request->GetURL();
CString csval = cefval.c_str();
if ( /* Match csval against your url/link */ )
{
//process the command here
//this is a command and not really intended for navigation
return true;
}
return false; //true cancels navigation, false allows it
}
Disclaimer: I haven't tried this code myself, but it should do the trick
免责声明:我自己没有尝试过这段代码,但它应该可以解决问题
回答by Chaya Sulman
I tried using a RequestHandler as suggested, however I found that while the link was opening correctly in a browser, the ChromiumWebBrowser was still opening an empty Chromium window. Instead of using the RequestHandler, I found that this could be more smoothly implemented using an ILifeSpanHandler - which allows me to catch the popup opening and redirect the process at that point.
我尝试按照建议使用 RequestHandler,但是我发现当链接在浏览器中正确打开时,ChromiumWebBrowser 仍然打开一个空的 Chromium 窗口。我发现使用 ILifeSpanHandler 可以更顺利地实现,而不是使用 RequestHandler - 这允许我抓住弹出窗口的打开并在那时重定向进程。
Here is the code I used for the ILifeSpanHandler:
这是我用于 ILifeSpanHandler 的代码:
public class ChromiumLifeSpanHandler : ILifeSpanHandler
{
public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
return false;
}
public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
newBrowser = null;
System.Diagnostics.Process.Start(targetUrl);
return true;
}
}
Here is how I implemented it in WPF (I just stuck it in a grid to have a place to show the static resource):
这是我在 WPF 中实现它的方式(我只是将它放在一个网格中以便有一个地方来显示静态资源):
<Grid>
<Grid.Resources>
<local:ChromiumLifeSpanHandler x:Key="popupHandler"/>
</Grid.Resources>
<cef:ChromiumWebBrowser Address="{Binding TwitterFeedAddress}"
LifeSpanHandler="{StaticResource popupHandler}"/>
</Grid>
回答by Louis Shanks
Correcting a small typeo in Chaya answer (which worked for me also). x:Key="" is missing the L.
更正 Chaya 答案中的一个小类型(也对我有用)。x:Key="" 缺少 L。
<Grid>
<Grid.Resources>
<local:ChromiumLifeSpanHandler x:Key="popupHandler"/>
</Grid.Resources>
<cef:ChromiumWebBrowser Address="{Binding TwitterFeedAddress}"
LifeSpanHandler="{StaticResource popupHandler}"/>
</Grid>

