I need the correct css path from a webpage, which will be displayed in my WPF application(to use it later with HTMLAgilityPack and/or Fizzler).

Something like this, to "copy css-path" or xpath(FireBug), should be the final goal.

I also found some interesting post like:

They all use "webBrowser.Document.GetElementFromPoint", "webBrowser.GetElementFromPoint" or "PointToClient", but I can not find it in any library and not even on msdn.microsoft(WebBrowser Class)

By the way I use the "WebBrowserControl" from visual studio 2010 toolbox to display my webpage.

Then I found some function on the client-side, but this can not be the thing they meant(javascript)...

updated:12 th june, 08:15 pm

This is actually a nice post by "dick":

    private void myBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
    dynamic doc = myBrowser.Document;
    dynamic htmlText = doc.documentElement.InnerHtml;
    string htmlstring = htmlText;
}

This works, but this stands in no relation to my WPF element. I get only the html but not the corresponding element. I could search for the text in that html doc, but if it appears more than once, its is not unique anymore.

updated: 13 th june, 07:15 a.m

Based on this tutorial I found a workaround.

I included this namespace in my ".xaml":

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

Then I added the the old winforms browser:

<WindowsFormsHost Name="wfhSample" Margin="372,12,12,205" MouseLeftButtonDown="wfhSample_MouseLeftButtonDown">
    <WindowsFormsHost.Child>
        <wf:WebBrowser />
    </WindowsFormsHost.Child>
</WindowsFormsHost>

Added to my "MainWindow()" a starting value:

MainWindow(){
 (wfhSample.Child as System.Windows.Forms.WebBrowser).Navigate("http://www.google.de/");
 }

The actual part, to get the element:

 /*
    System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
    ...myMethod(..., (wfhSample.Child as System.Windows.Forms.WebBrowser), point.X, point.Y);
    */
     ...myMethod(...,System.Windows.Forms.WebBrowser refWebBrowser2,Int32 valScreenX, Int32 valScreenY,....){

    Point refPoint = refWebBrowser2.PointToClient(new Point(valScreenX, valScreenY));

    System.Windows.Forms.HtmlElement refHtmlElement = refWebBrowser2.Document.GetElementFromPoint(refPoint); //System.Drawing()

    return refHtmlElement.TagName;
    }

The only problem,which is left by now is that the event handler does not fire(I added them over the properties window):

//winforms-browser
                    private void wfhSample_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MessageBox.Show("old");

        }

        //wpf-browser
                private void browser_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MessageBox.Show("new");

        }

Why can't I overwrite the event handler(not even the right button) ?

updated: 13 th june, 07:45 a.m

This could be an useful article, I will check this out.

updated: 16 th june, 07:00 a.m

Now I found a solution, where I can handle an event for a wpf-webbrowser, but not for the old winforms-browser.

    //new WPF webbrowser  
      private void browser_LoadCompleted(object sender, NavigationEventArgs e)
            {
                mshtml.HTMLDocument doc;
                doc = (mshtml.HTMLDocument)browser.Document;
                mshtml.HTMLDocumentEvents2_Event iEvent;
                iEvent = (mshtml.HTMLDocumentEvents2_Event)doc;
                iEvent.onclick += new mshtml.HTMLDocumentEvents2_onclickEventHandler(NewClickEventHandler);
            }

             private bool NewClickEventHandler(mshtml.IHTMLEventObj e)
            {
            //the click event handler works, but I have no access to "GetElementFromPoint"
 // it does not exist
                        //Point refPoint = browser.PointToClient(new Point(valScreenX, valScreenY));
                //System.Windows.Forms.HtmlElement refHtmlElement = browser.Document.GetElementFromPoint(refPoint);
                //return refHtmlElement.TagName;
                //because the new wpf control does not support for example 'GetElementFromPoint()'
            // I need to get the html controls conntected to the wpf cursor
            }

This helped me and I changed the event handling for Winforms webbrowser in my wpf application to:

//old Winforms webbrowser
        private void wfhSample_ChildChanged(object sender, System.Windows.Forms.Integration.ChildChangedEventArgs e)
        {
        //registering the event here, 
        //calling "OldClickEventHandler" does not work I get a "NullReferenceException" for "_docEvent"
         HTMLDocumentEvents2_Event _docEvent= (HTMLDocumentEvents2_Event)(wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;
            _docEvent.onclick += new HTMLDocumentEvents2_onclickEventHandler(OldClickEventHandler);
        }
                    private bool OldClickEventHandler(mshtml.IHTMLEventObj e)
            {
            }

At the moment I still do not get the element from the webbrowser which I selected in my WPF-application on the one hand I have a problem with an event for the old webforms webbrowser, where I get a "NullReferenceException"(actually it should not be null from my point of view) and on the other hand for my new(wpf) webbrowser control I can not access "GetElementFromPoint()" because it does not seem to exist for the wpf webbrowser control.

updated: 17 th june, 10:00 a.m

It seems, that

(HTMLDocumentEvents2_Event)(wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;

which is inside "wfhSample_ChildChanged" is not ready yet, because when I put the same statement:

(HTMLDocumentEvents2_Event)(wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;

into "NewClickEventHandler(mshtml.IHTMLEventObj e)" it has the required data in it(,but this is the wrong event handler).

So, now I need to find the correct/proper event handler for my old wpf browser.

updated: 17 th june, 11:30 a.m

Ok, now I found a solution based on this article, I changed my code to:

   private void wfhSample_Loaded(object sender, RoutedEventArgs e)
    {
        bool complete = false;
        (wfhSample.Child as System.Windows.Forms.WebBrowser).DocumentCompleted += delegate
        {
            if (complete)
                return;
            complete = true;
            // DocumentCompleted is fired before window.onload and body.onload
            (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.Window.AttachEventHandler("onload", delegate
            {
                // Defer this to make sure all possible onload event handlers got fired
                System.Threading.SynchronizationContext.Current.Post(delegate
                {
                    // try webBrowser1.Document.GetElementById("id") here
                    //System.Windows.MessageBox.Show("window.onload was fired, can access DOM!");
                    var bla = (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;
                    HTMLDocumentEvents2_Event _docEvent = (HTMLDocumentEvents2_Event)(wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;
                    _docEvent.onclick += new HTMLDocumentEvents2_onclickEventHandler(OldClickEventHandler);
                }, null);
            });
        };

        (wfhSample.Child as System.Windows.Forms.WebBrowser).Navigate("http://www.example.com");
    }
    private bool OldClickEventHandler(mshtml.IHTMLEventObj e)
    {
        System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
        System.Drawing.Point refPoint = (wfhSample.Child as System.Windows.Forms.WebBrowser).PointToClient(new System.Drawing.Point(point.X, point.Y));
        System.Windows.Forms.HtmlElement refHtmlElement = (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.GetElementFromPoint(refPoint);
        var restult = refHtmlElement.TagName; //this is what I need for the first time,to continue
        return true;
    }

And the event handling for the old control works :)

But the "var restult = refHtmlElement.TagName;" returns a "NullReferenceException", there seems to be something wrong with the coordinates.

As soon as I have a solution I will post it or if you have an idea you can help as well:)

1

There are 1 answers

0
user254197 On BEST ANSWER

Ok,I found a solution including the winform webbrowser into my wpf application(take a look at my question regarding, processes and resources):

1.The .xaml part(namespace)(more details):

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

2.The .xaml part(WebBrowser)(more details):

<WindowsFormsHost Name="wfhSample" Margin="372,12,12,205" Loaded="wfhSample_Loaded">
    <WindowsFormsHost.Child>
        <wf:WebBrowser />
    </WindowsFormsHost.Child>
</WindowsFormsHost>

3.The code behind file(more details):

   private void wfhSample_Loaded(object sender, RoutedEventArgs e)
    {
        bool complete = false;
        (wfhSample.Child as System.Windows.Forms.WebBrowser).DocumentCompleted += delegate
        {
            if (complete)
                return;
            complete = true;
            // DocumentCompleted is fired before window.onload and body.onload
            (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.Window.AttachEventHandler("onload", delegate
            {
                // Defer this to make sure all possible onload event handlers got fired
                System.Threading.SynchronizationContext.Current.Post(delegate
                {
                    // try webBrowser1.Document.GetElementById("id") here
                    //System.Windows.MessageBox.Show("window.onload was fired, can access DOM!");
                    var bla = (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;
                    HTMLDocumentEvents2_Event _docEvent = (HTMLDocumentEvents2_Event)(wfhSample.Child as System.Windows.Forms.WebBrowser).Document.DomDocument;
                    _docEvent.onclick += new HTMLDocumentEvents2_onclickEventHandler(OldClickEventHandler);
                }, null);
            });
        };

        (wfhSample.Child as System.Windows.Forms.WebBrowser).Navigate("http://www.example.com");
    }
    private bool OldClickEventHandler(mshtml.IHTMLEventObj e)
    {
        System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
        System.Drawing.Point refPoint = (wfhSample.Child as System.Windows.Forms.WebBrowser).PointToClient(new System.Drawing.Point(point.X, point.Y));
        System.Windows.Forms.HtmlElement refHtmlElement = (wfhSample.Child as System.Windows.Forms.WebBrowser).Document.GetElementFromPoint(refPoint);
        var restult = refHtmlElement.TagName; 
        return true;
    }

4.To get the full CSS-Path or XPath you could use Fizzler, HTMLAgilityPack(this).

Sometimes it is a little buggy(resizing window, changing tabs), the event handler does not fire anymore.