﻿<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Core :: WebControls</title>
    <description>The category will contain information pertaining to the DotNetNuke WebControls.  Currently this includes the DNNTree, DNNMenu (Beta), and DNNTextSuggest (Beta), but eventually will include more controls.</description>
    <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/BlogId/56/Default.aspx</link>
    <language>en-US</language>
    <webMaster>admin1@dotnetnuke.com</webMaster>
    <pubDate>Fri, 18 Jul 2008 23:35:12 GMT</pubDate>
    <lastBuildDate>Fri, 18 Jul 2008 23:35:12 GMT</lastBuildDate>
    <docs>http://backend.userland.com/rss</docs>
    <generator>Blog RSS Generator Version 3.4.0.39853</generator>
    <item>
      <title>Introducing DNNMultiStateBox</title>
      <description>&lt;p&gt;One of the new features coming in Cambrian is an update in the permissions grid.&amp;#160; The current grid supports two states, Allow and Null (not assigned).&amp;#160; The new grid will support three states (Allow, Deny, and Null).&amp;#160; The obvious question here is how do you present this to the user?&amp;#160; The current design allows for a nice compact way to set the permissions within a grid utilizing checkboxes.&amp;#160; The new way will use a new DotNetNuke WebControl that supports multiple states and mimics a checkbox.&amp;#160; The original name I came up with for the control was DNNTriStateCheckbox.&amp;#160; However, while developing this control I soon realized there was no reason I needed to only support 3 states and saw the opportunity to support any number of states and not necessarily look like a checkbox.&amp;#160; So the control is now called DNNMultiStateBox.&amp;#160; It is probably the simplest of all the controls in the &lt;a href="http://webcontrols.dotnetnuke.com/&amp;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1835/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1835/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1835</guid>
      <pubDate>Mon, 12 May 2008 06:00:00 GMT</pubDate>
      <slash:comments>10</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1835</trackback:ping>
    </item>
    <item>
      <title>Searching for the "Holy Grail" of Menu Item Customization</title>
      <description>&lt;p&gt;For a long time now many skinners for DotNetNuke have felt like customizing individual menu items was like &lt;a href="http://www.dotnetnuke.com/Community/Forums/tabid/795/mid/2108/forumid/109/threadid/149710/scope/posts/Default.aspx#149710"&gt;looking for the Holy Grail&lt;/a&gt;.  All the menus I have contributed to the community (Solpart and DNNMenu) have always had the ability to customize each menu item.  The problem always was&lt;br /&gt;
how do we allow DotNetNuke the ability to customize the items?  The only place the unique menu structure is known is after the portal is created, well out of reach of someone providing a generic skin to fit any site.  Sure there are those portal admins out there that know enough about css to make it work, but there still was a problem in how to access each item directly in css.&lt;/p&gt;
&lt;p&gt;I have been &lt;a href="http://www.dotnetnuke.com/Products/Development/Roadmap/tabid/616/ctl/Details/mid/3582/enhancementid/2/Default.aspx"&gt;considering options&lt;/a&gt; for how to overcome this for some time now,  and am currently working on the 2.0 version of the webcontrols which should contain one possible solution.  However, those controls are far from complete so I decided to offer a minor hack along the same lines.&lt;/p&gt;
&lt;p&gt;First, let us consider &lt;a href="http://www.dotnetnuke.com/Community/Forums/tabid/795/mid/2108/forumid/109/threadid/149710/scope/posts/Default.aspx#149710"&gt;eclayf's idea from the forums&lt;/a&gt;, where I borrowed the name of this blog entry from.  The idea is to loop through all menu items and assign a background image to each item based off of the icon assigned.  This allows the background image to be customized by the portal admin.&lt;/p&gt;
&lt;p&gt;To try this idea out add the following code to your ascx page using the DNNMenu (not solpart).  I tested with default blue for DNN.&lt;/p&gt;
&lt;pre&gt;&lt;script type="text/javascript"&gt;
    function setupMenuImageCss(id)
    {
       var menu = dnn.controls.controls[id + '_ctldnnNAV'];
       assignImageCss(menu, menu.rootNode);
    }
    
    function assignImageCss(menu, parent)
    {
	    var menuNode = new dnn.controls.DNNMenuNode(parent);
	    var iconCtl = menu.getChildControl(menuNode.id, 'icn');
	    if (iconCtl)
	    {
	        iconCtl.style.display = 'none'; //hide icon
		    var menuCtr = menu.getChildControl(menuNode.id, 'ctr');
		    menuCtr.style.backgroundImage = "url('" + iconCtl.src + "')";
	    }
	    for (var i=0; i &lt; parent.childNodeCount(); i++)
	    {
		    assignImageCss(menu, parent.childNodes(i));
	    }
    }

    try 
    {
        document.execCommand("BackgroundImageCache", false, true);
    } 
    catch(err) {}
    
&lt;/script&gt;
&lt;script runat="server"&gt;
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
        DotNetNuke.UI.Utilities.DNNClientAPI.AddBodyOnloadEventHandler(Me.Page, "setupMenuImageCss('" &amp; dnnNAV.ClientID &amp; "')")
