Working with HTML DOM in Silverlight 2 Beta 1 using the Bridge Pattern
Working with the HTML DOM in Silverlight 2 Beta 1 is rather simple and easy to do. However, to my surprise it’s a similar experience to working the the HTML DOM from within JavaScript; you have to know the name of the properties to get/set and you don’t have the luxury of compile time checking or intellisense.
Here an example of creating a new DIV element and setting some of it’s properties:
HtmlElement myDiv = HtmlPage.Document.CreateElement("div");
// Set the innerHTML property
myDiv.SetProperty("innerHTML", "**Some HTML Content**");
// Set some style properties
myDiv.SetStyleAttribute("border", "solid 1px black");
myDiv.SetStyleAttribute("position", "absolute");
myDiv.SetStyleAttribute("top", "10px");
myDiv.SetStyleAttribute("left", "10px");
// Add the myDiv element to the page
HtmlPage.Document.Body.AppendChild(myDiv);
// Get the innerHTML property
string html = myDiv.GetProperty("innerHTML");
// Get the Position Style attribute
string pos = myDiv.GetStyleAttribute("position");
As you can see from the above example, the HtmlElement object doesn’t have any real properties or style attributes, you must work with the helper methods to get/set them. I was a little surprised to see this at first, and I don’t know if they plan on adding any properties to the object in the final release or if they are doing this to just make the Silverlight download smaller.
Can We Extend the HtmlElement to Add Property Accessors?
Yes, but not through inheritance. For some reason they decided to make the System.Windows.Browser.HtmlElement class Sealed! So, instead we’ll have to use the Bridge Pattern to create a wrapper object that will have all the desired property accessors.
Here’s an example of using a class that implements the Bridge Pattern to do the exact same as above:
HtmlElementHelper myDiv = new HtmlElementHelper(HtmlPage.Document.CreateElement("div"));
myDiv.innerHTML = "**Some HTML Content**";
myDiv.Style.Position = "absolute";
myDiv.Style.Border = "solid 1px black";
myDiv.Style.Top = "10px";
myDiv.Style.Left = "10px";
HtmlPage.Document.Body.AppendChild(myDiv.Element);
Not only is the code using the Bridge Pattern easier to read, but now we have the benefit of compile time checking of our DIV elements properties. No need to worry if you misspelled any of the property names anymore.
Full Source Code for the HtmlElementHelper Bridge class
public class HtmlElementHelper
{
private HtmlElement _elem = null;
private HtmlElementStyleHelper _styleHelper = null;
public HtmlElementHelper(HtmlElement elem)
{
this._elem = elem;
}
public HtmlElement Element
{
get { return _elem; }
}
public object GetProperty(string propertyName)
{
return _elem.GetProperty(propertyName);
}
public void SetProperty(string propertyName, object value)
{
_elem.SetProperty(propertyName, value);
}
public HtmlElementStyleHelper Style
{
get
{
if (_styleHelper == null)
{
_styleHelper = new HtmlElementStyleHelper(this._elem);
}
return _styleHelper;
}
}
public string innerHTML
{
get { return GetProperty("innerHTML") as string; }
set { this.SetProperty("innerHTML", value); }
}
public string innerText
{
get { return GetProperty("innerText") as string; }
set { this.SetProperty("innerText", value); }
}
public string className
{
get { return GetProperty("className") as string; }
set { SetProperty("className", value); }
}
public string Id
{
get { return _elem.Id; }
set { _elem.Id = value; }
}
}
public class HtmlElementStyleHelper
{
private HtmlElement _elem = null;
public HtmlElementStyleHelper(HtmlElement elem)
{
this._elem = elem;
}
public string GetAttribute(string name)
{
return _elem.GetStyleAttribute(name);
}
public void SetAttribute(string name, string value)
{
_elem.SetStyleAttribute(name, value);
}
public string Position
{
get { return GetAttribute("position"); }
set { SetAttribute("position", value); }
}
public string Border
{
get { return GetAttribute("border"); }
set { SetAttribute("border", value); }
}
public string Top
{
get { return GetAttribute("top"); }
set { SetAttribute("top", value); }
}
public string Left
{
get { return GetAttribute("left"); }
set { SetAttribute("left", value); }
}
public string Width
{
get { return GetAttribute("width"); }
set { SetAttribute("width", value); }
}
public string Height
{
get { return GetAttribute("height"); }
set { SetAttribute("height", value); }
}
}
Conclusion
I have actually never had such a useful need to use the Bridge Pattern before, and this time it really saves the day. I hope Microsoft adds better support for the different HTML DOM Elements properties and style properties to the Silverlight 2 final release, or at least open up the HtmlElement object for inheritance. If neither, at least we can use the Bridge Pattern to fulfill our needs.