问题
I am trying to attach a context menu when user perform a hold gesture on a link on a webpage.
I've searched the web and found some recommendations HERE
if (webBrowser.IsScriptEnabled)
{
webBrowser.InvokeScript("execScript", "function eventListener(evt){ if (evt.type == 'MSPointerDown') { gestureHandler.addPointer(evt.pointerId); return; } if (evt.detail & evt.MSGESTURE_FLAG_END) { window.external.notify(evt.srcElement.tagName);}}");
webBrowser.InvokeScript("execScript","document.addEventListener('MSGestureHold', eventListener, false); document.addEventListener('MSPointerDown', eventListener, false); gestureHandler = new MSGesture(); gestureHandler.target = document.body;");
}
But the second execScript raised this error
System.SystemException was unhandled by user code
HResult=-2146233087
Message=An unknown error has occurred. Error: 80020101.
Source=Microsoft.Phone.Interop
StackTrace:
at Microsoft.Phone.Controls.NativeMethods.ValidateHResult(Int32 hr)
at Microsoft.Phone.Controls.WebBrowserInterop.InvokeScript(String scriptName, String[] args)
at Microsoft.Phone.Controls.WebBrowser.InvokeScript(String scriptName, String[] args)
at Tabbed_Browser.User_Controls.WebBrowser.AttachContextMenu()
at Tabbed_Browser.User_Controls.WebBrowser.webBrowser_Loaded(Object sender, RoutedEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
InnerException:
I've also tried the following, based on this posting. But apparently it only work in WP7 phone not in WP8 or the emulator.
public void AttachContextMenu()
{
try
{
if (webBrowser.IsScriptEnabled)
{
webBrowser.InvokeScript("execScript", "function FindParentLink(item) \r\n{\r\n\tif (!item.parentNode)\r\n\t\treturn null;\r\n\tif (item.tagName.toLowerCase() == 'a') \r\n\t{\r\n\t\treturn item;\r\n\t} \r\n\telse \r\n\t{\r\n\t\treturn FindParentLink(item.parentNode);\r\n\t}\r\n}\r\n\r\nfunction FindParentImage(item) \r\n{\r\n\tif (!item.parentNode)\r\n\t\treturn null;\r\n\tif (item.tagName.toLowerCase() == 'img') \r\n\t{\r\n\t\treturn item;\r\n\t} \r\n\telse \r\n\t{\r\n\t\treturn FindParentImage(item.parentNode);\r\n\t}\r\n}\r\n\r\nfunction HandleContextMenu() \r\n{\r\n\tvar linkItem = FindParentLink(event.srcElement);\r\n var imageItem = FindParentImage(event.srcElement);\r\n var notifyOutput = '';\r\n if (linkItem != null) if (linkItem.href != null) notifyOutput += linkItem.href;\r\n if (imageItem != null) if (imageItem.src != null) notifyOutput += imageItem.src;\r\n if (notifyOutput != '')\r\n window.external.notify(notifyOutput);\r\n else\r\n\t\twindow.external.notify('NOTLINKIMG');\r\n}");
webBrowser.InvokeScript("execScript", "document.oncontextmenu = HandleContextMenu;");
}
}
catch
{
}
}
I monitor the result via ScriptNotify but it never fired
private void webBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
Debug.WriteLine(e.Value.ToString());
}
Anyone know how to attach context menu in WP8 browser control?
EDIT
I've found an info that window.navigator.msPointerEnabled is false on the WebBrowser control and True on the Internet Explorer application. So does that mean we can't implement touch event detection properly in the control. Can we set it to enabled?
回答1:
If window.navigator.msPointerEnabled is false ,you can use onmousedown and onmouseup to monitor
回答2:
After trying to get the WP8 web browser control do some tricks, here are a couple observations.
The ...
System.SystemException
Message=An unknown error has occurred. Error: 80020101.
... typically means your javascript was not parsed correctly. Often a syntax error.
I found striping out the CR, LF, and TAB characters reduces the noise and makes finding syntax errors in a VisualStudio JavaScript editor window a little easier. String.Replace() is your friend.
I have only been successful using the InvokeScript() to execute anonymous functions. This pattern has been successful: (pay attention to the punctuation)
webBrowser.InvokeScript("eval", "(function (param1) { window.external.notify(param1); })('this is your message');");
In your specific case, I see three functions being defined but what causes them to be executed? Perhaps that explains the exception.
Gyle
回答3:
This is my solution. It is working on Windows Phone 8
<phone:WebBrowser
x:Name="WebBrowser"
IsHitTestVisible="True"
IsScriptEnabled="True"
LoadCompleted="WebBrowser_LoadCompleted"
ScriptNotify="WebBrowser_ScriptNotify">
</phone:WebBrowser>
private void WebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
if (WebBrowser.IsScriptEnabled)
{
var JavaScriptText =
@"function ReplaceBadXmlChars(str) {
var stri = str.split('&').join('&');
stri = stri.split('<').join('<');
stri = stri.split('>').join('>');
stri = stri.split("'").join(''');
stri = stri.split('"').join('"');
return stri;
}
function FindParentByTag(item, tag) {
if (!item.parentNode) return null;
if (item.tagName.toLowerCase() == tag.toLowerCase()) {
return item;
} else {
return FindParentByTag(item.parentNode, tag);
}
}
function OnClick() {
var linkItem = FindParentByTag(event.srcElement, 'a');
var imageItem = FindParentByTag(event.srcElement, 'img');
var zoom = screen.deviceXDPI / screen.logicalXDPI;
var valid = false;
var notifyMsg = '<Click ';
{
notifyMsg += 'pos="' + parseInt(event.clientX * zoom) + ',' + parseInt(event.clientY * zoom) + '" ';
if (linkItem != null && linkItem.href != null && !linkItem.href.startsWith("javascript")) {
notifyMsg += 'url="' + ReplaceBadXmlChars(linkItem.href) + '" ';
valid = true;
}
if (imageItem != null && imageItem.href != null && !linkItem.href.startsWith("javascript")) {
notifyMsg += 'img="' + ReplaceBadXmlChars(imageItem.src) + '" ';
valid = true;
}
}
notifyMsg += '/>';
if (valid) {
window.external.notify(notifyMsg);
return false;
}
}
function RegisterClickNotification() {
window.document.onclick = OnClick;
window.document.body.addEventListener('MSPointerDown', function(evt) {
evt = evt || window.event;
var linkItem = FindParentByTag(evt.srcElement, 'a');
var imageItem = FindParentByTag(evt.srcElement, 'img');
window.devicePixelRatio = window.screen.deviceXDPI / window.screen.logicalXDPI;
var doc = window.document.documentElement;
var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
var timerId = window.setTimeout(function() {
var notifyMsg = 'pos="' + parseInt((evt.clientX - left)) + ',' + parseInt((evt.clientY - top)) + '" ';
if (linkItem != null && linkItem.href != null) {
notifyMsg += 'url="' + ReplaceBadXmlChars(linkItem.href) + '" ';
}
if (imageItem != null && imageItem.href != null) {
notifyMsg += 'img="' + ReplaceBadXmlChars(imageItem.src) + '" ';
}
window.external.notify('<Hold ' + notifyMsg + '/>');
}, 500);
StopLoading();
evt.target.data = timerId;
});
}
window.document.body.addEventListener('MSPointerUp', function (evt) {
window.clearTimeout(evt.target.data);
});
window.document.body.addEventListener('MSPointerMove', function (evt) {
window.clearTimeout(evt.target.data);
});
window.document.body.addEventListener('MSPointerOut', function (evt) {
window.clearTimeout(evt.target.data);
});
window.document.body.addEventListener('pointerup', function (evt) {
});"
WebBrowser.InvokeScript("eval", new string[] { JavaScriptText });
WebBrowser.InvokeScript("RegisterClickNotification");
WebBrowser.InvokeScript("execScript", new string[] {
"function eventListener(evt) {if (evt.type == 'MSPointerDown'){ gestureHandler.addPointer(evt.pointerId); return; } if (evt.detail & evt.MSGESTURE_FLAG_END) { window.external.notify(evt.srcElement.tagName);}}" });
WebBrowser.InvokeScript("execScript", new string[] { "document.addEventListener('MSGestureHold', eventListener, false); document.addEventListener('MSPointerDown', eventListener, false); gestureHandler = new MSGesture(); gestureHandler.target = document.body;" });
}
}
回答4:
The following code works, but it fires even when you tap on any image or link. We may have to add a timer of some sort since we can't attach.
EDIT:
I was able to figure it out! The following code works in WP8 AND only detects a hold, not a tap.
public void AttachScripts()
{
try
{
if (GINternet.IsScriptEnabled)
{
var scriptsText = @"function ReplaceBadXmlChars(str) {
var stri = str.split('&').join('&');
stri = stri.split('<').join('<');
stri = stri.split('>').join('>');
stri = stri.split(""'"").join(''');
stri = stri.split('""""').join('"');
return stri;
}
function FindParentLink(item) {
if (!item.parentNode)
return null;
if (item.tagName.toLowerCase() == 'a') {
return item;
} else {
return FindParentLink(item.parentNode);
}}
function FindParentImage(item) {
if (!item.parentNode)
return null;
if (item.tagName.toLowerCase() == 'img') {
return item;
} else {
return FindParentImage(item.parentNode);
}}
var currGNetMouseTimer;
window.document.body.addEventListener('pointerdown', function (evt) {
evt = evt || window.event;
var linkItem = FindParentLink(evt.srcElement);
var imageItem = FindParentImage(evt.srcElement);
currGNetMouseTimer = window.setTimeout(function() {
var notifyMsg = '';
if (linkItem != null && linkItem.href != null) {
notifyMsg += ReplaceBadXmlChars(linkItem.href);
}
if (imageItem != null && imageItem.src != null) {
notifyMsg += ReplaceBadXmlChars(imageItem.src);
}
if (notifyMsg != '') {
window.external.notify(notifyMsg);
} else {
window.external.notify('NOTLINKIMG');
}
}, 750);
},false);
window.document.body.addEventListener('pointermove', function (evt) {
window.clearTimeout(currGNetMouseTimer);
},false);
window.document.body.addEventListener('pointerup', function (evt) {
window.clearTimeout(currGNetMouseTimer);
},false);
window.document.body.addEventListener('pointerout', function (evt) {
window.clearTimeout(currGNetMouseTimer);
},false);";
GINternet.InvokeScript("execScript", new string[] { scriptsText });
}
}
catch
{
}
}
private void GINternet_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
//REQUIRED FOR WINDOWS PHONE 8
AttachScripts();
}
来源:https://stackoverflow.com/questions/16481127/adding-contextmenu-to-wp8-browser-control