End Sub
&lt;/script&gt;&lt;/pre&gt;
&lt;p&gt;This should cause the icon images to be displayed as the background. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I noticed that if your skin declares the background-color (as the default blue does), the hover will no longer display the background.  If you change it to not set the background then the image remains.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;While this works, it is far from ideal.  For one thing the admin menu item icons are not customizeable.  Probably the biggest shortcoming is you can only customize the image, which happens to meet eclayf's requirements, but not generic enough to implement for DotNetNuke.&lt;/p&gt;
&lt;p&gt;The idea I have been toying with is allowing the next version of the menu to support known client-side IDs. My current thought is to allow the skin to decide whether to go this route by providing a "safe" known namespace.  For example, in your skin you would have a property like &lt;font face="Courier New"&gt;ClientIDPrefix="jcompany"&lt;/font&gt;, then on the client each node will be assigned a unique id, prefixed with that text.  So the root would be &lt;font face="Courier New"&gt;jcompany__0&lt;/font&gt;, &lt;font face="Courier New"&gt;jcompany__1&lt;/font&gt;, etc.  The child of &lt;br /&gt;
&lt;font face="Courier New"&gt;jcompany__2&lt;/font&gt; would be &lt;font face="Courier New"&gt;jcompany__2_1&lt;/font&gt;, &lt;font face="Courier New"&gt;jcompany__2_2&lt;/font&gt;, etc.   This way it would allow the skinner&lt;br /&gt;
to predefine as many levels as he/she sees fit, and as long as the user of the portal doesn't exceed the predefined number, the skin should work as originally intended.  Even if the skinner doesn't provide the level necesssary (something like &lt;font face="Courier New"&gt;jcompany__2_2_1_3_5&lt;/font&gt;), there is nothing stopping the user from adding the css himself, perhaps copying the value from a class defined higher up.  The only pitfal in this approach is the worry about overlapping prefixes with other controls on the page.&lt;/p&gt;
&lt;p&gt;In order to try this concept out add the following code to you ascx file that uses the DNNMenu&lt;/p&gt;
&lt;pre&gt;&lt;script type="text/javascript"&gt;
    function setupMenuIds(id, prefix)
    {
       var menu = dnn.controls.controls[id + '_ctldnnNAV'];
       assignMenuIds(menu, menu.rootNode, prefix, '');
    }

    function assignMenuIds(menu, parent, prefix, id)
    {
	    var menuNode = new dnn.controls.DNNMenuNode(parent);
	    var menuCtr = menu.getChildControl(menuNode.id, 'ctr');
	    var newId = prefix + '_' + id;
	    if (menuCtr)
		    menuCtr.id = newId;

        for (var i=0; i
&lt;script runat="server"&gt;
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
        DotNetNuke.UI.Utilities.DNNClientAPI.AddBodyOnloadEventHandler(Me.Page, "setupMenuIds('" &amp; dnnNAV.ClientID &amp; "', 'jcompany')")
End Sub
&lt;/script&gt;&lt;/pre&gt;
&lt;p&gt;Then in your css file add something like&lt;/p&gt;
&lt;pre&gt;#jcompany__0
{
	background: red;
}

#jcompany__1
{
	background: blue;
}

#jcompany__1_0 td
{
	background: green;
}

#jcompany__1_1 td
{
	background: orange;
}&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note:  It is worth noting that in general it is a bad idea to change the ids of a any control, as it most likely will break the control when it does a lookup by its id.  In the DNNMenu's case, those references to the lookup are cached internally, thus this reassignment of ids will work.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Right now this is just an idea I'm toying with. If people like the approach I probably will include it in version 2.0 of the DNNMenu.  Any feedback on this would be welcome.&lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1487/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1487/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1487</guid>
      <pubDate>Wed, 14 Nov 2007 17:43:03 GMT</pubDate>
      <slash:comments>15</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1487</trackback:ping>
    </item>
    <item>
      <title>BETA TEST PROGRAM: ClientAPI/WebControls - DawnTreader and Caspian</title>
      <description>&lt;p&gt;&lt;span class="Forum_Normal" id="spBody"&gt;
&lt;p&gt;The conversion of the ClientAPI and WebControls to utilize the MS AJAX Framework along with emitting xhtml compliant markup is near completion.  It is now time to start testing the backwards compatibility of the conversion.  In order to adequately do this, I am asking for the communities help.  If you are a skinner who uses any of the DotNetNuke webcontrols (DNNMenu, DNNTreeView, etc.) your assistance is needed.  If you are a module developer who uses any portion of the ClientAPI or any of the WebControls, you assistance is also needed. &lt;/p&gt;
&lt;p&gt;Interested in ensuring that your investment in DotNetNuke is backwards compatible?  Follow the instructions in &lt;a href="http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/76/threadid/176783/scope/posts/Default.aspx"&gt;this thread&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1597/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1597/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1597</guid>
      <pubDate>Thu, 18 Oct 2007 22:10:23 GMT</pubDate>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1597</trackback:ping>
    </item>
    <item>
      <title>Capturing the OnSubmit Event</title>
      <description>&lt;p&gt;Sometimes I grow frustrated when trying to solve apparently simple things, that end up taking most of the day to come up with an answer.  And if the answer is one that is bordering on a hack, I am even more distraught. This happened to me again while trying to optimize the latest version of the webcontrols, that will now use the Microsoft AJAX extensions framework. The optimization deals with allowing the control to persist its current structure. For example, when you have a tree that supports populate on demand, and you expand a node, causing a callback to occur, the new structure should be persisted. When a postback occurs, the tree should remember its structure (including what nodes are expanded). The code for this was already done. It was being called with each node expand, and each node selection. A more optimal way to handle this would be to simply call this persistence logic just before submitting the page. Simple, right?&lt;br /&gt;
&lt;br /&gt;
Uh, no actually. If you simply place an event handler on the form's onsubmit, you will only get notified when a submit button is pressed.  You will miss all other postbacks (like an autopostback from a dropdownlist). Knowing the MS AJAX framework has a nice object and event model I expected to find an event exposed. This search yielded no results, so I decided to have a look at what the &lt;a href="http://ajax.asp.net/ajaxtoolkit/"&gt;Control Toolkit&lt;/a&gt; does.  There are two controls that need this same notification: TextBoxWatermark and ConfirmButton. The solution offered there was not as good as I'd hoped. The way these controls handle getting the event notification is as follows&lt;br /&gt;
&lt;br /&gt;
1) Register the WebForm_OnSubmit event on the server with the following code&lt;/p&gt;
&lt;pre&gt;ScriptManager.RegisterOnSubmitStatement(&lt;font color="#0000ff"&gt;this&lt;/font&gt;,&lt;font color="#0000ff"&gt;typeof&lt;/font&gt;(&lt;font color="#2b91af"&gt;ConfirmButtonExtender&lt;/font&gt;),&lt;font color="#a31515"&gt;"ConfirmButtonExtenderOnSubmit"&lt;/font&gt;,&lt;font color="#a31515"&gt;"null;"&lt;/font&gt;);
ScriptManager.RegisterOnSubmitStatement(&lt;font color="#0000ff"&gt;this&lt;/font&gt;,&lt;font color="#0000ff"&gt;typeof&lt;/font&gt;(&lt;font color="#2b91af"&gt;TextBoxWatermarkExtender&lt;/font&gt;),&lt;font color="#a31515"&gt;"TextBoxWatermarkExtenderOnSubmit"&lt;/font&gt;,&lt;font color="#a31515"&gt;"null;"&lt;/font&gt;);&lt;/pre&gt;
&lt;p&gt;2a) When the control initializes on the client, the logic looks for the js function name that the ASP.NET runtime registers on the client. &lt;em&gt;Note that neither registration method invokes a specific function (null as the last parameter)&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;function WebForm_OnSubmit() {
//Note:  other page logic may register additional functions here as well!
null;
return true;
}&lt;/pre&gt;
&lt;p&gt;2b) A check to verify that a previous onsubmit handler was not already registered. Note, this is done with a shared/static property (not on the instance).&lt;/p&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt; ((&lt;font color="#0000ff"&gt;typeof&lt;/font&gt;(WebForm_OnSubmit) == &lt;font color="#a31515"&gt;'function'&lt;/font&gt;) &amp;&amp; !AjaxControlToolkit.TextBoxWatermarkBehavior._originalWebForm_OnSubmit) {&lt;/pre&gt;
&lt;p&gt;3) Assign the previous onsubmit handler for the watermark shared/static property to the current onsubmit handler&lt;/p&gt;
&lt;pre&gt;AjaxControlToolkit.TextBoxWatermarkBehavior._originalWebForm_OnSubmit = WebForm_OnSubmit;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
4) Assign a new function reference to the existing handler. &lt;/p&gt;
&lt;pre&gt;WebForm_OnSubmit = AjaxControlToolkit.TextBoxWatermarkBehavior.WebForm_OnSubmit;&lt;/pre&gt;
&lt;p&gt;5) The shared/static method that was reassigned to WebForm_OnSubmit will first invoke the original onsubmit method, if it returns successfully it will then loop through all components/extenders currently registered, and if it is of the same type as the current one, invoke that instance's onsubmit handler&lt;/p&gt;
&lt;pre&gt;AjaxControlToolkit.TextBoxWatermarkBehavior.WebForm_OnSubmit = function() {
  var result = AjaxControlToolkit.TextBoxWatermarkBehavior._originalWebForm_OnSubmit();
  if (result) {
    var components = Sys.Application.getComponents();
    for(var i = 0 ; i &lt; components.length ; i++) {
      var component = components[i];
      if (AjaxControlToolkit.TextBoxWatermarkBehavior.isInstanceOfType(component)) {
        component._onSubmit();
      }
    }
  }
  return result;
}&lt;/pre&gt;
&lt;p&gt;At first I did not think that this logic would work, as I felt that it would loose the onsubmit events of any other code that utilized the RegisterOnSubmitStatement. However, after further review, I now see that it should work fine, as it is kind of like a linked list approach.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Issues&lt;/strong&gt;&lt;br /&gt;
The first of three issues I have with this is similar to &lt;a href="http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryID/1305/Default.aspx"&gt;my issue&lt;/a&gt; with how the toolkit makes assumptions about what ASP.NET generated javascript names will be, in the earlier case it was the assumption on the function named WebForm_DoCallback, in this case it is WebForm_OnSubmit. While I do not anticipate MS changing the names of these functions, it certainly is not a dependency I would willingly keep unless necessary, as it could break going forward.&lt;br /&gt;
&lt;br /&gt;
The second issue is in how there is no global handler inside the toolkit for this logic. Rather it is up to each control to rewrite this somewhat clunky functionality.&lt;br /&gt;
&lt;br /&gt;
The last issue lies in an additional dependency the ConfirmButton places on the TextBoxWatermark. Apparently, if a watermark and confirm button exist on the same page, the watermark's handler needs to execute first. Obviously, this has a major issue for anyone else wishing to implement similar logic, as the confirm button will need to be reworked for each of these controls.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Different Approach&lt;/strong&gt;&lt;br /&gt;
Not willing to live with this set of shortcomings, I decided to look for other approaches. Unfortunately, I found none, so I decided to code my own. What I came up with is a new component called submitComponent, that lives in the dnn.controls client-side namespace. The following is how it works&lt;br /&gt;
&lt;br /&gt;
1) The server-side logic needs to register the componentbr&lt;/p&gt;
&lt;pre&gt;RegisterSubmitComponent(&lt;font color="#0000ff"&gt;Me&lt;/font&gt;.Page)&lt;/pre&gt;
&lt;p&gt;This in turn add the following to the WebForm_OnSubmit function generated to the client&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre&gt;function WebForm_OnSubmit() {
//Note:  other page logic may register additional functions here as well!
dnn.controls.submitComp.onsubmit();
return true;
}&lt;/pre&gt;
&lt;p&gt;2) The client-side dnn.controls script will instantiate the dnn.controls._submitComponent component, inheriting from Sys.Component.  Inheriting from Sys.Component gives our new class the event handler logic we are looking for (getHandler, addHandler, removeHandler).  &lt;br /&gt;
&lt;br /&gt;
3) The control's script will add a handler for onsubmit, by calling the submitComponent's add_handler method&lt;/p&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;._onsubmitDelegate = Function.createDelegate(&lt;font color="#0000ff"&gt;this&lt;/font&gt;, &lt;font color="#0000ff"&gt;this&lt;/font&gt;._onsubmit);&lt;br /&gt;dnn.controls.submitComp.add_handler(&lt;font color="#0000ff"&gt;this&lt;/font&gt;._onsubmitDelegate);&lt;/pre&gt;
&lt;p&gt;This approach does not have issue 1 listed above, as it does not hardcode the WebForm_OnSubmit method into the client-script, rather it uses the ASP.NET functionality as intended by registering the script to execute onsubmit.  The second issue is addressed as there is now a global component that can be used by each of my controls.  The last issue is not addressed by my component since I have no such requirements.  However, the component could easily add an additional parameter to the add_handler method to specify it must execute last.&lt;/p&gt;
&lt;p&gt;I can't help but think that this logic is already implemented somewhere and I have missed it.  If anyone out there knows how to better handle this scenario please post a comment./p&gt;&lt;/p&gt;
&lt;pre&gt; &lt;/pre&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1524/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1524/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1524</guid>
      <pubDate>Tue, 21 Aug 2007 01:43:53 GMT</pubDate>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1524</trackback:ping>
    </item>
    <item>
      <title>Navigation Provider Custom Attributes - A Sneak Peak At 4.5.0</title>
      <description>&lt;p&gt;DotNetNuke has supported navigation providers for about a year and a half.  Currently there are 4 providers we support.  The provider model is based off of interfaces, promoting a one-size-fits-all mentality.  This can be both a blessing and a curse.  The curse as it relates to the navigation providers is that it limits the features that the navigation provider's control can support.  For example, recently I added support for the DNNMenu to support horizontal submenus.  In order for this feature to be used in a skin (using the navigation provider), it needs a property exposed.  Adding this property, would expose it to all providers, which of course makes little sense for something like a treeview.  4.5 will no have the ability to specify custom attributes to the navigation providers.  This can be accomplished by adding the following to the skin's ascx file. &lt;/p&gt;
