Thursday, June 21, 2007

The last configuration handler I'll ever need...really

Scott Weinstein has a fantastic approach to deserializing configuration sections. I would like to propose an improvement though: make the class generic. Here's a simplified version:

Public Class XmlSerializerSectionHandler(Of T)
Implements IConfigurationSectionHandler

Public Function Create(ByVal parent As Object, ByVal configContext As Object, ByVal section As System.Xml.XmlNode) Implements IConfigurationSectionHandler.Create


Dim nav As XPathNavigator = section.CreateNavigator()

Dim ser As New XmlSerializer(GetType(T))

Return ser.Deserialize(New XmlNodeReader(section))

End Function

End Class

This eliminates the need to embed the type attribute in the data tag and moves it into the type declaration in the section tag. This...

<namessection type="TheMechanicalBride.Web.NamesSection, TheMechanicalBride.Web">
<name>Jafar Husain</name>
<name>Johhny</name>
</namessection>

Becomes...

<namessection>
<name>Jafar Husain</name>
<name>Johhny</name>
</namessection>

snip

<section name="namessection" type="TheMechanicalBride.Web.XmlSerializerSectionHandler `1[[TheMechanicalBride.Web.NamesSection, TheMechanicalBride.Web]]"/>


This is a minor modification but is definitely an improvement as the tag that contains the data no longer needs any awareness of the method by which it is serialized and deserialized.

Slaying CSS bugs with AJAX for ASP.NET

Recently I've been working on an ASP.NET project and am writing a whole host of custom controls. I really can't emphasize enough the power of custom controls. They are code which writes code, allowing you to build DSL's for expressing user-interface elements.

When building custom controls it's nice to make the elements in the control scale with the size of the control itself. This probably means that you will be using tables for any sufficiently complex control. Unfortunately in IE 5 and 6, if you nest a textbox inside of a table cell and make its width 100% the end of the textbox get's cut off thusly:



Attempts to correct this by specifying a value for margin-right are rudely ignored by IE. You can test this yourself by trying out the following code:


<span ><span id="ctl00_Main_PercentField1" style="display:inline-block;width:50px;"><table border="0" style="width:100%;"></span>
<span style="font-family: courier new;"> <tr></span>
<span > <td><div><input name="ctl00$Main$PercentField1$TextBox1" type="text" value="23" id="txt" style="width:100%"></div></td></span>
<span style="font-family: courier new;"> </tr></span>
<span ></table></span></span>

After confirming that this problem was a known bug I did the first thing most developers do: I bitched and moaned. There is not much web developers can do about browser CSS bugs. Or can they?

I've been doing heavy DHTML programming since the days of IE4 and am aware of a little known property called clientWidth. This property gives you access to the actual width of a UI element in pixels. All I needed to do, I figured was get the textbox using the DOM methods and set the CSS width to the clientWidth and subtract some absolute value. Sure enough it worked like a charm. Ten pixels is the magic number for some reason.



In addition to custom controls I've also been writing control extenders using AJAX for ASP.NET. I've complained about AJAX for ASP.NET in the past but I must admit it's a very elegant way of encapsulating javascript behaviors. It was child's play to create a custom extender that I could point to a textbox that was positioned inside a table. Here is the code:

FixTextBoxWidthBehavior.js
----------------
Type.registerNamespace('TheMechanicalBride')

TheMechanicalBride.FixTextBoxWidthBehavior = function(element)
{
GE.Water.Web.FixTextBoxWidthBehavior.initializeBase(this,[element]);

}

TheMechanicalBride.FixTextBoxWidthBehavior.prototype = {

initialize: function()
{
TheMechanicalBride.FixTextBoxWidthBehavior.callBaseMethod(this,'initialize')

var e = this.get_element();
e.style.width = "" + (e.clientWidth-10) + "px"


},

dispose : function()
{
TheMechanicalBride.FixTextBoxWidthBehavior.callBaseMethod(this,'dispose')


}
}

TheMechanicalBride.FixTextBoxWidthBehavior.registerClass('TheMechanicalBride.FixTextBoxWidthBehavior', AjaxControlToolkit.BehaviorBase);



------------------

FixTextBoxWidthExtender.vb
---------------------




Imports System
Imports System.Web.UI.WebControls
Imports System.Web.UI
Imports System.ComponentModel
Imports AjaxControlToolkit


<Assembly: WebResource("TheMechanicalBride.FixTextBoxWidthBehavior.js", "text/javascript")>

Namespace UI.WebControls

<ClientScriptResource("GE.Water.Web.FixTextBoxWidthBehavior", "GE.Water.Web.FixTextBoxWidthBehavior.js")> _
<TargetControlType(GetType(TextBox))> _
<RequiredScript(GetType(CommonToolkitScripts), 0)> _
Public Class FixTextBoxWidthExtender
Inherits ExtenderControlBase

Public Sub New()

End Sub

End Class

End Namespace



And that's it. The lesson: in the age of modern browsers you don't always have to accept CSS bugs. Get hacking.

About Me

My photo
I'm a software developer who started programming at age 16 and never saw any reason to stop. I'm working on the Presentation Platform Controls team at Microsoft. My primary interests are functional programming, and Rich Internet Applications.