none
ContextMenu in WebBrowser control in WP8 (OnMSGestureHold instead of OnContextMenu (WP7))

    Question

  • How can you add a ContextMenu to a WebBrowser control in WP8?

    In WP7 it has worked with this code:

    public void AttachContextMenu()
    {
        if (webBrowser.IsScriptEnabled)
        {
            webBrowser.InvokeScript("execScript", "function HandleContextMenu() \r\n{\r\n\twindow.external.notify('TEST');\r\n}");
            //WP7:
            webBrowser.InvokeScript("execScript", "document.oncontextmenu = HandleContextMenu;");
            //WP8:
            //webBrowser.InvokeScript("execScript", "document.onmsgesturehold = HandleContextMenu;");
        }
    }
    
    private void webBrowser_ScriptNotify(object sender, NotifyEventArgs e)  
    {
        MessageBox.Show(e.Value.ToString());	//Show Message "TEST"
    }
    
    private void webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
    {
        AttachContextMenu();
    }

    In the following document it is stated that one should use OnMSGestureHold instead of OnContextMenu.

    http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206947(v=vs.105).aspx

    http://msdn.microsoft.com/en-us/library/ie/hh771894(v=vs.85).aspx

    But that does not work. The event handler (HandleContextMenu) is not called.

    Can someone help me? Thank you!


    • Edited by chris202080 Tuesday, November 27, 2012 1:19 PM
    Tuesday, November 27, 2012 1:13 PM