&lt;p&gt;The following directive needs to be added at the top&lt;/p&gt;
&lt;p&gt;&lt;%@ Register TagPrefix="dnn" Namespace="DotNetNuke.UI.Skins" Assembly="DotNetNuke" %&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;&lt;%@ Register TagPrefix="dnn" Namespace="DotNetNuke.UI.Skins" Assembly="DotNetNuke" %&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Then within your skin object you simply embed a CustomAttributes element, then specify one or more attributes.&lt;/p&gt;
&lt;p&gt;    &lt;dnn:NAV ID="dnnNav" runat="server" ProviderName="DNNMenuNavigationProvider"&gt;&lt;br /&gt;
    &lt;CustomAttributes&gt;&lt;br /&gt;
      &lt;dnn:CustomAttribute Name="SubMenuOrientation" Value="Horizontal"/&gt;&lt;br /&gt;
    &lt;/CustomAttributes&gt;&lt;br /&gt;
    &lt;/dnn:NAV&gt;&lt;br /&gt;
 &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If you interested in how the skin object was modified, keep reading.&lt;/p&gt;
&lt;p&gt;This is accomplished by adding a Generics collection to the NavObjectBase (which is used by the Nav.ascx skin object).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="Courier New"&gt;    &lt;DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)&gt; _&lt;br /&gt;
    Public ReadOnly Property CustomAttributes() As Generic.List(Of CustomAttribute)&lt;br /&gt;
      Get&lt;br /&gt;
        Return m_objCustomAttributes&lt;br /&gt;
      End Get&lt;br /&gt;
    End Property&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
