简体   繁体   中英

I must be a heretic for wanting a C# browser with both NewWindow2 and GetElementsByTagName

You can't have your cake and eat it too, apparently.

I'm currently using the System.Windows.Forms.WebBrowser in my application. The program currently depends on using the GetElementsByTagName function. I use it to gather up all the elements of a certain type (either "input"s or "textarea"s), so I can sort through them and return the value of a specific one. This is the code for that function (my WebBrowser is named web1):

// returns the value from a element.
public String FetchValue(String strTagType, String strName) 
{
    HtmlElementCollection elems;
    HtmlDocument page = web1.Document.Window.Frames[1].Document;
    elems = page.GetElementsByTagName(strTagType);
    foreach (HtmlElement elem in elems)
    {
        if (elem.GetAttribute("name") == strName ||
            elem.GetAttribute("ref") == strName)
        {
            if (elem.GetAttribute("value") != null)
            {
                return elem.GetAttribute("value");
            }
        }
    }

    return null;
}

(points to note: the webpage I need to pull from is in a frame, and depending on circumstances, the element's identifying name will be either in the name or the ref attribute)

All of that works like a dream with the System.Windows.Forms.WebBrowser .

But what it is unable to do, is redirect the opening of a new window to remain in the application. Anything that opens in a new window shoots to the user's default browser, thus losing the session. This functionality can be easily fixed with the NewWindow2 event, which System.Windows.Forms.WebBrowser doesn't have.

Now forgive me for being stunned at its absence. I have but recently ditched VB6 and moved on to C# (yes VB6, apparently I am employed under a rock), and in VB6, the WebBrowser possessed both the GetElementsByTagName function and the NewWindow2 event.

The AxSHDocVw.WebBrowser has a NewWindow2 event. It would be more than happy to help me route my new windows to where I need them. The code to do this in THAT WebBrowser is (frmNewWindow being a simple form containing only another WebBrowser called web2 (Dock set to Fill)):

private void web1_NewWindow2(
                      object sender, 
                      AxSHDocVw.DWebBrowserEvents2_NewWindow2Event e)
{
    frmNewWindow frmNW = new frmNewWindow();
    e.ppDisp = frmNW.web2.Application;
    frmNW.web2.RegisterAsBrowser = true;
    frmNW.Visible = true;
}

I am unable to produce on my own a way to replicate that function with the underwhelming regular NewWindow event.

I am also unable to figure out how to replicate the FetchValue function I detailed above using the AxSHDocVw.WebBrowser . It appears to go about things in a totally different way and all my knowledge of how to do things is useless.

I know I'm a sick, twisted man for this bizarre fantasy of using these two things in a single application. But can you find it in your heart to help this foolish idealist?

I could no longer rely on the workaround, and had to abandon System.Windows.Forms.WebBrowser. I needed NewWindow2.

I eventually figured out how to accomplish what I needed with the AxWebBrowser. My original post was asking for either a solution for NewWindow2 on the System.Windows.Forms.WebBrowser, or an AxWebBrowser replacement for .GetElementsByTagName. The replacement requires about 4x as much code, but gets the job done. I thought it would be prudent to post my solution, for later Googlers with the same quandary. (also in case there's a better way to have done this)

IHTMLDocument2 webpage = (IHTMLDocument2)webbrowser.Document;
IHTMLFramesCollection2 allframes = webpage.frames;
IHTMLWindow2 targetframe = (IHTMLWindow2)allframes.item("name of target frame");
webpage = (IHTMLDocument2)targetframe.document;
IHTMLElementCollection elements = webpage.all.tags("target tagtype");

foreach (IHTMLElement element in elements)
{
  if (elem.getAttribute("name") == strTargetElementName)
   {
     return element.getAttribute("value");
   }
}

The webbrowser.Document is cast into an IHTMLDocument2, then the IHTMLDocument2's frames are put into a IHTMLFramesCollection2, then I cast the specific desired frame into an IHTMLWindow2 (you can choose frame by index # or name), then I cast the frame's .Document member into an IHTMLDocument2 (the originally used one, for convenience sake). From there, the IHTMLDocument2's .all.tags() method is functionally identical to the old WebBrowser.Document.GetElementsByTagName() method, except it requires an IHTMLElementCollection versus an HTMLElementCollection. Then, you can foreach the collection, the individual elements needing to be IHTMLElement, and use .getAttribute to retrieve the attributes. Note that the g is lowercase.

The WebBrowser control can handle the NewWindow event so that new popup windows will be opened in the WebBrowser.

private void webBrowser1_NewWindow(object sender, CancelEventArgs e)
{
  // navigate current window to the url
  webBrowser1.Navigate(webBrowser1.StatusText);
  // cancel the new window opening
  e.Cancel = true;
}

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/361b6655-3145-4371-b92c-051c223518f2/

The only solution to this I have seen was a good few years ago now, called csExWb2, now on Google code here .

It gives you an ExWebBrowser control, but with full-on access to all the interfaces and events offered by IE. I used it to get deep and dirty control of elements in a winforms-hosted html editor.

It may be a bit of a leap jumping straight into that, mind.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM