Introduction
ASP.NET lacks a WebForm based Property Grid control which
allows direct modification of objects honoring their component model
attributes. Third party or open source
contributions seem too clunky or just poorly implemented. While developing a custom framework recently
I found myself needing to instrument quite a few ASP.NET web pages that manipulated
my business objects. I did not have a
lot of time to manually craft these pages to fit the unique requirements of my
business objects, so I opted to spend a few hours to write an ASP.NET web based
Property Grid kind of user control. I primarily
wanted the user control to interrogate a single object dynamically, building the
necessary HTML input tags required to read and manipulate the public properties
of a class. This control is not perfect
and there is plenty of room for improvement.
Details
OK, first things first:
How does this User Control speed
up web page development? Typically building web pages that collect user
input and applies this input to a backend
database is very time consuming. Labels,
various input controls, formatting, conditional display or read/write behavior,
etc… take time to implement. And,
various CRUDL ([C]reate [R]ead [U]pdate [D]elete [L]ist) functions may span a
multitude of pages, or in some sad situations may be all jammed into one overly
complex web page. We typically have to a
lot of tedious work just to read data from, push new data to or update existing
data in a database. Also, if an object
changes, the web page(s) that invoke that object must change too. I am a firm believer of keeping database
select statements and store procedure calls out of the user interface markup,
instead using middle tier (Business Objects) to handle database activities. The Object Web Editor is capable of
interrogating an invoked class , reading its component model attributes,
rendering the Name of Properties, as well as the most appropriate Input User
Control, “on the fly” as well as collecting and applying PostBack data to the
object for further disposition. This
significantly decreases the amount of HTML form work required allowing web
pages to be implemented quickly. Also, a
pleasant side effect of this user control is pages are implemented consistently.
The Microsoft
System.ComponentModel
namespace provides the
means of marking up a class in such a way that object meta data will contain
design-time/run-time “rules” for engaging and object instance of a given
class. At the heart of the Object Web
Editor is its ability to recursively Reflect into an object instance reading
each property detecting its data type and providing the proper access based in
property designer attributes.
Let us take a peek at how this user control is used on a web
page and what it does when the page is loaded. Below is a screenshot of a simple web page of which invokes a
Person
class in its code-behind.
Here we see the dynamically created HTML rendered by the
Object Web Editor and the left, and the design-time view of the ASP.NET web
page and code-behind on the right. I
opted not to spend a lot of time on the design-time rendering and editing
aspects of this User Control so there is no design-time rendered HTML or
related property editor. The web page
defines the following in its markup…
<owe:ObjectWebEditor
id="personEditor"
runat="server"
ViewStateMode ="Enabled"
HiddenProperties="Exceptions" >
<owe:PropertyMap
PropertyName="HomePage"
LinkDescription="My Home Page"
URL="MyHomePage.aspx?SSN={SSN}"
ToolTip="Visit my Home Page" />
</owe:ObjectWebEditor>
I will cover the not-so-obvious properties of this custom
user control.
HiddenProperties
– This string contains a coma-delimited
list of object properties that you do not wish to show. “Show” meaning,
dynamically generate HTML to
allow viewing and possibly editing of these properties. In the example above, I have excluded the
Exceptions
property of
the underlying Person
class. Defined
within the ObjectWebEditor
user control are child controls that provide custom
handling of certain properties. In the
example below, I have opted to exchange the normally rendered HTML associated
with the “HomePage
” property of the Person
class with a
hyperlink bearing the
name “My Home Page”.
Default.aspx invokes an instance of the
Person
class and the
SelectedObject
property of the ObjectWebEditor
user control is set to this instance. Upon Page Load,
ObjectWebEditor
interrogates the Person
object rendering the HTML necessary to display its
properties. The editor honors component
model attributes such as ReadOnly
as well as only generates HTML for its public
members.
The Category
attributes of class properties serve as section headers.
These happen to be rendered in the order in which that are encountered during object interrogation.
Entire categories can be
hidden similarly to properties by defining Category Names in the
HiddenCategories
property of the ObjectWebEditor
.
Notice below how a few HTML input fields are
grayed
out. This is because these properties
are marked read-only at the Activity class level. That does not mean one cannot
programmatically change them.
HTML markup was generated automatically and on-the-fly by
the Object Web Editor user control. Each
of the HTML input fields are named in such a way the Object Web Editor user
control can determine where to apply a submitted value when a Post Back
occurs. The table row containing the
Description
property HTML markup is shown below.
<tr
class="PropertyGridPropertyRow"
align="left">
<td
class="PropertyGridPropertyName"
valign="top"
align="left"
width="100%">Age</td>
<td
class="PropertyGridPropertyValue"
valign="top"
align="left"
width="100%">
<input
id="personEditor_2"
name="personEditor_2"
type="Text"
value="52" >
</td>
</tr>
Each HTML input field name combines the name of the Object
Web Editor control plus the count of the property being represented. This guarantees each HTML input field to be
unique no matter of the number of these controls that exist on a given page.
Upon post back the
ObjectWebEditor
accesses the Request Form fields collection
and matches up file names to its internal mapping of form field names to
Selected Object class properties. It
should be able to do this. After all, it
created these fields in the first place ;o)
Some classes may contain instances of other classes as
public properties. The ObjectWedEditor
handles this by invoking a new instance
of itself and attaching it to the property…effective becoming its editor. Even then, the ClientID of this new user
control instance is made unique by combining the ClientID of its parent
“editor” in this case with “X”
resulting in “editorX”. And if the hypothetical child class had another child class, the same would be done
again resulting in “editorXX” and so
on.
There are situations in which one may want to hide
on-the-fly generated HTML markup for one or more Properties. This is
accomplished though the HiddenProperies
property of the Object Web Editor user control.
HiddenProperties="Exceptions,ActivityStatus,ActivityType,Prerequisites"
The same is true for class categories.
HiddenCategories="System"
There are situations in which the actual name of a given
property is not suitable for user interface display. In the example below we are changing the
“LastName” displayed label to “Persons Last Name” using a nested PropertyMap
definition.
JavaScript can be placed within the URL Property of the
PropertyMap
definition in order to cause other dynamic run-time behavior to
occur.
The PropertyMap
control can also substitute tokenized values
with a named property value of the Selected Object. Here we see Person.SSN
being applied to a
URL…
Each of the Object Web Editor user control resulting HTML
table elements can be styled as follows:
.PropertyGrid
{
}
.PropertyNestedGrid
{
}
.PropertyGridCategory
{
white-space: nowrap;
}
.PropertyGridCategoryName
{
white-space: nowrap;
font-weight: bold;
}
.PropertyGridPropertyRow
{
white-space: nowrap;
}
.PropertyGridPropertyName
{
white-space: nowrap;
}
.PropertyGridPropertyValue
{
white-space: nowrap;
}
.PropertyGridPropertyLink
{
white-space: nowrap;
}
For me the ObjectWebEditor
user control significantly
shortens ASP.NET web page development by providing dynamically generated
presentation and data gathering HTML for a large percentage of the pages I work
with these days. Using this control, I
was able to churn out 20 web pages wrapping business objects in about one half
of an hour opposed to taking a day building them by hand. Additionally, these pages ended up looking
very uniform in the ASP markup as well as the code behind.
History
- 1/2/2012: Initial release.