The provider will then be able to enumerate these custom attributes and apply them to the underlying control.&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;      For Each objAttr As DotNetNuke.UI.Skins.CustomAttribute In Me.CustomAttributes&lt;br /&gt;
        Select Case objAttr.Name.ToLower&lt;br /&gt;
          Case "submenuorientation"&lt;br /&gt;
            Me.Menu.SubMenuOrientation = DirectCast(System.Enum.Parse(Me.Menu.SubMenuOrientation.GetType, objAttr.Value), DotNetNuke.UI.WebControls.Orientation)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;        End Select&lt;br /&gt;
      Next&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1326/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1326/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1326</guid>
      <pubDate>Fri, 02 Mar 2007 18:00:00 GMT</pubDate>
      <slash:comments>9</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1326</trackback:ping>
    </item>
    <item>
      <title>Edit In Place Enhancements - A Sneak Peak At 4.5.0</title>
      <description>&lt;p&gt;Thought I'd mention that the Edit In Place enhancements will be incorperated into 4.5.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://webcontrols.dotnetnuke.com/download/EditInPlace-TextHTML.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Instead of rewriting an entire entry, I think it is best to simply point you to the &lt;a href="http://www.dotnetnuke.com/Community/BlogsDotNetNuke/tabid/825/EntryID/1165/Default.aspx"&gt;original blog&lt;/a&gt;, which also links the document with all the design details.  &lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1327/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1327/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1327</guid>
      <pubDate>Fri, 02 Mar 2007 17:01:00 GMT</pubDate>
      <slash:comments>8</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1327</trackback:ping>
    </item>
    <item>
      <title>Researching MS AJAX:  ScriptControlBase and Callbacks</title>
      <description>&lt;p&gt;Yesturday &lt;a href="http://www.dotnetnuke.com/Community/BlogsDotNetNuke/tabid/825/EntryID/1303/Default.aspx"&gt;&lt;span style="COLOR: #669966"&gt;I blogged&lt;/span&gt;&lt;/a&gt; on the MS AJAX framework's PageMethod implementation falling short when it comes to control developers.  Before I completely gave up on this, I decided to investigate some of the toolkit's controls to see how they handle these callbacks.  Two controls came up in my search: Rating and ReorderList.  I spent some time investigating the Rating control, which seems to utilize the classic ASP.NET 2.0 callback mechanism.  The only issue I saw is that the control did not use the script returned to it by the GetCallbackEventReference method, rather it had hardcoded its call into its js file. While I don't anticipate that Microsoft will ever change this function declaration, I wouldn't want to bet on it.  The method I am referring to is WebForm_DoCallback.  I decided to search the entire toolkit for any other controls utilizing this approach.  I didn't find any other controls but I did find a script called BaseScripts which really peaked my interest. &lt;/p&gt;
