WPF WebBrowser 컨트롤-스크립트 오류를 억제하는 방법?
여기에서 비슷한 질문을 찾았습니다.
WPF WebBrowser 컨트롤을 사용할 때 스크립트 오류를 어떻게 억제합니까?
그러나 이러한 솔루션 중 어느 것도 나를 위해 작동하지 않습니다. WebBrowser를 사용하여 웹 사이트에서 관리 작업을 자동화 할 때 팝업이 나타나지 않도록해야합니다.
SuppressScriptErrors
내 WebControl에서 사용 가능한 속성이 아닌 것 같습니다.
다음은 WPF WebBrowser
를 자동 모드로 전환 할 수있는 C # 루틴입니다 . 너무 이르기 때문에 WebBrowser 초기화에서 호출 할 수 없지만 대신 탐색이 발생한 후에 호출 할 수 있습니다. 다음은 wbMain WebBrowser 구성 요소가있는 WPF 샘플 앱입니다.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
wbMain.Navigated += new NavigatedEventHandler(wbMain_Navigated);
}
void wbMain_Navigated(object sender, NavigationEventArgs e)
{
SetSilent(wbMain, true); // make it silent
}
private void button1_Click(object sender, RoutedEventArgs e)
{
wbMain.Navigate(new Uri("... some url..."));
}
}
public static void SetSilent(WebBrowser browser, bool silent)
{
if (browser == null)
throw new ArgumentNullException("browser");
// get an IWebBrowser2 from the document
IOleServiceProvider sp = browser.Document as IOleServiceProvider;
if (sp != null)
{
Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
object webBrowser;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser);
if (webBrowser != null)
{
webBrowser.GetType().InvokeMember("Silent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty, null, webBrowser, new object[] { silent });
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
여기에 추가하는 것이 적절하다고 생각했습니다. WPF WebBrowser 의 기본 WebBorwser ActiveX 컨트롤 과 그 외에는 액세스 할 수없는 메서드 및 이벤트에 액세스 하는 또 다른 옵션이 있습니다 . 며칠 전에 발견했습니다. 매우 간단하며 WB에서 초기 탐색이 필요하지 않습니다.
dynamic activeX = this.WB.GetType().InvokeMember("ActiveXInstance",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, this.WB, new object[] { });
activeX.Silent = true;
물론이 방법이 향후 버전의 프레임 워크에서 작동하지 않을 가능성이 있지만 문서화되지 않은 다른 방법에 대해서도 마찬가지입니다. 지금까지 .NET 3.0 이후로 존재했습니다. 작동 코드 샘플에 대한 자세한 내용은 여기를 참조하십시오 .
이 문제를 해결하는 우아한 방법에 대해 Simon Mourier에게 감사드립니다. 나는 약간 개선하고 Simon의 솔루션을 첨부 된 속성으로 캡슐화했습니다.
내 응용 프로그램에서 뷰 모델에 데이터 바인딩 된 WebBrowser 컨트롤을 사용하고, 웹 브라우저가 비활성 TabItem에 숨겨져있을 수 있으므로 자바 스크립트 오류를 자동으로 설정하기 전에 로드 및 탐색 되었는지 확인해야합니다 . 그리고 당연히이 설정은 한 번만 수행해야하므로 설정 후 후크 이벤트를 해제합니다.
XAML 코드 :
<TabControl xmlns:b="clr-namespace:MyApplication.Behaviors">
<TabItem Header="foo">...</TabItem>
<TabItem Header="Google map">
<WebBrowser b:BindableSource="{Binding Path=MapUrl}"
b:DisableJavascriptErrors="True" />
</TabItem>
</TabControl>
행동 코드 :
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace MyApplication.Behaviors
{
public class WebBrowserBehavior
{
private static readonly Type OwnerType = typeof (WebBrowserBehavior);
#region BindableSource
public static readonly DependencyProperty BindableSourceProperty =
DependencyProperty.RegisterAttached(
"BindableSource",
typeof(string),
OwnerType,
new UIPropertyMetadata(OnBindableSourcePropertyChanged));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static string GetBindableSource(DependencyObject obj)
{
return (string)obj.GetValue(BindableSourceProperty);
}
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static void SetBindableSource(DependencyObject obj, string value)
{
obj.SetValue(BindableSourceProperty, value);
}
public static void OnBindableSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var browser = d as WebBrowser;
if (browser == null) return;
browser.Source = (e.NewValue != null) ? new Uri(e.NewValue.ToString()) : null;
}
#endregion
#region DisableJavascriptErrors
#region SilentJavascriptErrorsContext (private DP)
private static readonly DependencyPropertyKey SilentJavascriptErrorsContextKey =
DependencyProperty.RegisterAttachedReadOnly(
"SilentJavascriptErrorsContext",
typeof (SilentJavascriptErrorsContext),
OwnerType,
new FrameworkPropertyMetadata(null));
private static void SetSilentJavascriptErrorsContext(DependencyObject depObj, SilentJavascriptErrorsContext value)
{
depObj.SetValue(SilentJavascriptErrorsContextKey, value);
}
private static SilentJavascriptErrorsContext GetSilentJavascriptErrorsContext(DependencyObject depObj)
{
return (SilentJavascriptErrorsContext) depObj.GetValue(SilentJavascriptErrorsContextKey.DependencyProperty);
}
#endregion
public static readonly DependencyProperty DisableJavascriptErrorsProperty =
DependencyProperty.RegisterAttached(
"DisableJavascriptErrors",
typeof (bool),
OwnerType,
new FrameworkPropertyMetadata(OnDisableJavascriptErrorsChangedCallback));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static void SetDisableJavascriptErrors(DependencyObject depObj, bool value)
{
depObj.SetValue(DisableJavascriptErrorsProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static bool GetDisableJavascriptErrors(DependencyObject depObj)
{
return (bool)depObj.GetValue(DisableJavascriptErrorsProperty);
}
private static void OnDisableJavascriptErrorsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var webBrowser = d as WebBrowser;
if (webBrowser == null) return;
if (Equals(e.OldValue, e.NewValue)) return;
var context = GetSilentJavascriptErrorsContext(webBrowser);
if (context != null) {
context.Dispose();
}
if (e.NewValue != null) {
context = new SilentJavascriptErrorsContext(webBrowser);
SetSilentJavascriptErrorsContext(webBrowser, context);
}
else {
SetSilentJavascriptErrorsContext(webBrowser, null);
}
}
private class SilentJavascriptErrorsContext : IDisposable
{
private bool? _silent;
private readonly WebBrowser _webBrowser;
public SilentJavascriptErrorsContext(WebBrowser webBrowser)
{
_silent = new bool?();
_webBrowser = webBrowser;
_webBrowser.Loaded += OnWebBrowserLoaded;
_webBrowser.Navigated += OnWebBrowserNavigated;
}
private void OnWebBrowserLoaded(object sender, RoutedEventArgs e)
{
if (!_silent.HasValue) return;
SetSilent();
}
private void OnWebBrowserNavigated(object sender, NavigationEventArgs e)
{
var webBrowser = (WebBrowser)sender;
if (!_silent.HasValue) {
_silent = GetDisableJavascriptErrors(webBrowser);
}
if (!webBrowser.IsLoaded) return;
SetSilent();
}
/// <summary>
/// Solution by Simon Mourier on StackOverflow
/// http://stackoverflow.com/a/6198700/741414
/// </summary>
private void SetSilent()
{
_webBrowser.Loaded -= OnWebBrowserLoaded;
_webBrowser.Navigated -= OnWebBrowserNavigated;
// get an IWebBrowser2 from the document
var sp = _webBrowser.Document as IOleServiceProvider;
if (sp != null)
{
var IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
var IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
object webBrowser2;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser2);
if (webBrowser2 != null)
{
webBrowser2.GetType().InvokeMember(
"Silent",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty,
null,
webBrowser2,
new object[] { _silent });
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
public void Dispose()
{
if (_webBrowser != null) {
_webBrowser.Loaded -= OnWebBrowserLoaded;
_webBrowser.Navigated -= OnWebBrowserNavigated;
}
}
}
#endregion
}
}
@SimonMourier의 답변은 저에게 효과적이지 않았지만 다음과 같이 작동했습니다.
public void HideScriptErrors(WebBrowser wb, bool Hide)
{
FieldInfo fiComWebBrowser = typeof(WebBrowser)
.GetField("_axIWebBrowser2",
BindingFlags.Instance | BindingFlags.NonPublic);
if (fiComWebBrowser == null) return;
object objComWebBrowser = fiComWebBrowser.GetValue(wb);
if (objComWebBrowser == null) return;
objComWebBrowser.GetType().InvokeMember(
"Silent", BindingFlags.SetProperty, null, objComWebBrowser,
new object[] { Hide });
}
또한 JavaScript 오류를 비활성화하는 흥미로운 방법을 찾았습니다. 그러나 우아한 동적 유형을 사용하기 때문에 최소한 .Net Framework 4.0을 사용해야합니다.
WebBrowser 요소의 LoadCompleted 이벤트를 구독해야합니다.
<WebBrowser x:Name="Browser"
LoadCompleted="Browser_OnLoadCompleted" />
그 후에 아래와 같은 이벤트 핸들러를 작성해야합니다.
void Browser_OnLoadCompleted(object sender, NavigationEventArgs e)
{
var browser = sender as WebBrowser;
if (browser == null || browser.Document == null)
return;
dynamic document = browser.Document;
if (document.readyState != "complete")
return;
dynamic script = document.createElement("script");
script.type = @"text/javascript";
script.text = @"window.onerror = function(msg,url,line){return true;}";
document.head.appendChild(script);
}
내 솔루션을 볼 수 있습니다. Silverlight의 WebBrowser 컨트롤에서 JavaScript 오류 비활성화-Silverlight 용이지만 WPF에서도 작동해야합니다.
글쎄 필요하다면 WinformHost
WebBrowser Control을 추가하고 사용했을 것입니다.
당신은 쉽게 여기에 그 작업을 수행 할 수 있습니다 WinformHost
내가 사물의 번들을 수행 전체 응용 프로그램을 만들었습니다 때문에도
다음은 리플렉션을 사용하지 않고이를 수행하는 방법의 예입니다.
/// <summary>
/// Gets an interop web browser.
/// </summary>
/// <param name="browser"></param>
/// <returns></returns>
public static SHDocVw.WebBrowser GetInteropWebBrowser(this WebBrowser browser)
{
Guid serviceGuid = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;
Interop.IServiceProvider serviceProvider = (Interop.IServiceProvider)browser.Document;
SHDocVw.IWebBrowser2 browser2 = (SHDocVw.IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);
SHDocVw.WebBrowser wb = (SHDocVw.WebBrowser)browser2;
return wb;
}
/// <summary>
/// Disables script errors for the browser.
/// </summary>
/// <param name="browser"></param>
/// <param name="silent"></param>
public static void SetSilent(this WebBrowser browser, bool silent)
{
SHDocVw.WebBrowser browser2 = browser.GetInteropWebBrowser();
if (browser2 != null)
browser2.Silent = silent;
}
/// <summary>
/// Provides the COM interface for the IServiceProvider.
/// </summary>
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
/// <summary>
/// Queries the service.
/// </summary>
/// <param name="serviceGuid"></param>
/// <param name="riid"></param>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.IUnknown)]
object QueryService(ref Guid serviceGuid, ref Guid riid);
}
그런 다음 브라우저 컨트롤을 호스팅하는 뷰의 생성자에 다음이 있습니다.
Browser.Navigated += (s, e) =>
{
Browser.SetSilent(true);
};
I wanted to add that I tried all the above solutions to try and stop the long running script error (which they don't claim to do so, but this was the closest question I could find to my issue). Posting in case anyone else has the same "a script on this page is causing your browser to run slowly" issue.
The only thing I found to work was setting the registry key which must be set before the browser is created
var keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\styles";
if(Registry.GetValue(keyName, "MaxScriptStatements", null) == null)
{
Registry.SetValue(keyName, "MaxScriptStatements", unchecked((int)0xffffffff), RegistryValueKind.DWord);
}
Really very simple, thank you for your solution.
Dim sb As New StringBuilder
sb.Append("<html>")
sb.Append("<head>")
sb.Append("</head")
sb.Append("<body>")
sb.Append("<iframe src ='" + url + "' height='" + webBrowser1.Height + "' width='" + webBrowser1.Width + "'></iframe>")
sb.Append("</body")
sb.Append("</html>")
WebBrowser1.DocumentText = sb.ToString
ReferenceURL : https://stackoverflow.com/questions/6138199/wpf-webbrowser-control-how-to-suppress-script-errors
'Program Tip' 카테고리의 다른 글
Android에서 그라디언트가있는 텍스트 (0) | 2020.12.26 |
---|---|
iOS 앱의 첫 실행 감지 (0) | 2020.12.26 |
OS X에서 명령 줄을 통해 활성 사용자의 이름을 어떻게 얻습니까? (0) | 2020.12.26 |
foreach 루프에서 반복 횟수 계산 (0) | 2020.12.26 |
Switch 케이스에서 추가 중괄호의 목적은 무엇입니까? (0) | 2020.12.26 |