| |
| |
|
LATEST POSTS
Thursday, October 25, 2007
And here we have, three common ASP.NET AJAX mistakes.
I haven't been out Ajaxin' that much lately but reading through that list surfaced some painful, painful memories. And I've dealt with Rogers Wireless Customer Service so I know a thing or two about pain.
The underlying thought that went through my head for each and every one of these mistakes is: Why is the technology so complicated as to allow these mistakes in the first place?
Look at the recommended practices to avoid the mistakes: Litter your code with checks for IsPostBack or IsInAsyncPostBack. Make sure you call events in the right order. And for heaven's sake, put that code in PreRender, not Load. Dummy. And my favorite from the intro: "this...means that using the UpdatePanel requires careful attention to the ASP.NET Page Life Cycle."
Now I don't want to be a hippo-critter-cal hillbilly. I did, at one point, live and breathe the page life cycle and saw no never mind to it at the time. But it's interesting how the introduction of alternatives can change one's perspective. Nowadays, I look back at when I dealt with OnInit, OnLoad, OnPreRender, OnRender and wonder if I sounded like some crazed Santa Claus when I talked to other people about it.
Kyle the Commonly Mistaken
Wednesday, September 19, 2007
Today's post brought to you by honorary Hillbilly, Kevin Hemeon, who sent the following e-mail: Dear Coding, I realize you're a big mucky-muck who is too busy for the likes of the little people but my job, my life, indeed my very *soul* depends on being able to collapse an ASP.NET AJAX Toolkit CollapsiblePanel programmatically in a postback event, such as a button click. I've tried using myCollapsiblePanel.Collapsed = true but it doesn't work. And I, being a blogger mindful of his readership, replied: Kind and noble Kevin, The solution to this problem is mere child's play and it certainly did *not* take me a good couple of hours wondering "WTF" while I stared in disbelief at what should be an obvious piece of code. You see, the CollapsiblePanel is "postback-aware" in that it will save its state during a postback and re-create it. This is very handy when you are submitting a form and you don't want to startle people who are easily offended by things such as UI elements that look different when a web page refreshes. That's the sort of behaviour that tends to lead to warnings on coffee cups, if you catch my meaning. Unfortunately, this doesn't bode well if, in the postback, you want to alter its appearance manually. In this case, another line of code is necessary: myCollapsiblePanel.ClientState = "true"; myCollapsiblePanel.Collapsed = true; So you see, a simple solution for a simple problem (i.e. not a problem that appears simple but keeps you up all &*%$ night). Until next time, code strong and AJAX well. Kyle the (De)Mentor
Sunday, September 02, 2007
The ASP.NET Ajax Control Toolkit has a hate-on for namespaces, let me tell you. Their sample works slicker'n a greased hog when you use nice project names like "DisableButton" or "AlertBox". But use a name like "Suvius.DynamicFamilyTreeSorter" and you're in for a world of hurt. Side note: Call me old-fashioned, but I like having the namespace in my project name. Saves me having to muck with assembly names in the project properties and makes things obvious when I'm staring at a twenty-project solution with four projects named DataAccessLayer. Plus it fosters creativity in naming if the project contains classes from different namespaces. So what's a hillbilly to do if they like seeing they're comp'ny name embedded in the control project name? Let's assume you have just created an AJAX Control project with the name "Suvius.DynamicFamilyTreeSorter". Your project will contain three files: - Suvius.DynamicFamilyTreeSorterBehavior.js
- Suvius.DynamicFamilyTreeSorterDesigner.cs
- Suvius.DynamicFamilyTreeSorterExtender.cs
The first task is to rename each of these files, removing "Suvius." from the beginning of each. After that, here are the steps for the contents of each file: DynamicFamilyTreeSorterBehavior.js - First non-commented line of code: Change the namespace to Suvius
- Last non-commented line of code: Change the first argument in the call to registerClass to Suvius.DynamicFamilyTreeSorter (i.e. removing the trailing ".Suvius")
DynamicFamilyTreeSorterDesigner.cs - Remove "Suvius." from the name of the class
- Remove "Suvius." from the generic part of the ExtenderControlBaseDesigner<> declaration. This isn't totally necessary but helps keeps things clear
DynamicFamilyTreeSorterExtender.cs
For the longest time, I was getting a run-time error: Assemby 'yadda yadda' contains a Web resource with name 'Suvius.DynamicFamilyTreeSorter.DynamicFamilyTreeSorterBehavior', but does not contain an embedded resource with name 'Suvius.DynamicFamilyTreeSorter.DynamicFamilyTreeSorterBehaviour.js'. This after I had performed all the steps above. Except renaming the files in the first place.
So it would appear that WebResource locates files based on their location (replacing slashes with dots). Lesson learned. Or at least documented. *EDIT* One more step: In DynamicFamilyTreeSorterBehavior.js, replace all instances of Suvius.DynamicFamilyTreeSorterBehavior.Suvius with Suvius.DynamicFamilyTreeSorterBehavior.
Kyle the Assembled
Tuesday, June 05, 2007
So I'm back in ASP.NET AJAX/Atlas world for the time being while I work on my dad's application. And like a kid in a candy store, I'm trolling through the AJAX Control Toolkit trying to see which ones I can use. As opposed to picking out the cool ones and trying to find a way to wedge them into the application. It's a subtle difference. Anyway, the TabContainer caught my eye and I played with it both online and locally with the source code. One thing I think is a nice touch is the effect you get when you hover over the tabs, something you are accustomed to in WinForms but not as often on the web. I'm sure I've said it before but the guys on that time are counting with all ten fingers. In the HTML for that page though is some javascript that caught my eye and it led me on a wondrous journey: function ActiveTabChanged(sender, e) {
var CurrentTab = $get('<%=CurrentTab.ClientID%>');
CurrentTab.innerHTML = sender.get_activeTab().get_headerText();
Highlight(CurrentTab);
}
var HighlightAnimations = {};
function Highlight(el) {
if (HighlightAnimations[el.uniqueID] == null) {
HighlightAnimations[el.uniqueID] = AjaxControlToolkit.Animation.createAnimation({
AnimationName : "color",
duration : 0.5,
property : "style",
propertyKey : "backgroundColor",
startValue : "#FFFF90",
endValue : "#FFFFFF"
}, el);
}
HighlightAnimations[el.uniqueID].stop();
HighlightAnimations[el.uniqueID].play();
}
At first I thought this was their funky way of animating things when you switch tabs. But if you check the sample, there isn't really any animation on the page when you go from one tab to the next. Unless you look VERY closely at the text beside where it says "Current Tab". If you do, you'll see a short little fade effect that I tried to duplicate on my project with much frustration.
For those readers who actually have the Ajax Control Toolkit source code and are so inclined, here's an exercise for you: In the sample page for the Tabs control, remove the two CollapsiblePanelExtender controls at the bottom of the page and refresh your browser. If you have a default installation of Firefox with no extensions, you'll notice the fade animation is no more. If you use IE or have a Firefox extension that reports javascript errors, you'll notice a little more than that. Namely, that AjaxControlToolkit.Animation doesn't exist.
The reason is that the ScriptManager will output only those scripts it deems necessary for the controls on the page. And the Animations.js script (located in the Animation folder of the toolkit source code), which is the one that declares the AjaxControlToolkit.Animation "namespace", is not deemed necessary by the TabContainer control. But it *is* necessary for the CollapsiblePanelExtender, which you can see by opening CollapsiblePanelExtender.cs and having a boo at the [RequiredScript] attribute.
So what if you want to do this funky animation without adding an Extender that requires it? There are at least two ways I can think of:
- Include the Animations.js file in your project and reference it like any other script. I've taken this approach in my dasBlog theme because it is, in fact, the only way to include toolkit objects in the template files since they don't allow server-side controls.
- Add an empty AnimationExtender to your aspx page, either in the code-behind/beside or in the .aspx file:
<ajaxToolkit:AnimationExtender id="MyExtender"
runat="server" TargetControlID="Tabs">
</ajaxToolkit:AnimationExtender>
Both are mildly icky. The first seems a little too manual to me. What if I later add an extender that requires the Animations.js file? And worse, what if I upgrade to a later version of the toolkit that has a different version of Animations.js?
The second is safer but the TargetControlID is required, so you have to have at least one server-side control on the page to attach the extender to.
As it turns out, that little tidbit of javascript that inspired this post isn't actually necessary for the TabContainer control. It was added, I suspect, by some mean-spirited AJAXer who was acutely aware of my inquisitive nature and tendency to be easily interrupted.
Kyle the Animated
Tuesday, June 05, 2007
Am in the process of upgrading to the latest dasBlog build in an attempt to combat some of the referral spam I've been getting (which is a little odd since I don't show my referrals anywhere). Would like to be able to turn the pingback and trackback services back on here too. I have a feeling Akismet isn't going to solve all of these problems but I've got some time on my hands. Which is a good thing because I've been putting this off on the grounds that it will take time to get up and running again with a new version of dasBlog. The reason being my hillbilly theme (which is looking more and more like it needs upgrading every day) uses Atlas. Not ASP.NET AJAX Extensions. As in, I got Atlas working with dasBlog many moons ago and never looked back. So there be some work to do not only making sure I upgrade my AJAX installation but also with the client-side scripting I'm using to render the AjaxControlToolkit doohickets I'm using. But that's for another post. Today's tidbit involves ASP.NET AJAX and the blowery.web control which dasBlog uses. It seems they don't play nicely together out of the box (or at least not the way dasBlog configures blowery.web by default). After getting the latest dasBlog source, upgrading it to ASP.NET 2.0, and adding my ScriptManager, I get getting a javascript error: Line: 1 Error: Invalid character. To get the solution out of the way for those looking to get on with their project: Modify the <scriptresourcehandler> node in your <system.web.extensions> section of the web.config: <system.web.extensions>
<scripting>
<scriptResourceHandler enableCompression="false" enableCaching="true" />
<webServices>
</webServices>
</scripting>
</system.web.extensions>
This is merely speculation but I suspect that both AJAX and blowery.web are trying to compress the ScriptResource.axd that is output by the ScriptManager. I'm guessing you could also configure blowery.web to exclude ScriptResource.axd instead if you were inclined to let ASP.NET AJAX do its own compression.
I was going to relate my entire odyssey in discovering the error but now that the solution is in print, it seems kind of moot now. I will point out that I had to switch to Internet Explorer to figure this out though. It may be my configuration but Firefox didn't through any javascript errors at all.
Kyle the Compressed
Friday, May 11, 2007
I've decided to make use of the ASP.NET Ajax Toolkit for an app I'm working on after dropping out of the Atlas space for a few months. Sweet Jayzus, those guys have been busy. There are at least a dozen new controls since I last looked. I like the idea of the extenders. That is, you extend the capabilities of existing ASP.NET controls simply by dropping them on the page and configuring them. I purposely used the word "simply" there. Because I found the practice a little different than the promise. Let's take a look at the HTML I'm extending: <div style="margin: 0.5em; float: right; width: 150px; background-color: steelblue; color: lightsteelblue; font-weight: bold;" class="quickLinks">
<div style="padding: 0.25em; background-color: white; height: 18px; color: steelblue; border: 1px solid steelblue;">
<div style="float: left;">
Quick Links
</div>
<div style="float: right; vertical-align: middle;">
<asp:Image ID="Image2" runat="server" ImageUrl="~/images/collapse.jpg" />
</div>
</div>
<div style="padding: 0.5em; border-bottom: 2px solid white;">
<a href="#">Add Job</a><br />
<a href="#">Find a Job</a><br />
</div>
<div style="padding: 0.5em;">
<a href="#">Edit...</a><br />
</div>
</div>
I've purposely kept things out of CSS as much as possible to keep things in the same file for the purpose of this demonstration. The exception is my use of a quickLinks class in the first DIV. I did that so that I could make the links white: .quickLinks A
{
font-weight: normal;
color: white;
}
The above HTML produces the output you see to the right (aligned to the right sid e of the browser thanks to the "float").
Now, the toolkit effects I chose for this bad boy are: Drop Shadow (which comes with its own built-in rounded corners), the Collapsible Panel, and the Drag Panel. So I set out extending my code with these nifty little controls.
The keen observer will have noticed that the extenders apply to ASP.NET controls which was my first problem. That means using Panels rather than divs. Not such a big deal that. Usually one can just replace the <div> tag with <asp:Panel id="moo" runat="server"> and change the class tag to CssClass and be done with it.
But some of the extenders also need things to be lain out a little differently in order to attach to the appropriate elements. Take the Drop Shadow for example. In my first attempt, I converted the outer <div> to an ASP.NET Panel and applied the DropShadowExtender to it directly. This led to the grooviness you see below.
Which isn't the most ideal-looking piece of design I've done (look closely at the corners at the bottom). Also, you can't see it but the right-margin was no longer in effect. As in, this was right up against the right side of the screen.
The solution for this particular case was to wrap the entire HTML in another <div> and move the float:right and margin:0.5em; styles to the new outer <div>.
I won't go through all the little tweaks I had to make for the other controls. But here is the final HTML I needed to build to get this to work in both Firefox and IE (with *some* styles moved to CSS classes): <div style="float: right; margin: 0.5em; width: 150px;">
<asp:Panel ID="panelQuickLinks" runat="server" CssClass="quickLinks" Style="z-index: 20;">
<asp:Panel ID="quickLinksExpand" runat="server">
<div style="padding: 0.25em; background-color: white; height: 14px; color: steelblue; border: 1px solid steelblue; cursor: pointer;">
<div style="float: left;">
Quick Links
</div>
<div style="float: right; vertical-align: middle;">
<asp:Image ID="Image1" runat="server" ImageUrl="~/images/collapse.jpg" />
</div>
</div>
</asp:Panel>
<asp:Panel ID="quickLinksContent" runat="server">
<div style="padding: 0.5em; border-bottom: 2px solid white;">
<a href="#">Add Job</a><br />
<a href="#">Find a Job</a><br />
</div>
<div style="padding: 0.5em;">
<a href="#">Edit...</a><br />
</div>
</asp:Panel>
</asp:Panel>
</div>
So now I'm five levels deep and using a mix of <div>s and Panels each with its own unique little style attached. Not very pretty.
To be fair, it didn't take very long to mangle up my HTML to accommodate the extenders. And I'm certainly not proposing that what the toolkit team is doing is anything but sublime. Let's not ignore what I've actually done here: created a draggable, collapsible box with drop shadows that works in both IE and Firefox and I wrote zero javascript code.
But like many tools that deal with HTML, you still need more than a basic knowledge of HTML and CSS to get the extenders to match what you are picturing in your head.
Still, the fact that I *can* match what's in my head is testament to how far we've come.
Or a commentary on my lack of imagination.
Kyle the Extended
Monday, February 05, 2007
ASP.NET AJAX 1.0 has been released but you knew that. ASP.NET AJAX Control Toolkit has been released but you knew that, too. What you may not have known is that the RoundedCornersExtender in the new release now features the ability to specify which corners you wish to round. The code looks absolutely nothing like my version and from my brief comparison of their code to mine, that's a good thing. A nice little bonus: not only can you rounded specific corners (e.g. TopLeft, BottomRight) but there are shortcuts to round pairs of corners (e.g. Top will round both the top left and top right corners). So I'll take my version of the RoundedCorners down soon but in the meantime, if you've hit this page from a search engine, skip it and download the real thing.
Thursday, January 04, 2007
I've had some people send me e-mails over the last couple of months on how to use my RoundedCornersExtender. I would usually give them a half-baked answer from the bowels of my memory and apologize for not putting more thought into it.
But thanks to the persistent Dave Hobbs (http://www.licenseprofessor.com), I now have an updated version on the control. It now works with the latest versions of Atlas and the control toolkit (sorry, can never remember the official names). And it is bundled in a separate project so there is no need to copy files into the control toolkit. The control is named RoundedCornersEx so as not to conflict with the existing one.
NOTE: The project has a project reference to the toolkit project. You'll need to update that reference to make it work. Apologies for that manual step but the toolkit is just a zip file so I have no idea where it may be installed on your system.
Also note that there is some work underway to incorporate these changes into the official build. Have no idea when that will happen though. It's not in the latest release in any case.
Suvius.AjaxControlToolkit.zip (322.58 KB)
** UPDATE ** Latest version of the toolkit now has this functionality built-in and implemented better than mine. Download mine at your own peril.
Friday, October 06, 2006
Old, ugly search box reminiscent of the Teletubbies
I think I should have stuck with the junk-mail-subjects-as-post-titles theme. "oprah used it to lose weight" would have been pure gold...
Anyway, Jayzus only knows why I spend my time on this stuff but for whatever reason, the bubbly looking search box on my blog annoyed me enough that I extended an extender. The RoundedCornersExtender to be specific.
I added four properties to it: TopLeftCornerStyle, BottomLeftCornerStyle, TopRightCornerStyle, and BottomRightCornerStyle. The value of each of these can be one of: Inward (default), Outward, or None.
If you leave these properties off, you'll notice absolutely nothing different in the control which was my intent. But you can now change any of the individual corner styles to either Outward or None. Outward means that the corner will curve outward and None means no curving will occur at all.
To illustrate, here are the settings for the new search box you see above (and in the graphic below):
- TopLeftCornerStyle: Inward
- TopRightCornerStyle: None
- BottomLeftCornerStyle: Outward
- BottomRightCornerStyle: None
It is left as an exercise to the reader to determine what the settings are for the RSS section above the search box.
Svelte, new search box oozing class
The revised extender is attached. Note that I kept the same name for the control so it can't really co-exist with the existing RoundedCornersExtender. There's no real reason for them to co-exist. This is kind of a superset of the original one. Plus I wasn't really thinking that far ahead when I started.
I'll forego the detailed explanation mostly because by throwing it out there so cavalierly, I can make it sound like I whipped it up in a very short time (which I didn't) rather than spending several hours on it at the expense of my family (which I did). Plus I'm lazy.
I updated the CodingHillbilly theme if you want to see how it's done client-side. I also updated the other Atlas Control scripts because of changes made to the latest release version of Atlas (namely that it seems the AtlasControlExtender.js script has been renamed BaseScripts.js and there is now a Common.js script).
Side note on dasBlog: Does anyone know a way of developing themes in version 1.9 that doesn't require me to have to clear my temporary internet files every time I want to see my changes? No suggestions about the IE setting to get the latest version every time you load the page, please.
And lastly, when the &*$% are the Atlas people going to fix that typo/spelling mistake/abomination in the CollaspablePanelBehavior (sic)?
RoundedCorners.zip (4.96 KB)
** UPDATE ** Latest version of the toolkit now has this functionality built-in and implemented better than mine. Download mine at your own peril.
Thursday, October 05, 2006
Here's something you may not know about the TextboxWatermark Atlas Control. If you use the normal server-side control as depicted in the samples, the control will clear the watermark text from the textbox before submitting the form if the user hasn't added a value. Which is good. But if you add the TextboxWatermark client-side, it will submit the watermark text as the textbox's value. Which is bad. The rest of this post outlines why this happens so skip it if you don't care.
The TextboxWatermarkExtender class will loop through the Extender and register a little bit of javascript for each watermark control in the extender. One of those pieces is to register an OnSubmit statement which means that the script it's registering will get executed just before the form containing the textbox gets submitted.
The script is just a call to the watermark's onsubmit function in the main javascript file for it. That onsubmit function is pretty basic:
this._onSubmit = function() { var e = this.control.element; if(_watermarked) { // Clear watermark text before page is submitted this.clearText(false); _clearedForSubmit = true; } }
That is, if the textbox is watermarked, clear the text from it before submitting the page. This is so that you don't submit the watermark text as the textbox's value.
As I mentioned, the code that registers this OnSubmit statement is in the TextboxWatermarkExtender class. This means it is included whenever you use the <atlasToolkit:TextboxWatermarkExtender> control in your aspx page.
It also means that if you are registering your textbox watermark control client-side, you do not get the benefit of this functionality. Because you aren't using the <atlasToolkit:TextboxWatermarkExtender>. you are, I'm guessing, bypassing the Extender class and going straight to the underlying javascript.
You can see this behaviour in action by simply clicking the Search button at the top without putting in a search string. Because I'm adding my watermark client-side, you'll get the search results for the term "Enter a search string". If I were to use the server-side TextboxWatermarkExtender control, I'd get whatever behaviour happens when you search for an empty string in dasBlog.
But of course, I shan't be using the server-side control. My workaround for my blog will be to do nothing. The fix affects only those users who want to search for an empty string for Jayzus' sake. Like I've always said: you can't save everybody.
This came up while working on Flamingo and there, I don't have the luxury of assuming an empty string search will be meaningless. My fix is going to be to use the server-side control because the only reason I had the client-side control in there is to see if I could do it.
If you truly want a solution that you can use client-side, here's a rough draft of something that might work. Create a javascript function that calls the _onsubmit for each watermark object on the form. Doubt you'll be able to do that by iterating through a collection if you have more than one. You'll probably have to call the _onsubmit function for each one manually. Here's how you do it (copied straight from the control's source):
var o = Sys.Application.findObject('<id of watermark object>'); if(o) { o._onSubmit(); };
At the end of this function, add: return true;
Next, you'll need to wire this function into the form's onsubmit event:
< form id="form1" runat="server" onsubmit="javascript:return mySubmitFunction( );">
This whole thing is essentially what the extender class does for you. You have other alternatives to registering the submit function. A javascript call to document.forms[0].attachEvent anywhere on the page will probably work, at least in IE. I think the mechanism for attaching events is different in Firefox and Safari. You can also make your own call to Page.ClientScript.RegisterOnSubmitStatement but if you're doing that, you may as well use the server-side control anyway and avoid this mess.
Finally, this doesn't affect all the controls in the Atlas Toolkit. Most of them don't register client scripts in their Extender classes. I had a quick look through a few of them and didn't see any others, in fact. Which makes sense. It'll be necessary anywhere you need to alter the value of a form before submitting it and few of the controls do this.
Wednesday, October 04, 2006
Administrivia first: To those people searching for "hillbilly names" and stumbling across this site, my most humble apologies. Also, I've already abandoned my post-naming convention for fear that they get banned from search engines. And I have a feeling my last post contributed to the trackback spam I'm now encountering... So I keep waffling back and forth on my preferred AJAX mechanism for Flamingo. The two choices are: roll my own or use Atlas. There are some advantages to rolling my own. Less research into the technology. I've been AJAX-ing since the days of Microsoft.XMLDocument and I am pretty comfortable with it. I can page and sort fairly easily. Doing it this way also lends itself to adding the app to live.com or Google's personal portal page or wherever. It seems these portals like it best when you stick with standard HTML and Javascript although I have a feeling they may block anything fancy like XMLHTTP calls to a separate web service. I can also give the user more visual cues about what's going on. Showing little Processing... messages, clearer error messages, all the things you should do but usually don't. You also have more control over the content that is passed to and from the server with the XMLHTTP calls but seriously, who really cares about that anyway? On the other hand is Atlas with its all-powerful UpdatePanel. The compelling argument here? Sweet Jayzus you can build this stuff fast! No mucking around with XPath queries, no javascript coding to determine what page you're on, no futzing with sort directions. ASP.NET has all of this built-in. Ergo, the UpdatePanel has it all built-in. And with controls like the UpdatePanelAnimation, you can't even argue about the lack of feedback to users while "stuff" is happening in the background. So for the moment, I'm tilted into the Atlas camp again. This came last night after a couple of hours getting the paging working in the search results page. Faced with the daunting task of now having to wire it all into the selected music list, I decided to flip over to the Atlas version, which didn't have paging yet and see what would be involved in getting that working. Total elapsed time: 30 minutes including a timeout in the middle to help my daughter sack Eleuthera. For both the search results and the selected music list. And with better paging controls than I had (thanks to what appears to be some upgrades to the paging functionality in .NET 2.0). This framework is seriously going to rock when the documentation hits. Finally, a word on LiveWriter. Pretty impressed so far but it has an annoying habit. When you are at the very end of your current post, which you frequently are as you write it, you need to avoid holding down the SHIFT key and selecting text using the keyboard. If you hold SHIFT and press the left or up arrows, you select text normally. But after you've selected text, try pressing the right or down arrows. Nothing happens. Even if you've released the SHIFT key. In short, if you begin your selection by selecting the final character in your post, you can't de-select anything. My work-around is to start every post with "moo" then begin the post above it.
Tuesday, September 26, 2006
A couple of minor clean-up details on my recent Atlas journey.
Firstly, during the upgrade, I again had to remove all references to blowery.web from the web.config in dasBlog. Not sure why. It works on my laptop, not on the server. Perhaps something to do with Windows 2003. I care not...for now. But don't you folks go makin' the Coding Hillbilly all pop'lar now.
To clarify the javascript references for Atlas: There are a lot of them necessary for basic Atlas functionality. All of the Atlas .js files are in C:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas\ScriptLibrary\[Debug|Release].
The good news is you don't need to reference them yourself. The ScriptManager handles that for you. But if you are in an environment that doesn't allow ASP.NET server-side controls, like PHP, you need to copy these files somewhere in your project and reference them. In order. Don't ask me what the order is.
The extenders in the Atlas Control Toolkit also require appropriate .js file references. These files are located directly in the codebase which is wherever you unzipped it.
Again, good news here. If you add a CollapsiblePanelExtender server-side control to your .aspx page, you don't need to worry about these references. For dasBlog, however, the themes don't support server-side ASP.NET controls (as far as I know) so my options were: a) embed the server-side controls directly into the WebControl objects (which I did the first time around), or b) bring the .js files I needed into my theme folder and reference them directly
The extender scripts aren't quite as order specific. You need to reference the AtlasControlExtender.js script first, I imagine, but after that, they're pretty much all independent of each other. The CollapsiblePanel is one exception because it relies on animation code in the AtlasUIGlitz.js script and for whatever reason, my ScriptManager wasn't including it. I imagine one of the ScriptManager properties could handle that but the less mucking with compiled code, the better.
Tuesday, September 26, 2006
Man, I gotta lay off the 'shine. Two fairly decent credibility-buildin' posts absolutely slaughtered in a moment of weakness.
So here's a question for ya. Now that I have Atlas and dasBlog in their own little marriage of convenience, what do I do with it? I can't submit it for addition to the codebase because Atlas requires .NET 2.0 and I imagine my recommendation would be met with a hearty "Nein!" as the French might say. (Oh wait, we ended up saving them in that war, didn't we.)
I guess I could post the whole application again somewhere but frankly, I didn't do that much to the codebase itself. Ninety-five percent of it is documented on the Atlas site anyway.
Oh well, I was in it for the academic exercise anyway (unlike those glory-hounds in Edmonchuck). At some point, I'll probably start incorporating more Atlas features into dasBlog outside of the themes. At least where it makes sense, like when you're scrolling through dates looking at your dwindling viewership. And certainly when you're editting your links. Not sure what I'll do with that when it's done either since I'm essentially forking the code (tee hee) from what the newtelligence folks are working on.
Sucks that doing this is more fun than my other project which has some modicum of profitability to it.
Sunday, September 24, 2006
So now that DasBlog was all set up for Atlas, complete with ScriptManager, the next step was to add a couple of controls from the Atlas Control Toolkit. Specifically, I'm using a TextBoxWatermark in the search box and RoundedCorner and CollapsiblePanel controls for each of the funky brown blobs you see to the right.
In the first iteration, I had opened up each of these controls individually and had myself a little hootenanny in each one. I created a bunch of panels and images programmatically within the Render method as well as CollapsiblePanel and RoundedCorners controls attached to these panels. At some point, I found it necessary even to move all of that code out of the Render method and into CreateChildControls (where I believe it belongs; what if I want to handle events by any of the constituent controls?). Can't remember why I needed it, probably for the calendar which required me to create a whole brand now control specifically so I could wrap it in a bunch of Panels to house the heading and dropdown image.
The end result, as I alluded to in a post from many moons ago, was FrankenBlog. A blog only a mother could love (but not my mother). The controls were so intrinsically tailored to the CodingHillbilly theme, the code was nigh unreleasable to the general public, lest the coding Hillbilly be scoffed for reasons other than his penchant for plaid. (On a side note...does anyone even know what 'intrinsically' means?)
But I's a smart bumpkin and I knew others might like to know how to do this themselves. And I sure wasn't about to release that code. It was, to continue the Frankenstein theme, abby-normal.
Anyway, enough pre-amble. Here is the HTML for my Links box:
< div id="navLinksDiv"> <div class="navHeader" id="navLinksHeader"> <div style="float:left;">Links</div> <div style="float:right;"><img id="navLinksImage" style="cursor:hand;" src='<%radio.macros.imageurl( "webpart-up.gif" )%>' /></div> </div> <div id="navLinksContent"> <%navigatorLinks%> </div> </div>
Pretty standard HTML and it nicely highlights my disdain for using tables for layout.
And herein lies one of the many Good Things© about the toolkit extenders. They extend. As in you write your HTML like you normally would and apply whatever extenders you want to them.
One issue though is that all the toolkit samples show the extenders being applied to server-side controls. And they show the extenders as server-side controls themselves. But they don't need to be. The extenders can be applied client-side to regular HTML controls.
The following javascript will add a RoundedCorners extender to the navLinksDiv div above:
var roundedCorners = new AtlasControlToolkit.RoundedCornersBehavior( ); roundedCorners.set_Color( "#706861" ); roundedCorners.set_Radius( 10 );
var theDiv = new Sys.UI.Control( $("navLinksDiv") ); theDiv.get_behaviors( ).add( roundedCorners ); roundedCorners.initialize( );
It looks a little funky but yes, it's javascript. Atlas has abstracted a bunch of things and added an object model that I REALLY hope gets better documentation before release time. Hillbillies get cranky when there ain't no intelly-sense.
So we create a RoundedCornersBehavior object and set some properties on it. Then we create a Sys.UI.Control object which is, I think, a generic Atlas control. There are more specific ones but they correspond to actual form elements like textboxes and dropdown lists. In this case, we're applying it to a div, so we create a Sys.UI.Control.
Note that we pass in the ID of the DIV in the constructor (if I recall, the $ notation is Atlas-shorthand for document.getElementById but don't quote me). This was a little weird for me because now we've essentially got this Sys.UI.Control object that's bound somehow to the navLinksDiv HTML element. And in the next line, we call this method on it that attaches the roundedCorners behavior to it. And somehow this all filters back to the original HTML element, which hasn't really been touched.
Obviously, this code doesn't work out of the box. You need appropriate javascript references. The ScriptManager handles the base Atlas script references for things like the controls in the Sys.UI namespace. For the RoundedCornersBehavior object, you need to include a reference to the RoundedCornersBehavior.js file that is included in the AtlasControlToolkit source code:
< script language="javascript" type="text/javascript" src="themes/CodingHillbilly/ExtenderScripts/AtlasControlExtender.js"></script> <script language="javascript" type="text/javascript" src="themes/CodingHillbilly/ExtenderScripts/RoundedCornersBehavior.js"></script>
If you are using the server-side controls, this reference isn't necessary because the control itself handles the references for you using WebResource.axd, which I understand not at all. As you can see here, I've copied the .js file into my theme folder for easy reference. And the reference to AtlasControlExtender.js I gather is necessary if you're going to do any client-side extender work. All I know is that it didn't work when I just had RoundedCornersBehavior.js references and it did after I added AtlasControlExtender.js.
I'll wrap it up by saying the entire theme is attached. homeTemplate.blogTemplate is where all the action is. (Apologies in advanced on the formatting. For whatever reason, I slugged it out with Visual Studio as my editor and it kept wanting to reformat everything in that annoyingly helpful, Steve Urkel-like way.) There are a couple of other little things like the fact that Atlas will always call the pageLoad javascript function if it is defined and that the AtlasUIGlitz.js function is needed to make the animation in the CollapsiblePanel work. Hopefully the comments are clear.
The end result is: It is possible to use the Atlas Control Toolkit within your themes without having to muck around (much) with the codebase. On reflection, this whole post could have been laid out better had I known I would go into full "how to" mode. If anything is unclear, gimme a holler.
And finally, sweet Jayzus am I ever getting tired of correcting myself when my fingers inevitably type "behaviour". CodingHillbilly.zip (64.56 KB)
Saturday, September 23, 2006
Evenin' Hillbillies. Got somethin' t'say on my upgrade to dasBlog 1.9 so iffen you'll turn your attention from your squirrel skinnin', I'd be much obliged.
The reason for my upgrade is solely to support FlareItems, something I could have done earlier with one of the intermediate codebases but I don't do nuttin' until Scott Hanselman tells me to.
It wasn't something I was looking forward to because I had bastardized my existing version to wedge Atlas controls into it. As it turns out, though, I was able to learn from my recent trials and tribulations and get the new version of dasBlog working with Atlas controls without having to embed the controls into the codebase itself. So what you see on this har site are the following AtlasControlToolkit controls in action with very minimal changes to the core code:
In the previous version, I had embedded these controls server-side into the individual pieces, SideBarList, CategoryList, and so on and so forth. Which means these controls were useful in my theme and nowhere else. The brown rounded corners did not really lend themselves to...well...any other theme in the world.
Forthwith, a list of non-theme changes I made to dasBlog to support the inclusion of Atlas and the Atlas Control Toolkit:
- Upgrade the project to VS2005. Follow the instructions. They work.
- Add a reference to the Microsoft.Web.Atlas assembly in both the newtelligence.DasBlog.Web and newtelligence.DasBlog.Web.Core projects
- Add a reference to the AtlasControlToolkit assembly in the newtelligence.DasBlog.Web project. I'm not entirely certain this is necessary. It could be enough that you include the assembly in the bin folder because all the functionality is handled client-side. I.E. There are no actual server-side AtlasControlToolkit controls created.
- Modify the web.config to accommodate Atlas. This and the previous step are detailed here.
- Added the following code to the top of the Page_Load event in newtelligence.DasBlog.Web.Core.SharedBasePage:
Microsoft.Web.UI.ScriptManager manager = new Microsoft.Web.UI.ScriptManager( ); this.Controls.Add( manager );
The second last step I think might be considered a little dicey. The rest of it is essentially what you would do to any application to Atlas-ize it. But I needed a place to put the ScriptManager and this seemed the logical choice. Unfortunately, it means you're getting a ScriptManager whether you want one or not.
The other option is to include script references to all of the Atlas javascript files in your template which I'm not too comfortable with because those seem to be dependent on the order in which they are loaded.
Anyway, that's it really. Now you can start using Atlas features in dasBlog. You might need to play around with the settings on the ScriptManager depending on what you're doing. The next entry, which I will post shortly, will detail what I did to include toolkit controls into my theme.
Thursday, September 14, 2006
Before I get started, Atlas has an official name but I can't be bothered to change the category name so until I do, it's still Atlas on this site.
I'm still working on my music app, tentatively named Flamingo mostly because since I've moved to the Bahamas, I've always wanted to give an app that name. (It's the national bird and the source of a very entertaining albeit somewhat creepy routine at the local zoo). I've gone back to the basics and decided I need to get some features on it before playing around with the cutting edge crap.
One of those tasks is to have a reasonably easy way to update the database periodically as new music is added (and occasionally dropped lest I give the wrong impression). And let me tell you, dealing with metadata for MP3s and WMAs is a hideous process for someone with minor obsessive compulsive disorder.
The first problem comes when key fields are simply not filled in. I'm currently working through a list of approximately one hundred MP3s that have no official title.
That's the easy part. Next problem: People are absolutely horrible at tagging these things. Never mind the filenames_that_include_every_single_piece_of_data_within_them. Worse is when it's just plain wrong. The Guess Who sings Secret Agent Man? Leonard Cohen and Joe Cocker doing a duet on First We Take Manhattan? John Williams wrote the Back to the Future theme? The Rolling Stones doing I Saw Her Standing There?!?! Is one thing to be lazy, it's another to be on &*$%# crack, people!
These are hard things to fix because they don't show up unless you're actually listening to the song. And in most cases, you aren't in any position to actually correct the data.
I'm also extending this problem to one of my main pet peeves about metadata. I hate the fact that all of these fields are atomic. I.E. They take one value and one value only*. Again, my OCD kicks in here and it drives me crazy that I have to file Leon Redbone's and Zooey Deschanel's duet of Baby, It's Cold Outside under *either* R or D in the artist. Plus now I've created a brand new artist in the eyes of WMP: Redbone, Leon & Deschanel, Zooey. Any searches for other tunes by Leon Redbone will not bring up this little gem.
Same goes for albums and genres. The song Let It Be is probably on no less then seventeen different albums when you include soundtracks, greatest hits, compilations, not to mention live recordings. Shouldn't I be able to search for any one of those albums and pull up Let It Be? If a song is on the Bobby Jo's Last Supper soundtrack as well as The Stanton "Family" Reunion's Greatest Hits, a decent music search should reflect that.
The genre field is even more useless as a single-valued field. I haven't the slightest clue what the difference is between R&B, hip hop, urban jazz, funk fusion and progressive adult contemporary (which is a term I just made up but I'm sure has already been used). And people have a tendency to use Soundtrack as a genre unto its own which confuses things further. I can't even begin to try to categorize songs like this one.
So my intention is to not only make these fields multi-valued, but to allow the songs themselves to be tagged. With anything. You think a song is a combination of jazz and boogie? Log 'em both. Fumbling Toward Ecstasy is a good song to make out to? Tag it. You think Paradise By the Dashboard Light would make a good wedding song? Thy voice be heard.
It's coming, campers. The musical revolution will be heard. At least as long as the local electric company can keep the &*$% island powered.
*My experience is limited to how Windows Media Player tags its music. I have no doubt that some other apps have addressed this but I'm leery about dealing with them since the last time I tried, it was with Satan's music player, MusicMatch.
Tuesday, September 12, 2006
I don't like linking to someone else's hard work unless I can add something to it. Having said that, holy crap! Nikhil Kothari has added bookmarkability and the ability to add postbacks to a browser's history when you use the Atlas UpdatePanel. Not only that, you can control when and where a postback is added to the history.
How is this possible? I had simply written these two problems off as something AJAX developers would have to deal with until browsers caught up. I seriously picked the wrong week to start avoiding distractions from my other projects.
Sunday, September 10, 2006
So just as I had managed to justify not having to learn Test Driven Development, James Kovacs throws his hat into the ring. JP Boodhoo convinced me to at least be agnostic about the methodology some months ago. But James has made me feel downright guilty about not going into it further. Like Catholic-guilty.
Not to speak against JP's arguments, which are very good. This is more psychological. Some very interesting conversations aside, I know JP more by reputation. I hear he's a brilliant guy from many people and I assume that to be true. But I know first-hand that James is a brilliant guy (and a snappy dresser) so when he extols the virtues of a topic upon which I'm sittting on the fence, to paraphrase a billboard near Steinbach, MB, I can no longer be neutral. (If you're familiar with Steinbach, you can imagine what the context of that billboard is.)
So...ummm...that's the whole point of this post, I guess. That I should learn TDD and that other people are smart. Suppose I should point out some random technical junk to stave off a class action from my readership:
- FeedBurner FlareItems don't work with the release version of dasBlog 1.8. Latest builds have support for it as does the upcoming 1.9. Error comes from a missing attribute in the RSS.
- The following code will attach a TextboxWatermark Atlas Control Extender to an existing textbox using Javascript
var textbox = new Sys.UI.TextBox( $(<<ID of Textbox>>) ); var watermark = new AtlasControlToolkit.TextBoxWatermark( ); watermark.set_WatermarkText( "watermark text" ); watermark.set_WatermarkCssClass( "watermarked" ); textbox.get_behaviors( ).add( watermark ); watermark.initialize( );
You'll need to include reference to a lot of Atlas scripts if you haven't already included a ScriptManager. The scripts are most likely in: C:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas\ScriptLibrary on your machine. You'll also need a reference to AtlasControlExtender.js and TextboxWatermark.js from the latest Atlas Control Toolkit build. (NOTE: In the latest release, the AtlasControlExtender is still a compiled assembly; the latest build makes its source available.)
| |