&lt;pre style="FONT-SIZE: 7pt"&gt;_invoke : function(name, args, cb) {
    /// &lt;summary&gt;&lt;/summary&gt;invokes a callback method on the server controlif (!this._callbackTarget) {
&lt;/pre&gt;
&lt;p&gt;Seeing that this method is private, or at least meant to be since it is prefixed with an underscore, I tried to find where it is called from.  I had found nothing.  Perhaps it was only a partial implementation.  I decided not to give up, rather, I did another search to see how a control's _callbackTarget property could be set.  This search yielded this code in the ScriptObjectBuilder class &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre style="FONT-SIZE: 7pt"&gt;// determine if we should describe methods
foreach (MethodInfo method in instance.GetType().GetMethods(
  BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
{
    ExtenderControlMethodAttribute methAttr = 
      (ExtenderControlMethodAttribute)Attribute.GetCustomAttribute(
        method, typeof(ExtenderControlMethodAttribute));
    if (methAttr == null || !methAttr.IsScriptMethod)
    {
        continue;
    }

    // We only need to support emitting the callback target and registering  
    //the WebForms.js script if there is at least one valid method
    Control control = instance as Control;
    if (control != null)
    {
        // Force WebForms.js
        control.Page.ClientScript.GetCallbackEventReference(control, null, null, null);

        // Add the callback target
        descriptor.AddProperty("_callbackTarget", control.UniqueID);
    }
    break;
}
&lt;/pre&gt;
&lt;p&gt;This was very interesting to me, for it seems that if we denote an internal method as being a ScriptMethod and as long as the method is public, static, &lt;strong&gt;or&lt;/strong&gt; an instance method we are going to be "hooked up".&lt;br /&gt;
&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;  It seems odd that this is an &lt;/em&gt;&lt;strong&gt;&lt;em&gt;or&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;...  looks like a bug.  I would not assume you can have a private instance method and it still work.  &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I decided to make a simple control to try out this seemingly undocumented functionality. &lt;/p&gt;
&lt;p&gt;My control was very simple.  It inherits from the ScriptControlBase class, renders simple div tag with text, and has two methods marked as ExtenderControlMethod. &lt;/p&gt;
&lt;pre style="FONT-SIZE: 7pt"&gt;using System.Web.UI;
using System.ComponentModel;
using AjaxControlToolkit;

[assembly: WebResource("MyAjaxControls.SimpleCallback.SimpleCallback.js", 
    "application/x-javascript")]
namespace MyAjaxControls
{
    [ClientScriptResource("MyAjaxControls.SimpleCallback", 
      "MyAjaxControls.SimpleCallback.SimpleCallback.js")]
    public class SimpleCallback : ScriptControlBase
    {
        public SimpleCallback()
            : base(false) {}

        [DefaultValue("")]
        [Category("Appearance")]
        public string Text
        {
            get { return (string)(ViewState["Text"] ?? string.Empty); }
            set { ViewState["Text"] = value; }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.Write(this.Text); 
            writer.RenderEndTag();
	//required to hook up element on client
            ScriptManager.RegisterScriptDescriptors(this); 
        }

        [ExtenderControlMethod]
        public string HelloWorld(string s)
        {
            return "hello: " + s;
        }

        [ExtenderControlMethod]
        public int Add(int x, int y)
        {
            return x + y;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;The client side library was also simple.  It simply hooked up the click event of the element and invoked our callback &lt;/p&gt;
&lt;pre style="FONT-SIZE: 7pt"&gt;Type.registerNamespace("MyAjaxControls");

MyAjaxControls.SimpleCallback = function(element) {
    MyAjaxControls.SimpleCallback.initializeBase(this, [element]);    
    this._onclick$delegate = Function.createDelegate(this, this._onclick);
    this._cbcomplete$delegate = Function.createDelegate(this, this._cbcomplete);
}
MyAjaxControls.SimpleCallback.prototype = {
    
    initialize : function() {
        MyAjaxControls.SimpleCallback.callBaseMethod(this, "initialize");
        var element = this.get_element();
        $addHandler(element, "click", this._onclick$delegate);
    },

    dispose : function() {

        var element = this.get_element();
        if(element) {
            $removeHandler(element, 'click', this._onclick$delegate);
        }
        MyAjaxControls.SimpleCallback.callBaseMethod(this, "dispose");
        
    },
    
    _onclick : function(sender, e) {
        //this._invoke('HelloWorld', ['hi'], this._cbcomplete$delegate);
        this._invoke('Add', [20, 3], this._cbcomplete$delegate);
    },
    
    _cbcomplete: function(result, ctx)
    {
        alert(result);
    }
}

MyAjaxControls.SimpleCallback.registerClass("MyAjaxControls.SimpleCallback", AjaxControlToolkit.ControlBase);
&lt;/pre&gt;
&lt;p&gt;I must say that I am really pleased to find this implementation.  Even though under the covers it is using a classic ASP.NET 2.0 callback, all the plumbing work to allow our multiple parameters along with any number of functions to be invoked is all handled for us.  I am not sure why the _invoke is private, or if this is even functionality that should be used by control developers.  Searching the internet was not helpful at all.  The only reference I found on the subject is &lt;a href="http://community.bennettadelson.com/blogs/rbuckton/archive/2006/12/18/What-is-AjaxControlToolkit.ScriptControlBase_3F00_.aspx"&gt;&lt;span style="COLOR: #669966"&gt;this blog&lt;/span&gt;&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;ScriptControlBase implements some great new features that hopefully soon will make their way into ExtenderControlBase before the next real release.  These include:&lt;/em&gt; &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;em&gt;Load/Save ClientState methods similar to Load/Save ViewState on the server and client-side &lt;/em&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;&lt;em&gt;ASP.NET 2.0 Callbacks &lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;em&gt;ScriptUserControl to create custom AJAX controls using .ascx files.  Facilitates creating reusable mashup controls when building web applications &lt;/em&gt;&lt;/li&gt;
    &lt;li&gt;&lt;em&gt;ControlBase.prototype.findElement() client method to find child objects using .NET Naming Containers (ScriptControlBase is an INamingContainer)&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If anyone out there can shed some light on this functionality I would really appreciate it.&lt;/p&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: Consolas, "Courier New", Courier, Monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1305/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1305/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1305</guid>
      <pubDate>Wed, 14 Feb 2007 01:00:00 GMT</pubDate>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1305</trackback:ping>
    </item>
    <item>
      <title>Researching MS AJAX:  PageMethods</title>
      <description>&lt;p&gt;With my plate relatively clear, I have decided to spend some time investigating the released version of &lt;a href="http://ajax.asp.net/Default.aspx"&gt;Microsoft AJAX Extensions for ASP.NET 2.0&lt;/a&gt; (formarly Atlas and from now on I will call it MS AJAX).  Specifically, I want to see what advantages and disadvantages I would have by utilizing this framework instead of (or addition to) the ClientAPI.  One of the first things that I looked for was the ability to make "callbacks".  I had heard about Atlas' ability to invoke webservices for some time now and have been on a project that was IE specific and therefore was able to use the &lt;a href="http://msdn.microsoft.com/workshop/author/webservice/overview.asp"&gt;WebService behavior&lt;/a&gt; to accomplish the same thing.  While this functionality is cool, people who know me, know that my real passion is for writing reusable webcontrols.  Writing a webcontrol that needs to communicate with the server&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Should not require the end user to expose a webservice.  &lt;/li&gt;
    &lt;li&gt;Communication to the server should allow the control be able to raise events in the context of the current page.  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my opinion, these two requirements are vital to writing webcontrols.  &lt;/p&gt;
&lt;p&gt;My initial look through the &lt;a href="http://ajax.asp.net/docs/"&gt;documentation&lt;/a&gt; I found little that would assist me in the answer (eventually I found &lt;a href="http://ajax.asp.net/docs/tutorials/ExposingWebServicesToAJAXTutorial.aspx"&gt;this&lt;/a&gt; last sample).  Searching google yielded some promising results.  Apparently, there is this concept called PageMethods that appeared to be able to make a callback from the client to the server without the need for a separate webservice.  After digging through several sites explaining their use and lack of documentation I soon learned that through the various releases of this feature, quite a few changes were made.  Two of these changes are the need to also decorate your method with a ScriptMethod
&lt;scriptmethod&gt;&lt;/scriptmethod&gt;
attribute (though when I try it, this does not seem necessary any more), and the fact that in the later betas these methods are now &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/10/20/ASP.NET-AJAX-Beta-1-Released.aspx"&gt;required to be static&lt;/a&gt;!&lt;br /&gt;
 &lt;/p&gt;
&lt;p&gt;It appears that PageMethods will satisfy my first requirement (not needing external webservices), however, the second is not met.  For we need the context of the current page to be useful.  To understand what I mean, lets take the DNNLabelEdit control.  A developer can place this on any page or module (for DNN), handle an event (UpdateLabel) and successfully have access to all it needs to update the database (ModuleId for example).  If we don't have the context of the page, we will need the information posted to the server through the callback.  The control cannot make assumptions on what should and shouldn't be posted, so this leaves it up to the developer.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
One of the reasons for the change in requiring static/shared methods is &lt;a href="http://blogs.msdn.com/sburke/archive/2006/10/21/hint-components-that-use-web-services-with-asp-net-ajax-v1-0-beta.aspx"&gt;stated here&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;"They reason the AJAX team decided to make these methods static was so you could avoid page-lifecycle issues and subtleties, such as the inability to modify or access page state"&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ASP.NET 2.0 out of the box supports callbacks.  These same issues are present, yet they still support the feature!  I know, for I have researched and documented them when dealing with the DNNTabStrip control.  I suppose I am not as upset as I could be, especialy if I had tried to adopt Atlas earlier and had developed solutions requiring this functionality like others have commented in the blogs listed above. It is looking like I will be continuing the use of the ClientAPI's callback functionality.  &lt;em&gt;Note:  I could choose to use the ASP.NET 2.0 callback functionality, but I don't think it worth moving, since my callback implementation has a few more enhancments included.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some people have questioned why even bother with PageMethods if they have to be static.  They argue they are just like webservices.  The fact that they appear to satisfy my first requirement makes them different.  &lt;/p&gt;
&lt;p&gt;Two final notes before moving on.  &lt;/p&gt;
&lt;p&gt;First, I am readily admitting that I just started researching MS AJAX, and therefore may not have all my facts straight.  If someone knows another way that MS AJAX solves my requirements above, please comment or send me an email.&lt;/p&gt;
&lt;p&gt;Finally, I see many people who decide to use PageMethods do so by setting the ScriptManager's EnablePageMethods property to true.  I would highly recommend against this.  While it makes your invoking of the method simple, it generates a large amount of payload sent down to the client.  To see what I mean, I am listing the output generated within the page for only two simple methods (Add and Add2)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;font face="Courier New" size="1"&gt;var PageMethods = function() {&lt;br /&gt;
PageMethods.initializeBase(this);&lt;br /&gt;
this._timeout = 0;&lt;br /&gt;
this._userContext = null;&lt;br /&gt;
this._succeeded = null;&lt;br /&gt;
this._failed = null;&lt;br /&gt;
}&lt;br /&gt;
PageMethods.prototype = {&lt;br /&gt;
Add:function(x,y,succeededCallback, failedCallback, userContext) {&lt;br /&gt;
return this._invoke(PageMethods.get_path(), 'Add',false,{x:x,y:y},succeededCallback,failedCallback,userContext); },&lt;br /&gt;
Add2:function(x,y,succeededCallback, failedCallback, userContext) {&lt;br /&gt;
return this._invoke(PageMethods.get_path(), 'Add2',false,{x:x,y:y},succeededCallback,failedCallback,userContext); }}&lt;br /&gt;
PageMethods.registerClass('PageMethods',Sys.Net.WebServiceProxy);&lt;br /&gt;
PageMethods._staticInstance = new PageMethods();&lt;br /&gt;
PageMethods.set_path = function(value) { &lt;br /&gt;
var e = Function._validateParams(arguments, [{name: 'path', type: String}]); if (e) throw e; PageMethods._staticInstance._path = value; }&lt;br /&gt;
PageMethods.get_path = function() { return PageMethods._staticInstance._path; }&lt;br /&gt;
PageMethods.set_timeout = function(value) { var e = Function._validateParams(arguments, [{name: 'timeout', type: Number}]); if (e) throw e; &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New" size="1"&gt;if (value &lt; 0) { throw Error.argumentOutOfRange('value', value, Sys.Res.invalidTimeout); }&lt;br /&gt;
PageMethods._staticInstance._timeout = value; }&lt;br /&gt;
PageMethods.get_timeout = function() { &lt;br /&gt;
return PageMethods._staticInstance._timeout; }&lt;br /&gt;
PageMethods.set_defaultUserContext = function(value) { &lt;br /&gt;
PageMethods._staticInstance._userContext = value; }&lt;br /&gt;
PageMethods.get_defaultUserContext = function() { &lt;br /&gt;
return PageMethods._staticInstance._userContext; }&lt;br /&gt;
PageMethods.set_defaultSucceededCallback = function(value) { &lt;br /&gt;
var e = Function._validateParams(arguments, [{name: 'defaultSucceededCallback', type: Function}]); if (e) throw e; &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New" size="1"&gt;PageMethods._staticInstance._succeeded = value; }&lt;br /&gt;
PageMethods.get_defaultSucceededCallback = function() { &lt;br /&gt;
return PageMethods._staticInstance._succeeded; }&lt;br /&gt;
PageMethods.set_defaultFailedCallback = function(value) { &lt;br /&gt;
var e = Function._validateParams(arguments, [{name: 'defaultFailedCallback', type: Function}]); if (e) throw e; &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New" size="1"&gt;PageMethods._staticInstance._failed = value; }&lt;br /&gt;
PageMethods.get_defaultFailedCallback = function() { &lt;br /&gt;
return PageMethods._staticInstance._failed; }&lt;br /&gt;
PageMethods.set_path("/MSAjax10/PageMethods.aspx");&lt;br /&gt;
PageMethods.Add= function(x,y,onSuccess,onFailed,userContext) {PageMethods._staticInstance.Add(x,y,onSuccess,onFailed,userContext); }&lt;br /&gt;
PageMethods.Add2= function(x,y,onSuccess,onFailed,userContext) {PageMethods._staticInstance.Add2(x,y,onSuccess,onFailed,userContext); }&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
While it is nice to be able to invoke these methods like&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;PageMethods.Add(1,2, methodComplete, methodError);&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;The amount of overhead for each page request is not worth it IMO.&lt;/p&gt;
&lt;p&gt;Instead I recommend calling the method like this&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;Sys.Net.WebServiceProxy.invoke('/MSAjax10/PageMethods.aspx', 'Add', false, { x:1, y:2 }, methodComplete, methodError);&lt;/font&gt;&lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1303/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1303/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1303</guid>
      <pubDate>Tue, 13 Feb 2007 01:00:00 GMT</pubDate>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1303</trackback:ping>
    </item>
    <item>
      <title>DotNetNuke WebControls v1.5 Released</title>
      <description>I am pleased to announce the release of the latest DotNetNuke WebControls v1.5.  I must admit, this release took a lot longer than I had anticipated.  I have spent the last couple weeks putting everything else on hold in order to finish up the DNNTabStrip control.  Most of the work done will be visible to the public, however, there is quite a bit of work that I spent in prototyping that may never see the light of day.  &lt;br /&gt;
&lt;br /&gt;
The bulk of the work was done in the DNNTabStrip control.  This required some additional changes to the ClientAPI.  See the note below on the installation of the controls if you plan on using the advanced features in the DNNTabStrip.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;strong&gt;ClientAPI Enhancements / Bug Fixes&lt;/strong&gt;&lt;/u&gt;&lt;br /&gt;
&lt;strong&gt;ClientAPI&lt;/strong&gt; - Dynamic Script Loading - Removed reliance on setScriptLoaded.  Support for Safari through XMLHTTP request.&lt;br /&gt;
&lt;strong&gt;ClientAPI&lt;/strong&gt; - Dynamic Batch Script Loading&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;u&gt;WebControl Enhancements / Bug Fixes&lt;/u&gt;&lt;br /&gt;
DNNTabStrip&lt;/strong&gt; - Support for CallBackType=ProcessPage (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5015"&gt;WCT-5015&lt;/a&gt;)&lt;br /&gt;
&lt;strong&gt;DNNTabStrip&lt;/strong&gt; - Support for script registration from containing tab's controls (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5016"&gt;WCT-5016&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;DNNMenu&lt;/strong&gt; - Support for Horizontal SubMenus (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5017"&gt;WCT-5017&lt;/a&gt;)&lt;br /&gt;
&lt;strong&gt;DNNMenu&lt;/strong&gt; - Default MouseOutDelay to 500 ms. Only render to client when different (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5018"&gt;WCT-5018&lt;/a&gt;)&lt;br /&gt;
&lt;strong&gt;DNNMenu&lt;/strong&gt; - Fixed bug with IE, where if you clicked menuitem with target=_blank, then went back to the menu, the click events wouldn't fire (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5019"&gt;WCT-5019&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;DNNLabelEdit&lt;/strong&gt; - Added option to Render as a div tag instead of span.  This is for scenarios where you wish to have block elements (P, INPUT, etc.) inside your editing control, which is an inline element (span).  Striving to support XHTML compliance. (&lt;a href="http://support.dotnetnuke.com/issue/ViewIssue.aspx?id=5020"&gt;WCT-5020&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;New and Updated Samples&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/samples/MenuHorizontalSub.aspx"&gt;New sample&lt;/a&gt;&lt;/strong&gt; - showing DNNMenu with Horizontal SubMenus&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/samples/tabstripalignment.aspx"&gt;New sample&lt;/a&gt;&lt;/strong&gt; - demonstrating TabStrip Alignment &lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/samples/tabstripchildcontrols.aspx"&gt;New sample&lt;/a&gt;&lt;/strong&gt; - demonstrating TabStrip's capabilities to contain complex controls and still utilize callbacks. &lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/ClientAPI/DynamicLoadScript.aspx"&gt;Updated sample&lt;/a&gt;&lt;/strong&gt; - Dynamic Script Loading to include dynamic batch loading&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/DNNMenu.aspx"&gt;Updated sample&lt;/a&gt;&lt;/strong&gt; - DNNMenu to include option for Horizontal SubMenus &lt;br /&gt;
&lt;strong&gt;&lt;a href="http://WebControls.DotNetNuke.com/DNNLabelEdit.aspx"&gt;Updated sample&lt;/a&gt;&lt;/strong&gt; - DNNLabelEdit to include option to render as div &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Version Support&lt;/strong&gt;&lt;br /&gt;
I have added an additional install file (DotNetNuke_WebControls1.5.0_Install_11.zip) that will allow version 1.5 of the WebControls to work with ASP.NET 1.x (DNN 3.x).  The additional files included in this zip are ClientAPI files.  These include the DotNetNuke.WebUtility.dll, and all js files that are not controls.  Depending on the DNN version of 4.x you are updating, you may need some the files as well.  For example, if you plan on using the new tabstrip or edit in place functionality, the js files from this update will be required prior to 4.5 (dnn.js, dnn.scripts.js).&lt;br /&gt;
&lt;br /&gt;
I also wanted to say that this this is perhaps the last version that I will be supporting v1.x of the .NET Framework.  There are several reasons for this that I may go into more detail in future blogs.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;DNNMenu - Horizontal SubMenus&lt;/strong&gt;&lt;br /&gt;
One of the enhancements listed above is horizontal submenu support.  This has been a highly requested item for a long time.  While this release will allow the DNNMenu to contain horizontal submenus, it does not address how you as a skinner can set this property.  Look for a blog in the near future explaining an enhancement to the core skin objects to enable this.&lt;br /&gt;
&lt;strong&gt;&lt;br /&gt;
View Live Sample Site and Download&lt;br /&gt;
&lt;/strong&gt;You can view all the samples online along with downloading all the source and installation files from &lt;a href="http://webcontrols.dotnetnuke.com"&gt;http://webcontrols.dotnetnuke.com&lt;/a&gt; &lt;strong&gt;&lt;br /&gt;
&lt;br /&gt;
Questions&lt;/strong&gt; &lt;br /&gt;
Currently there is no WebControls forum.  Therefore if you have any questions it is best to post them in the ClientAPI forums.&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1296/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1296/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1296</guid>
      <pubDate>Fri, 09 Feb 2007 01:00:00 GMT</pubDate>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1296</trackback:ping>
    </item>
    <item>
      <title>TabStrip Rendering Document Complete</title>
      <description>&lt;p&gt;The DNNTabStrip control has been under development for quite some time.  The original document was written in August of 2006.  I am happy to announce that I was able to finish the final chapter for it just a couple hours before the Super Bowl (Go Bears!).  Chapter 6 deals with the two callback methods available, detailing under what situations you would choose one over the other.  Here is the introduction.&lt;/p&gt;
&lt;p&gt;&lt;hr /&gt;
&lt;/p&gt;
&lt;p&gt;The ClientAPI currently supports two different types of Callbacks:  Simple and ProcessPage.  The difference between these lies in how much of the default ASP.NET page’s lifecycle is run before it is short-circuited.  The following diagrams illustrate the differences.&lt;/p&gt;
&lt;p&gt;&lt;img height="301" width="400" alt="" src="/Portals/25/Projects/Core/WebControls/CallBackPageLifeCycle-Simple-sm.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;For a CallbackType of Simple the grayed out boxes are skipped.&lt;/p&gt;
&lt;p&gt;&lt;img height="301" width="400" alt="" src="/Portals/25/Projects/Core/WebControls/CallBackPageLifeCycle-ProcessPage-sm.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;For a CallbackType of ProcessPage, all the same events that happen in a normal PostBack occur.  The difference is in how much information is processed.  For example, only the tab’s HTML is rendered.&lt;/p&gt;
&lt;p&gt;&lt;hr /&gt;
&lt;/p&gt;
&lt;p&gt;You can read the document in its entirety &lt;a href="http://www.dotnetnuke.com/LinkClick.aspx?fileticket=TnzfKgH4rts%3d&amp;tabid=874&amp;mid=2653"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please note that the code discussed in this document along with the samples have not been published or released yet.&lt;/p&gt;</description>
      <link>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1291/Default.aspx</link>
      <comments>http://www.dotnetnuke.com/Products/Development/Forge/ComponentWebControls/tabid/873/EntryID/1291/Default.aspx#Comments</comments>
      <guid isPermaLink="true">http://www.dotnetnuke.com/Default.aspx?tabid=873&amp;EntryID=1291</guid>
      <pubDate>Sun, 04 Feb 2007 20:00:00 GMT</pubDate>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.dotnetnuke.com/DesktopModules/Blog/Trackback.aspx?id=1291</trackback:ping>
    </item>
  </channel>
</rss>