最近做实验需要数据, 数据需要labeling, labeling需要tool, 于是需要做个类似于山寨版的Element Inspector或者FireDebug的小东东… 一开始想直接在WebBrowser上用System.Drawing画框框, 结果总是被WebBrowser控件盖住, 遂用hack HTML的方法搞定之, 即直接向HtmlDocument对象注入HtmlElement, 达到highlight网页元素的目的. 引用Microsoft.mshtml库, 调用IHTMLElement接口, 便可以方便地设置DIV style.
比较麻烦的地方是DIV的定位. 尝试过使用cursor.ClientRectangle的各种属性都失败了. 后来发现cursor.OffsetRectangle属性可以用, 但它仅用来表示当前节点和其parent节点间的相对位置, 因此需要递归 (或循环) 向上查找父节点直到根节点, 并累加这些offset, 从而得到最终的position. 代码整理了一下放在下面.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
using mshtml; private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e) { HtmlDocument htmlDoc = webBrowser1.Document; htmlDoc.MouseOver += new HtmlElementEventHandler(HtmlDocument1_MouseOver); } private void HtmlDocument1_MouseOver(Object sender, HtmlElementEventArgs e) { try { HtmlElement cursor = e.ToElement; HtmlDocument doc = webBrowser1.Document; HtmlElement cur = doc.GetElementById("labelingRect"); HtmlElement labelElem = null; //Detect existing highlight DIV if (cur == null) //Take effect only on the first time when cursor enter into WebBrowser { labelElem = doc.CreateElement("DIV"); labelElem.Id = "labelingRect"; if (doc.Body != null) doc.Body.AppendChild(labelElem); } else //Already exists highlight DIV, just update it when cursor moves { labelElem = cur; } //Set DIV style IHTMLElement rect = labelElem.DomElement as IHTMLElement; rect.style.setAttribute("position", "absolute", 0); rect.style.visibility = "visible"; rect.style.borderColor = "red"; rect.style.borderStyle = "solid"; rect.style.borderWidth = "2"; rect.style.zIndex = 2012; //Set the location and size of DIV int width = cursor.ClientRectangle.Right - cursor.ClientRectangle.Left; int height = cursor.ClientRectangle.Bottom - cursor.ClientRectangle.Top; int left = getXoffset(cursor); int top = getYoffset(cursor); rect.style.left = left; rect.style.top = top; rect.style.width = width; rect.style.height = height; //Hide one-point DIV if (width == 0 || height == 0) rect.style.visibility = "hidden"; } catch { } } public int getXoffset(HtmlElement el) { //Get element position int xPos = el.OffsetRectangle.Left; //Get the parents position HtmlElement tempEl = el.OffsetParent; while (tempEl != null) { xPos += tempEl.OffsetRectangle.Left; tempEl = tempEl.OffsetParent; } return xPos; } public int getYoffset(HtmlElement el) { //Get element position int yPos = el.OffsetRectangle.Top; //Get the parents position HtmlElement tempEl = el.OffsetParent; while (tempEl != null) { yPos += tempEl.OffsetRectangle.Top; tempEl = tempEl.OffsetParent; } return yPos; } |
另一个需要注意的地方是zIndex这个属性, MSDN Library的解释是”stacking order of positioned objects”, 其实就是网页元素的层叠属性, 设置一个很大的值 (例如代码中的2012), 即可避免需要highlight的DIV被其他元素覆盖.
本文在 BY-NC-SA 3.0 版权协议下发布, 转载请注明出自 zhangyuyu.com .