2016-04-21 13 views
4

PräambelKind Ankerelement erhält Kontrolle innerhalb WebBrowser

Ich verwende die WebBrowser Steuerung, die ein Benutzer mit interagieren, so dass eine Lösung benötigen, um mit einer sichtbaren WebBrowser Kontrolle zu arbeiten.

Frage

Wie kann ich überprüfen, ob ein Element einen Anker als ein Kind? Alle Browser können unterscheiden, dass ein Element einen Anker enthält (<a href=""...), und bieten die Funktion "In neuem Tab öffnen". Das versuche ich zu reproduzieren. Wenn ich jedoch mit der rechten Maustaste auf eine HtmlElement klicke, kann ich nur das übergeordnete Element erhalten.

Beispiel

Unter der BBC-Website als Beispiel, wenn ich auf dem markierten Elemente rechts klicken (Bild unten), meine Ausgabe ist DIV, aber sehen Sie den Quellcode gibt es ein Ankerelement als Kind davon div.

bbc homepage example

SSCCE

using System; 
using System.Diagnostics; 
using System.Windows.Forms; 

namespace BrowserLinkClick 
{ 
    public partial class Form1 : Form 
    { 
     private WebBrowser wb; 
     private bool firstLoad = true; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      wb = new WebBrowser(); 
      wb.Dock = DockStyle.Fill; 
      Controls.Add(wb); 
      wb.Navigate("http://bbc.co.uk"); 
      wb.DocumentCompleted += wb_DocumentCompleted; 
     } 

     private void Document_MouseDown(object sender, HtmlElementEventArgs e) 
     { 
      if (e.MouseButtonsPressed == MouseButtons.Right) 
      { 
       HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); 
       //I assume I need to check if this element has child elements that contain a TagName "A" 
       if (element.TagName == "A") 
        Debug.WriteLine("Get link location, open in new tab."); 
       else 
        Debug.WriteLine(element.TagName); 
      } 
     } 


     private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
     { 
      if (firstLoad) 
      { 
       wb.Document.MouseDown += new HtmlElementEventHandler(Document_MouseDown); 
       firstLoad = false; 
      } 
     } 

    } 
} 

Testen Sie jede vorgeschlagene Lösung die BBC-Website und die markierte Überschrift (die Überschrift ändert, aber das DOM bleibt gleich) verwendet wird.

Antwort

2

Sie haben die untergeordneten Elemente von element zu erhalten, bevor geprüft wird, ob es ein Anker ist:

HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); 
foreach (HtmlElement child in element.Children) 
{ 
    if (child.TagName == "A") 
     Debug.WriteLine("Get link location, open in new tab."); 
} 
+0

Leider gibt dies immer noch nicht das 'a'-Tag für mein Beispiel zurück. Kannst du es mit dem BBC-Beispiel von meinem ursprünglichen Beitrag versuchen und sehen, ob das für dich der Fall ist? Die Nachricht wurde geändert, die DOM-Struktur bleibt jedoch unverändert. – TEK

2

Um die erforderlichen Eigenschaften, die Sie benötigen Zugriff auf die HtmlElement einem der unmanaged MSHTML Schnittstellen zu werfen, z.B. IHTMLAnchorElement

Sie müssen Microsoft HTML Object Library COM-Referenz zu Ihrem Projekt hinzufügen.
(Der Dateiname ist mshtml.tlb.)

foreach (HtmlElement child in element.Children) 
{ 
    if (String.Equals(child.TagName, "a", StringComparison.OrdinalIgnoreCase)) 
    { 
     var anchorElement = (mshtml.IHTMLAnchorElement)child.DomElement; 
     Console.WriteLine("href: [{0}]", anchorElement.href); 
    } 
} 

Es gibt viele solcher Schnittstellen aber MSDN hilft Ihnen dabei. :)

Scripting Object Interfaces (MSHTML)

+0

Leider gibt dies immer noch nicht das 'a'-Tag für mein Beispiel zurück. Kannst du es mit dem BBC-Beispiel von meinem ursprünglichen Beitrag versuchen und sehen, ob das für dich der Fall ist? Die Nachricht wurde geändert, die DOM-Struktur bleibt jedoch unverändert. – TEK

+0

Sie können eine rekursive Methode verwenden, die prüft, ob eines der 'HtmlElement.Children' ein' mshtml.IHtmlAnchorElement' ist; falls keiner, dann setze das aktuelle Element auf sein Elternelement und rufe die gleiche Methode rekursiv auf (natürlich solltest du die bereits geprüften Elemente überspringen). – Gabor

2

Ich schlage vor, Sie die folgende Lösung:
url Variable URL der gewünschten Ausgabe haben, können Sie es in Debugger-Fenster sehen.

private void Document_MouseDown(object sender, HtmlElementEventArgs e) 
{ 
     if (e.MouseButtonsPressed == MouseButtons.Right) 
     { 
      HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); 
      //I assume I need to check if this element has child elements that contain a TagName "A" 
      if (element.TagName == "A") 
      { 
       Debug.WriteLine("Get link location, open in new tab."); 
       var urlRaw = element.OuterHtml; 
       string hrefBegin = "href="; 
       var idxHref = urlRaw.IndexOf(hrefBegin) + hrefBegin.Length + 1; 
       var idxEnd = urlRaw.IndexOf("\"", idxHref + 1); 
       var url = urlRaw.Substring(idxHref, idxEnd - idxHref); 
       Debug.WriteLine(url); 
      } 

      else 
       Debug.WriteLine(element.TagName); 
     } 
    } 
