Listing 1 Implementing IElementBehavior
namespace BinBehaviors { [ ComVisible(true), IElementBehaviorSiteOM bsiteOM; IHTMLPaintSite paintsite; IHTMLDocument2 document; IHTMLWindow2 parwindow; IHTMLElement element; HTMLElementEvents_Event events; Point point1, point2; float penwidth; Color pencolor; int xoffset, yoffset; Bitmap bitmap; /// <summary> /// A default constructor (no parameters) is necessary for COM instantiation /// </summary> public Line() { point1 = new Point(0, 0); point2= new Point(0, 0); penwidth = 1; pencolor = Color.Black; xoffset = yoffset = (int) this.penwidth + 1; } ~Line() { } /// <summary> /// Gets or sets the end points of the line as a single string. /// </summary> public string coords { get { return String.Format("{0} {1} {2} {3}", point1.X, point1.Y, point2.X, point2.Y); } set { UpdateCoords(value); DoLineDraw(); } } // IElementBehavior method. void mshtml2.IElementBehavior.Init(IElementBehaviorSite behavsite) { try { this.bsite = behavsite; if (behavsite is IElementBehaviorSiteOM) this.bsiteOM = (IElementBehaviorSiteOM) behavsite; if (behavsite is mshtml.IHTMLPaintSite) this.paintsite = (mshtml.IHTMLPaintSite) behavsite; } catch (System.ExecutionEngineException e) { MessageBox.Show(e.Message); } } // IElementBehavior method. void mshtml2.IElementBehavior.Notify(int lEvent, System.IntPtr pVar) { try { switch ((_BEHAVIOR_EVENT)lEvent) { case _BEHAVIOR_EVENT.BEHAVIOREVENT_DOCUMENTREADY: if (this.bsite == null) return; this.element = this.bsite.GetElement(); // Cache the HTML element. this.document = (IHTMLDocument2) this.element.document; this.parwindow = (IHTMLWindow2) document.parentWindow; // Drawing to absolute point locations // requires absolute position style. element.style.setAttribute("position", "absolute", 0); // Hook up event handlers. if (element is mshtml.HTMLElementEvents_Event) { this.events = (HTMLElementEvents_Event) this.element; events.onpropertychange += new mshtml.HTMLElementEvents_onpropertychangeEventHandler( HTMLElement_OnPropertyChange); } // Initial attribute values. // All HTML attributes come in as strings (or null, if not present). // "coords" property is ONLY a property, not an attribute. string x1 = element.getAttribute("x1", 0) as string; string y1 = element.getAttribute("y1", 0) as string; string x2 = element.getAttribute("x2", 0) as string; string y2 = element.getAttribute("y2", 0) as string; if (x1 != null) point1.X = Convert.ToInt32(x1); if (y1 != null) point1.Y = Convert.ToInt32(y1); if (x2 != null) point2.X = Convert.ToInt32(x2); if (y2 != null) point2.Y = Convert.ToInt32(y2); // ARGB must come in hexadecimal form. string argbstring = element.getAttribute("argb", 0) as string; if (argbstring != null) this.pencolor = Color.FromArgb( (int) Convert.ToUInt32(argbstring, 16)); // Width must be base 10. string widthstring = (string) element.getAttribute("width", 0) as string; if (widthstring != null) { this.penwidth = Convert.ToSingle(widthstring); xoffset = yoffset = (int) this.penwidth + 1; } DoLineDraw(); break; case _BEHAVIOR_EVENT.BEHAVIOREVENT_FIRST: //MessageBox.Show("event: first"); break; case _BEHAVIOR_EVENT.BEHAVIOREVENT_LAST: MessageBox.Show("event: last"); break; case _BEHAVIOR_EVENT.BEHAVIOREVENT_APPLYSTYLE: MessageBox.Show("event: apply style"); break; default: MessageBox.Show("event: (default)"); break; } } catch (System.ExecutionEngineException e) { MessageBox.Show(e.Message); } } // IElementBehavior method. void mshtml2.IElementBehavior.Detach() { } /// <summary> /// Handle the element's OnPropertyChange event. /// Update the drawing to reflect the new property values. /// </summary> public void HTMLElement_OnPropertyChange() { IHTMLEventObj2 evo = (IHTMLEventObj2) parwindow.@event; string name = evo.propertyName.ToLower(); object o = element.getAttribute(evo.propertyName, 0); switch (name) { case "x1": if (o is System.Int32) point1.X = (int) o; break; case "y1": if (o is System.Int32) point1.Y = (int) o; break; case "x2": if (o is System.Int32) point2.X = (int) o; break; case "y2": if (o is System.Int32) point2.Y = (int) o; break; case "coords": // NOT CALLED, because of our coords property (above) UpdateCoords((string) o); // Object is a string (BSTR). break; case "width": if (o is System.Int32) penwidth = (int) o; break; case "argb": // ARGB will come as double if too big to fit as Int32. if (o is System.Double) pencolor = Color.FromArgb((int) Convert.ToUInt32((double) o)); else if (o is System.Int32) pencolor = Color.FromArgb((int) o); break; default: break; } DoLineDraw(); } /// <summary> /// Update the coordinates members (x1, y1, x2, y2) /// given a string representation. /// </summary> /// <param name="coords">String representation of x1, y1, x2, y2.</param> private void UpdateCoords(string coords) { // May have: coords=" x1 ;y1 , x2 y2 ", etc. string s = coords.Trim(); Regex re = new Regex("\\s*[,;]\\s*|\\s+"); // Separate at: space | punct. // Order of alts is important. string[] segs = re.Split(s, 5); if (segs.Length >= 4) { point1.X = Convert.ToInt32(segs[0]); point1.Y = Convert.ToInt32(segs[1]); point2.X = Convert.ToInt32(segs[2]); point2.Y = Convert.ToInt32(segs[3]); UpdateAttributes(); } } /// <summary> /// Update the HTML attributes to reflect actual property values. /// </summary> private void UpdateAttributes() { this.element.setAttribute("x1", point1.X.ToString(), 0); this.element.setAttribute("y1", point1.Y.ToString(), 0); this.element.setAttribute("x2", point2.X.ToString(), 0); this.element.setAttribute("y2", point2.Y.ToString(), 0); } // . } }