|
With the release of Visual Studio .NET Beta 2 and "Gold"
coming in a matter of a month or so (expected Nov. 2001) the components
and controls marketplace has heated up considerably. I've seen .NET controls
of all types being released by most of the major vendors - everything
from "add-ins" for working with databases, to email and upload
controls, "Plug-in" Webservices and Data compression classes
for compressing/decompressing data over the wire. One of the more glamorous
categories of course in in the Web UI area, where a number of vendors
have released entries having to do with manipulation and display of data.
And the fact of the matter is, it's a lot easier to use
the .NET Platform to author custom controls because of the ability to
derive from and override Base classes. One example can be found on the
GotDotNet site from Eilon Lipton, a Microsoft intern who has posted the
complete source for his Treeview
Control. If you are adventurous and want to look into writing your
own custom ASP.NET controls, his submission is a good place to start (Good
way to practice being "Sharp" too).
Microsoft has also released ASP.NET Server Control versions
of the most popular IE controls, namely Treeview, TabStrip, ToolBar and
MultiPage. These are all fully .NET compliant server-side controls. They
are also, however, "Browser aware", and if the browser is "uplevel"
(IE 5.5 or higher) the associated Client-side HTC behavior for each control
is automatically downloaded with the page. Now obviously this makes for
some very interesting combinations of both client-side data manipulation
as well as autopostback server-side data handling.
You can download the control installation package free
at http://msdn.microsoft.com/library/default.asp?url=/workshop/webcontrols/overview/overview.asp
and install it on your server or development machine. This includes the
assemblies as well as all the client-side HTC behaviors.
CAUTION: Some of this Microsoft documentation is obviously
being "rushed out" a bit. If you plan on using the Treeview
XML Databinding methods, and wish to apply an XSL Transform to a preexisting
or dynamically-generated XML data source, be aware that the documentation
illustrates the XSL source attribute of the Treeview as "TreeNodeXslSrc".
This is WRONG! The correct attribute name is 'TreeNodeXsltSrc".
That's XSLT with a "T". I just about went nuts with this
trying to figure out why, even after I went backwards and just used Microsoft's
own sample, it didn't work. I knew my Transform worked cause I had tried
it out separately. So, hope this saves you some time because this is one
of the most powerful features (I'll illustrate it shortly, as well as
how to programmatically create a Treeview object.) I haven't yet completed
my studies, but I wouldn't be surprised if there are a few additional
"glitches". If you're having difficulty with a particular area,
three newsgroups I'd recommend where you can get help are on msnews.microsoft.com.
They are microsoft.public.dotnet.framework.aspnet
, microsoft.public.dotnet.languages.csharp, and microsoft.public.dotnet.xml.
Remember when you post to these groups, there are a large number of posts
and people of all levels of expertise. The best way to get a response
to your question is to think it through beforehand and make sure that
your post is both clear and detailed. Also, you want to search thoroughly
first to see if there's actually already an answer to your question. Otherwise,
you'll either get flamed - or just ignored. Also, don't post binaries
like BMP screenshots to a non-binary newsgroup. That's just rude! (I only
mention this because there are what appear to be otherwise intelligent
people actually doing this!).
Now lets get a quick overview of the Treeview control.
The Treeview in its simplest iteration is declaratively
inserted on the page with a custom namespace in a manner very similar
to how you would attach a custom IE behavior element:
<%@ Page Language="c#"
debug="true"%>
<%@ import namespace="Microsoft.Web.UI.WebControls" %>
<%@ register TagPrefix="myxmltree"
Namespace="Microsoft.Web.UI.WebControls"
Assembly="Microsoft.Web.UI.WebControls" %>
Once the assembly import and tagprefix
of your choice are registered (don't forget both the namespace and the
Assembly attributes in your @ register directive) then you are ready to
place instances of the Treeview declaratively on the page, like this:
<form id="myform"
runat="server">
<myxmltree:treeview id="tree1" runat="server" />
</form>
Note that the control must be inside
a Form tag in order for the server-side actions to take place. Of course,
the above has no nodes declared or content and so would do nothing. You
can add Nodes and NodeTypes declaratively when constructing the page,
or programmatically at runtime. You can also dynamically alter the content,
type and other features of nodes and childnodes The examples provided
in the documentation clearly illustrate how to declaratively create content
and attributes, so there's no reason for me to go over this ground. What
I think is particularly interesting, however, is the ability to do Databinding
with an XML source, and even to take an existing XML source in whatever
format it exists and apply an XSL Transform to it in order to transform
it into a new XML document that fits the spec so the Treeview control
will properly render it. That's what I'm going to illustrate next, and
the easiest way to do it is with a real - life, useful example.
On our Eggheadcafe.com site we
have new articles, code snippets and other resources coming in almost
on a daily basis. At the top of our main page we have a marquee control
that scrolls a newsfeed. What we do "behind the scenes" is fire
off a scheduled script that combines this newsfeed of developer-related
content with our own XML file "articles" dynamically to create
a new XML document that shows the latest newsfeed items PLUS our most
recent content from our site. I wanted to take this "articles.xml"
file and be able to use it in a Treeview so that if you clicked on a node,
you would be taken to that article.
Now the Treeview control will only
render content in a specific format. It expects XML that must look like
this:
<TREENODES>
<treenode Text="Hotlinks" >
<treenode Text = "this link" />
...etc. for child nodes within
each main treenode.
</treenode>
</TREENODES>
But the "articles.xml"
file doesn't conform, and I'm not about to rewrite it just for this purpose
(take a look: article.xml
). Fortunately, I don't have to. I can supply both a TreeNodeSrc
and a TreeNodeXsltSrc attribute in my TreeView tag, like this:
<myxmltree:treeview id="tree1"
runat="server" TreeNodeSrc="https://www.nullskull.com/article.xml"
TreeNodeXsltSrc="https://www.nullskull.com/hotlinktemplate.xsl"
ChildType="Folder" />
My XSL template looks
like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:template match="/">
<TREENODES>
<treenode Text="Hotlinks" >
<xsl:for-each select="moreovernews/article">
<xsl:element name="treenode">
<xsl:attribute name="DefaultStyle">background:#CCFF66;border:solid
1px;color:blue;font-size:9pt</xsl:attribute>
<xsl:attribute name="HoverStyle">background:#FF66CC;color:brown;font-name;Arial</xsl:attribute>
<xsl:attribute name="SelectedStyle">color:red;font-name=Tahoma;font-weight:bold-italic</xsl:attribute>
<xsl:attribute name="Text" ><xsl:value-of select="headline_text"/></xsl:attribute>
<xsl:attribute name="NavigateURL" ><xsl:value-of select="url"/></xsl:attribute>
<xsl:attribute name="Target" >_blank</xsl:attribute>
</xsl:element>
</xsl:for-each>
</treenode>
</TREENODES>
</xsl:template>
</xsl:stylesheet>
Note that I create
the required <TREENODES> root element inline, create the main "Hotlinks"
node, and then simply iterate my document, replacing instances of the
"article" element with the required "treenode" element,
and adding the attributes DefaultStyle, HoverStyle, SelectedStyle, Text,
NavigateURL and Target for each node. The result is that I'm Databinding
this control with exactly what it expects. The
result looks like this. But that's just the beginning - I can do much
more. If I want, I can actually have each node load a separate list of
links (as XML) pulled out of the database by having the target URL for
each say, "Hotlink Topic" point to an ASP or ASPX page that
queries SQL Server and sends the correct XML results back in the Response
Stream. For example, Hotlink Topic "Articles" might point to
a page "GetHotLinks.aspx?category=Articles".
This page would then
issue a SQL Server query such as "Select Hotlink_Title , Hotlink_URL,
HotLink_Text from Hotlinks where HotlLink_Category = '" +Request.QueryString("category")
+ "' FOR XML AUTO, ELEMENTS" and return the resultant XML
fragment to the calling page where another XSL stylesheet specified in
the TreeNodeXsltSrc attribute of the tag for that particular ChildNode
would handle the Transform. The databinding only occurs when a node is
expanded, so I'm keeping my database activity down until somebody actually
expands a node. In addition, the "GetHotlinks.aspx" page would
have an output cache directive like <%@ OutputCache Duration="100"
VaryByParam="*" %>. This means that anytime within 100
minutes if the page were called again with the same parameter ("category=Articles")
the page would automatically be served from the ASP.NET Output Cache.
So we can see there is a lot of interesting
flexibility we gain with these databinding features in the server-side
controls. Another thing to remember is these controls are all browser
- aware, so I don't have to worry if a Netscape or Opera visitor looks
at the page. The controls automatically handle HTML 3.2 rendering for
these "downlevel" browsers.
The other main area I want to cover here
is that of dynamically rendering the control - programmatically at runtime,
rather that declaratively when designing the page. This adds a whole new
area of flexibility because we now have the ability to use the entire
object model exposed by the base classes and all of their overridden methods
in dynamically generating and altering the Treeview object at will. A
quick look at Microsoft.Web.UI.Webcontrols.dll in ILDASM show just a small
portion of the methods available:
What we'll do next is create a Treeview programmatically
during page rendering:
<%@ Page
Language="c#" debug="true" %>
<%@ import namespace="Microsoft.Web.UI.WebControls" %>
<%@ import namespace="System.Xml" %>
<% @ import namespace="System.Data" %>
<% @ import namespace="System.Data.SqlClient" %>
<%@ register TagPrefix="mytree"
Namespace="Microsoft.Web.UI.WebControls"
Assembly="Microsoft.Web.UI.WebControls" %>
<script Language="C#" runat="server" debug="false">
private void Page_Load(object sender, System.EventArgs e)
{
doTree();
}
public void doTree(){
TreeNode x = new TreeNode();
// create our main node...
x = new TreeNode();
x.Text = "<B><font face="tahoma" Size=3>Hotlinks </font></B>";
Treeview1.Nodes.AddAt(0, x );
// create the childnodes...
TreeNode xx;
xx = new TreeNode();
xx.Text = "C# - Native SQL Provider Sample Speed Tests";
xx.NavigateUrl = "https://www.nullskull.com/articles/20010919.asp";
xx.ImageUrl = "https://www.nullskull.com/images/save.gif";
Treeview1.Nodes[0].Nodes.Add(xx );
xx = new TreeNode();
xx.Text = "ASP.NET Vs. Classic ASP Performance Tests";
xx.NavigateUrl = "https://www.nullskull.com/articles/20010920.asp";
xx.ImageUrl = "https://www.nullskull.com/images/save.gif";
Treeview1.Nodes[0].Nodes.Add(xx );
xx = new TreeNode();
xx.Text = "Build a C# MS Search WebService with COM Interop";
xx.NavigateUrl = "https://www.nullskull.com/articles/20010916.asp";
xx.ImageUrl = "https://www.nullskull.com/images/save.gif";
Treeview1.Nodes[0].Nodes.Add(xx );
}
</script>
<html>
<Body>
<form id="myform" runat="server">
<mytree:treeview id="Treeview1" runat="server"
>
</mytree:treeview>
</form>
</Body>
</html>
And if you'd like to
view the result, you can see where we've been going with this. Note
that I've only used just a few of the methods and properties here. Once
again, there is no reason why the NavigateURL attribute can't be set to
some dynamic page generation code that returns records from a database
, or we can set the TreeNodeSrc property to do the same. If you would
like to use the above as some sort of starting point for experimentation,
feel free to use the source files in the ZIP file download at the link
below.
Time permitting, and as my "experiments"
progress, I'll be posting follow up articles on the ToolBar, TabStrip
and MultiPage server controls as well.
Download
the code that accompanies this article
Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer
/Analyst at in Orlando and a co-developer of the NullSkull.com
developer website. He can be reached at info@eggheadcafe.com
|