+0

@TEK hilft es? –

+0

Das Parsen der URL vom Anker ist nicht das Problem, sondern das Anchor-Tag, wenn es ein Kind anderer Elemente ist (ja, die Analyse des Links ist ein zukünftiges Problem, aber ich kann noch nicht einmal den Anker holen). Benutze die BBC-Homepage von meinem ursprünglichen Post, du wirst sehen, dass ich keinen Anker finde, wenn ich mit der rechten Maustaste auf eine der Überschriften klicke. Das "WebBrowser" -Steuerelement mit einem Standardkontextmenü kann jedoch, ebenso wie andere Webbrowser, unterscheiden, ob ein Anker vorhanden ist. – TEK

+0

Was betrachten Sie als Anker? Eltern-Tag oder Geschwister-Tag? Können Sie ein Beispiel dafür nennen, welche Ausgabe Sie erwarten? –

2

Es muss etwas anderes mit Ihrem Programm falsch sein. Auf der BBC-Website funktioniert Ihr Code für die Nachrichtenartikel (obwohl ich die nicht britische Version der Website sehe). Auf anderen Websites, auf denen gibt es Ankerelemente wie Kinder den Code unten arbeitet

private void Document_MouseDown(object sender, HtmlElementEventArgs e) 
    { 
     if (e.MouseButtonsPressed == MouseButtons.Right) 
     { 
      HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); 
      if (element.Children.Count > 0) 
      { 
       foreach (HtmlElement child in element.Children) 
       { 
        if (child.TagName == "A") 
         Debug.WriteLine("Get link location, open in new tab."); 
       } 
      } 
      else 
      { 
       //I assume I need to check if this element has child elements that contain a TagName "A" 
       if (element.TagName == "A") 
        Debug.WriteLine("Get link location, open in new tab."); 
       else 
        Debug.WriteLine(element.TagName); 
      } 
     } 
    } 
+0

Der Code, den ich in meinem ursprünglichen Post postete, ist mein Testprogramm für diese Lösungen, die bisher bereitgestellt wurden. Um dies zu verdeutlichen, können Sie mit der rechten Maustaste auf die Nachricht klicken, die in meinem Beispielbild durch ein rotes Kästchen markiert ist (die Nachricht wurde geändert, das DOM nicht), und Sie können die Debug-Ausgabe "Get link" erhalten Ort, in neuem Tab öffnen. "?, denn je nachdem, wo ich auf diesen News-Artikel (Element) klicke, bekomme ich entweder" DIV "oder" SPAN ". Können Sie einen Screenshot von dem, was Sie mit der rechten Maustaste klicken und der Ausgabe? – TEK

+0

Ja, Ihr Code allein funktioniert für BBC. Vielleicht ist die britische Version jedoch anders. Ich bekomme immer das Anker-Tag, egal wo ich darauf klicke. Hier ist ein Bild: http://imgur.com/4uAB04p. Ich habe versucht auf anderen Seiten, wo der Anker hinter einem Header-Tag ist und der obige Code funktioniert. –

+0

Danke für das Posten des Bildes ... Ich begann zu denken, dass ich verrückt wurde! Das ist wirklich sehr verwirrend. Es zeigt einfach kein Element mit dem Tagnamen "A" für diese Nachrichten. :/ – TEK

1

Die Herausforderung bei bbc Website, dass es wenig Nicht-Standard-Ansatz in Richtung ihrer URL haben. geht Unterhalb einer der Proben ihrer a href:

<A tabIndex=-1 aria-hidden=true class=block-link__overlay-link href="http://www.bbc.com/news/world-africa-36132482" rev=hero5|overlay>Barbie challenges the 'white saviour complex' </A> 

so, was Sie brauchen, wenn in zwei Teile verwenden:
1. element.TagName == "A" 2. Check href wie dieses Attribut : element.GetAttribute ("href")

Diese beiden Überprüfungen können Ihnen garantieren, dass Sie sich mit etwas mit dem Tag a beschäftigen, und dieses Tag hat das Attribut href. Siehe ein anderes Anwendungsbeispiel:

private void Document_MouseDown(object sender, HtmlElementEventArgs e) 
    { 
     if (e.MouseButtonsPressed == MouseButtons.Right) 
     { 
      HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); 
      //I assume I need to check if this element has child elements that contain a TagName "A" 
      if (element.TagName == "A" && !string.IsNullOrEmpty(element.GetAttribute("href")))//it means we have deal with href 
      { 
       Debug.WriteLine("Get link location, open in new tab."); 
       var url = element.GetAttribute("href"); 
       Debug.WriteLine(url); 
      } 

      else 
       Debug.WriteLine(element.TagName); 
     } 
    } 
+0

Ich schätze Ihre fortgesetzten Bemühungen sehr, aber je nachdem, wo ich mit der rechten Maustaste auf das jeweilige Schlagzeilenelement klicke, gibt es entweder "DIV" oder "SPAN", ich kann das Kindankerelement ('A') überhaupt nicht bekommen. In der Tat, was ich jetzt beobachtet habe, ist, dass, wenn der Anker Kind * irgendeines * Elements von * irgendeiner * Webseite ist, ich nicht darauf zugreifen kann. Mein 'WebBrowser'-Steuerelement wurde nicht bearbeitet, und ich benutze das einfache Beispiel, das ich als Basis für eine dieser geposteten Lösungen gepostet habe, so dass ich mir nicht ganz sicher bin, was vor sich geht. – TEK