All replies

  • Are you setting:
    Browser.IsScriptEnabled = true;

    -Jeff


    Jeff Sanders (MSFT)

    Tuesday, November 27, 2012 2:19 PM
  • Thanks for your answer!

    Yes, I'm doing this in my XAML Code:

    <phone:WebBrowser IsScriptEnabled="True" LoadCompleted="webBrowser_LoadCompleted" ScriptNotify="webBrowser_ScriptNotify" Name="webBrowser" />

    Chris

    Tuesday, November 27, 2012 2:25 PM
  • This sample will get you really close to what you need:

     

                if (Browser.IsScriptEnabled)
                {
                    Browser.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);}}");
                    Browser.InvokeScript("execScript","document.addEventListener('MSGestureHold', eventListener, false); document.addEventListener('MSPointerDown', eventListener, false);  gestureHandler = new MSGesture(); gestureHandler.target = document.body;");
                }
    

    -Jeff 

    Jeff Sanders (MSFT)

    Tuesday, November 27, 2012 7:26 PM
  • Thanks Jeff! The MessageBox with the TagName shows up.
    But no matter where I tap and hold, the TagName is "BODY".

    I need the source link from a picture that I tap and hold.
    In WP7 it works with this code:

    function FindImage(item) { if (!item.parentNode) return null; if (item.tagName.toLowerCase() == 'img') { return item; } else { return FindImage(item.parentNode); } } function HandleContextMenu() { var imageItem = FindImage(event.srcElement); var notifyOutput = ''; if (imageItem != null) if (imageItem.src != null) notifyOutput += imageItem.src; if (notifyOutput != '') window.external.notify(notifyOutput); else window.external.notify('NoLink'); }

    document.oncontextmenu = HandleContextMenu;

    This does not work with your code because the TagName is always "BODY".


    • Edited by chris202080 Tuesday, November 27, 2012 8:19 PM
    Tuesday, November 27, 2012 8:17 PM
  • Hi Chris,

    This sample shows using a div and in an HTML page to simplify testing.  You would replace 'div' with 'img' and embed it into your code as above.

    <!DOCTYPE html>
    <html >
    <head>
    
    <link rel="stylesheet" type="text/css" href="/html/css/phone.css" />
        <title>Touch and hold example</title>
      <style>
        body {
          -ms-touch-action:none;
        }
        
        .touchspot {
          width:100px;
          height:100px;
          background-color:aquamarine;
          border:solid 2px black;
        }
      </style>
    
    </head>
    <body>
      <div class="touchspot" id="touchspot">Touch and hold me</div>
        <div class="touchspot" id="touchspot2">Touch and hold me2</div>
      <script>
    
    
          var theDivs = document.querySelectorAll('div');
    
          for (var i = 0; i < theDivs.length; i++) {
              doGesture(theDivs[i]);
          }
          
    
          function doGesture(elem) {
              //  Create a new gesture object and assign the <div> as the target element
              var gestureObj = new MSGesture();
              gestureObj.target = elem;
    
              //  Assigns a pointerId to the gesture object
              elem.addEventListener("MSPointerDown", function (e) {
                  gestureObj.addPointer(e.pointerId)
              }, false);
    
              elem.addEventListener("MSGestureHold", function (e) {
                  // use END because if the user slides off before completing the hold you don't care about this event
                  if (e.detail == e.MSGESTURE_FLAG_END) {
                      e.target.innerHTML = "I'm being held";
                  } else {
                      e.target.innerHTML = "I've been held";
                  }
              }, false);
    
              elem.addEventListener("contextmenu", function (e) {
                  e.target.innerHTML = "I've been held";
                  e.preventDefault();    // Disables system menu
              }, false);
          }
      </script>
    </body>
    </html>
    
    -Jeff

    Jeff Sanders (MSFT)


    Wednesday, November 28, 2012 1:57 PM
  • Hi Jeff, the code works. Thanks for your help!
    On some websites an exception is thrown in this line:

    var gestureObj = new MSGesture;

    For example on this Website.

    Any idea why this is the case?

    Tuesday, December 04, 2012 1:21 PM
  • Hi Chris,

    The syntax should be this:           var gestureObj = new MSGesture();

    ... note the Parens.

    That may be the issue.

    -Jeff


    Jeff Sanders (MSFT)

    Tuesday, December 04, 2012 4:44 PM
  • Hi Jeff,

    Unfortunately, the error still appears.

    Tuesday, December 04, 2012 5:22 PM
  • Any news on this issue? Other developers are likely to have the same problem. especially developers of alternative browsers like Surfcube browser.
    Friday, December 14, 2012 9:53 AM
  • Sorry Chris,

    I have not had time to look into this further yet.  One possibility is that the site is running in some sort of compatibility mode so the Gesture object is not available.  You will need to insert a try catch block to avoid the exception. 

    -Jeff


    Jeff Sanders (MSFT)

    • Proposed as answer by Noeek Friday, July 12, 2013 7:34 AM
    • Unproposed as answer by Noeek Friday, July 12, 2013 7:34 AM
    Friday, December 14, 2012 3:25 PM
  • Hi Jeff,

    I am trying to do the same, activating my own context menu when a link is the element on gesture hold. However, it always return "BODY" if I click anywhere except a link.

    When I hold a link,  "BODY" sometimes return sometimes nothing happen.

    So how do I modify the code to detect a link has been is the one being click?

    Saturday, May 11, 2013 12:14 PM
  • This is what I've done so far

                if (webBrowser.IsScriptEnabled)
                {
                     string gestureHold = string.Format("{0} {1} {2} {3} {4} {5} {6} {7}",
                        "var links = document.getElementsByTagName('a'); ",
                        "for (i = 0; i < links.length; i++)",
                        "{",
                            "links[i].addEventListener('MSGestureHold', eventListener, false);",
                            "links[i].addEventListener('MSPointerDown', eventListener, false);",
                            "gestureHandler = new MSGesture();",
                            "gestureHandler.target = links[i];",
                        "};");

                     string eventList = string.Format("{0} {1} {2} {3} {4}",
                         "function eventListener(evt)",
                         "{",
                         "if (evt.type == 'MSPointerDown') { gestureHandler.addPointer(evt.pointerId); return; }",
                         "if (evt.detail & evt.MSGESTURE_FLAG_END) { window.external.notify(evt.target.href); }",
                         "};");


                    webBrowser.InvokeScript("execScript", eventList);
                    webBrowser.InvokeScript("execScript", gestureHold);
                }

    Now it detects the link on long tap but it only returns the last link on the page. And sometimes the on long tap event is not fired. Another issue I am having is when user click a link and navigate to other page, the script stop detecting a long tap.

    I've made sure I attached the script in the webBrowser_Navigated event but the problem persists. Any suggestion how to fix this? Thanks

    Saturday, May 11, 2013 6:01 PM
  • I believe that this code does not work in the WP8 web browser control. It does work on Internet Explorer app.

    UPDATE: Sorry guys. The gestures didnt work because the build profile had a path to WP7 Phone.Controls DLL. i hadnt noticed because all other features worked the same. Thanks for your reply.

    Thursday, May 23, 2013 7:14 PM
  • Did you enable scripting in the browser control WP8?
    Friday, May 24, 2013 2:37 AM