|
|
|
Tuesday, 9 February 2010
|
Out, damned space
posted at
02:48 AM
|
trackback
|
|
link
The other day I was doing something where I wanted to display some data as a comma-delimited list, like so:
a, b, c, d
This seemed like a job for the Repeater control. So I created the markup for the control and included a separator template, like this:
<asp:Repeater runat="server" ID="Repeater1" DataSourceID="LinqDataSource3" > <ItemTemplate> <asp:Label runat="server" ID="labelCategory" Text='<%# Eval("Category") %>'> </asp:Label> </ItemTemplate> <SeparatorTemplate>, </SeparatorTemplate> </asp:Repeater> The result was this:
a , b , c, d
One thing was right (no trailing comma). But there was that silly space between the data item and the delimiter.
I spent as much as a minute looking to see if there was an easy fix for this. Failing in this effort, I invented a solution that seems ... well ... kinda complex, considering. So this is where the Internet tells me that a) I'm using the wrong control and/or b) alls you have to do is set a property, duh.
In the meantime, tho, what I ended up doing was this: I handled the Repeater control's PreRender event, which is well after data binding and about the last time you can go in and mess about with the markup that the control will render. In that event, I walked the contents of the Repeater control to, in effect, trim spaces.
But it wasn't quite as simple as I thought. Instead of being able to grub around directly -- in a simple string that represented the markup being rendered, say -- I was obliged to walk the control tree that was inside the Items collection exposed by the control. And even then, I did not get access to the actual delimiters, only to the data items. (This would be another good place for someone to tell me how I managed to overlook the easy way.)
The, dunno, peculiarity of the way that the Repeater renders is that the controls being rendered for each data item go something like this:
[LiteralControl][Bound control][LiteralControl]
IOW, the Repeater control brackets the data-bound control (in the example above, the Label control) with a LiteralControl instance on each side that pads the data with a space. Or that's what I was seeing, anyway. I'm not so clear on why it does this, but poking around inside the Items collection for each data element seemed to show this. (Is this the design? How come?)
What I ended up doing, then, was walking through the Items collection to get each item's control collection. Then I walked the control collection, and whenver I found a LiteralControl, I set its text to an empty string. If I found a Label control or Hyperlink control, I did a trim on it. Here's the code:
Public Sub RepeaterTrimItems(ByVal source As Object, ByVal e As EventArgs) Dim r As Repeater = CType(source, Repeater) For itemCtr As Integer = 0 To r.Items.Count - 1 For controlCtr As Integer = 0 To r.Items(itemCtr).Controls.Count - 1 Dim controlObj As Object = r.Items(itemCtr).Controls(controlCtr) Dim controlType As Type = controlObj.GetType() Select Case controlType.ToString().ToUpper() Case "SYSTEM.WEB.UI.LITERALCONTROL" Dim lit As LiteralControl = CType(controlObj, LiteralControl) lit.Text = lit.Text.Trim() If lit.Text = " " Then lit.Text = "" End If Case "SYSTEM.WEB.UI.WEBCONTROLS.LABEL" Dim lab As Label = CType(controlObj, Label) lab.Text = lab.Text.Trim() Case "SYSTEM.WEB.UI.WEBCONTROLS.HYPERLINK" Dim hlink As HyperLink = CType(controlObj, HyperLink) hlink.Text = hlink.Text.Trim() End Select Next Next End Sub There are a number of ways in which this is messy. It's hard-coded to work for a Repeater control, for one. Then in order to be able to set the Text property of any given control it encounters, it has to cast the objects in the Controls collection to an appropriate type. To do that, I have to get the type (GetType), and then I have a messy Select block that is (again) hard-coded to look for certain control types only. (This feels like something that could be done a lot more elegantly.) On the plus side, it works. To get it hooked up, all I do is this, on any Repeater control:
<asp:Repeater runat="server" ID="Repeater1" DataSourceID="LinqDataSource3" OnPreRender="RepeaterTrimItems" > <ItemTemplate> <asp:Label runat="server" ID="labelCategory" Text='<%# Eval("Category") %>'> </asp:Label> </ItemTemplate> <SeparatorTemplate>, </SeparatorTemplate> </asp:Repeater> Having done all this (once you get started, you sort of get caught up in the challenge), I took a step back and thought "But surely this isn't necessary for the slick new ListView control." But as far as I can tell, it's the same. I have a function that does virtually the same thing for the ListView control, the only difference being that I use an ItemSeparatorTemplate instead:
<asp:ListView ID="ListView2" runat="server" DataSourceID="LinqDataSource3" OnPreRender="TrimListView"> <ItemTemplate> <asp:Label runat="server" ID="labelCategory" Text='<%# Eval("Category") %>'> </asp:Label> </ItemTemplate> <ItemSeparatorTemplate>,</ItemSeparatorTemplate>
<LayoutTemplate> <div ID="itemPlaceholderContainer" runat="server" style=""> <span runat="server" id="itemPlaceholder" /> </div> </LayoutTemplate> </asp:ListView> Again, I'd be delighted to hear about how this is supposed to be done for real. In the meantime, tho, I have my comma-separated list.
[categories]
aspnet
|
posted at
12:32 AM
|
trackback
|
|
link
More on linking. (Earlier post) Compare these snippets in which the reader is invited to go elsewhere for more information[1]:
Version 1
Version 2
Maybe it's just me, but I find the first version, you know, friendlier. The second version gives me link fatigue just looking at it.
When you're creating links, it's tempting (and easy) to add just one or more two links, because who knows, those might end up being just the ones that the reader needs. The shotgun approach. And pretty soon you have a couple dozen, and the reader's eyes glaze over.
Herewith, then some thots for you to contemplate the next time that you make hyperlinks.
The ideal number of links to provide is one. That is, you link to the target document that is exactly what the reader needs right now.
Every additional link is more work for the reader. They have to click the link, look at the target document, and decide if it contains the information they want.
Let's make up some statistics. Say that your goal is to provide a link to the one correct document that will help the user right now. If you provide one link, you have 100% success in getting the user to that document. If you provide two links, only one of them is correct; the reader has a 50% chance of getting to the right document with a single click. If you provide 10 links, the reader's odds of getting directly to the correct doc are ... You see where this is going.
Now, you will say that you don't know what that ideal target document is, so you provide a selection of target documents for the user. Fair enough. But who has to do the work to determine which is the correct target? If you just create a long list of undifferentiated links, you're putting that burden on the user. Is that fair? (Do they want to click through 16 links?)
So let me posit that ...
You, as the writer, are in a better position to judge what the reader needs right now than the reader is. You know more than the reader, both about what you're writing and about where to find more information. Therefore, it's up to you to do that work, think about what the reader needs, and provide just the right link.
Granted, this can be hard. You must:- Understand why you're giving the reader the link in the first place. What information is the reader missing that you need to send them to?
- Understand what the reader will get from the target document. This means that you know yourself what information the target document(s) contain, and how the target document relates to the first point.
- Understand where not to send the user. This is really the salient point. You probably have a choice of target documents; some are more useful than others. You must understand why it's not useful to send the user to some of your possible selections. (Not making this choice is why you see long lists of links.)
Remember what I said last time: every link is a bright, shiny object that you're putting in front of the reader, tempting them to go away right now (and possibly not return). If too many of the bright, shiny objects turn out to just be frustrating for the reader, they're going to stop trusting you and your many links.
Don't just link because you can. Make sure that every link you create is adding value and that know what that value is. As that dude says (sort of): link with the end in mind.
[categories]
writing
|
posted at
06:25 PM
|
trackback
|
|
link
This is for fun. I was reading the article "UN climate report riddled with errors on glaciers", which reports on an IPCC report that has some errors in it. The controversy is mostly around one particular section of the report, a half page in a report that is 838 pages long[1], and which lists some (incorrect) numbers about how quickly glaciers are melting in the Himalayas.
Naturally, this has thrown gas onto the whole climate-change controversy, with skeptics in particular having a field day with the errors.
What I liked about the whole brouhaha, though, was the following. I bet you know why."It is a very shoddily written section," said Graham Cogley, a professor of geography and glaciers at Trent University in Peterborough, Canada, who brought the error to everyone's attention. "It wasn't copy-edited properly."
[categories]
editing
|
posted at
05:21 PM
|
trackback
|
|
link
Visual Web Developer has long had a blank-sheet-of-paper issue when you create a new Web site project or Web application project in Visual Studio. As in, you create the project and then you, developer person, get to start adding your own layout (master pages, css), content, and optionally, authentication. Among other things.
In the 2.0 release, we had what were referred to as Starter Kits, which were prebuilt apps for what were perceived to be common tasks -- "personal Web site" (which included a photo album -- this was before Flickr), time tracker, club site, stuff like that. But Starter Kits were, at best, a kind of add-on, and of course assumed that your goal was one of the types of Web sites for which a Starter Kit was available.
For ASP.NET 4, they've decided that pretty much all apps needed a certain core set of functionality. So for ASP.NET 4, when you create a Web project, you get certain functionality out of the box. The exception is if you explicitly choose to create an empty Web site (thusly named), which is about as empty as you can get. (You get a skeleton Web.config file and that's it.)
What you get Here's what Visual Studio 2010 builds for you when you create a new Web site/application project: - Web site folder structure.
- A master page.
- A Menu control (tabs) on master page that link to individual content pages.
- A CSS file (Styles folder).
- 2 free-form content pages (Default, About).
- jQuery (Scripts folder).
- Routing (which is basically just enabled by default).
- A Web.config file.
- A Global.asax file.
- forms authentication, which includes:
- A Login link on the master page
- A LoginView control on master page (shows “Hello, <you>” when you’re logged in)
- An Account folder that includes the following pages:
- Registration page (content page + CreateUserWizard control)
- Login page
- Change-password page
- Change-password success page

What you don’t get Certain functionality was left out by design: - Roles. This is explicitly disabled in the Web.config file.
- For forms authentication:
- A link to the change-password page.
- Reset password capability. (Because we don’t know what settings you might end up with for the membership provider, we don’t know whether we can (e.g.) send you your password.)
- SMTP configuration. You would need this to support change-password functionality.
What you would typically do The preceding is what's built (or not built) for you. You can actually press CTRL+F5 and see pages with content and some measure of design appear immediately after you create the site, which is quite a step up from the old days, where you'd just see a blank Default.aspx page.

If you want to restrict content to "members", you can do that by creating a folder, adding content, and then creating an authorization rule (either manually or using the Web Site Administration Tool) for that content. Note that you can do this all using declarative syntax; no code required for these various tasks.
What you'd typically do is along the lines of the following: - Add content pages.
- Add menu items (tabs) to the master page for any new content you create.
- (Optional) Tweak the layout of the master page.
- (Optional) Tweak the CSS file.
- (Optional) Define routes if you want to use routing.
- For forms authentication:
- Add a link somewhere to the ChangePassword.aspx page. (A good place might be on the Login page.)
- Create a folder for restricted content.
- Add content pages to the restricted folder.
- Configure authorization for the restricted content. Simplest case: deny access to anonymous users.
- (Optional) Configure the membership provider to specify how passwords are stored. You can do this using the Web Site Administration Tool.
- (Optional) Create a way for users to recover passwords. (Depends on how password encryption is configured, and this might require SMTP configuration.)
- (Optional) Configure SMTP, if you want to support recover-password scenarios.
- For roles/authorization (all optional):
- Enable roles.
- Create roles.
- (Manually) add users to roles. The default registration page does not a way to specify roles for users added at run time.
- Configure restricted content to allow access by role.
Notes On the master page, the link to the login page is a hyperlink, not a LoginStatus control. This was a deliberate decision so that pages that are rendered for anonymous users are lightweight – no view-state goo, no postback-link goo, etc. If you run the default page and look at the source, it’s very clean HTML.
The default page in the template contains this link: “You can also find documentation on ASP.NET at MSDN.” This links (will link) to some documentation on how to proceed from where you are.
By default, there is no link to the change-password page. Not all site necessarily want or need this functionality, and it's easy enough to change.
The login controls in the Account folder are all fully templated. (Templates are optional for these controls.) This makes it easier to tweak the layout and CSS for those controls.
The membership database and deployment There are a couple of issues with the membership database. First, if SQL Server Express is installed, the database is created automatically in App_Data by the membership provider the first time a user is registered. (Some consider it a bad practice to allow the database to be autocreated like this.) If you’re using the Visual Studio Development Server (a.k.a. Cassini) -- that is, you have created a file-system project -- this all works great. However, if you are using a) an IIS project and b) IIS 7 or above, the app pool uses an identity that does not have permission to write to the App_Data folder. There’s a KnowledgeBase article that describes how to fix this. If you don't, you see an error message when ASP.NET tries to write to the membership database. (The error does, however, link to the article, nice.)
A second issue is deployment. In general, you don’t want to deploy an .mdf file in the App_Data folder; most hosters won’t accept this. Instead, they give you a connection string to your piece of their SQL Server. Therefore, if you have an ASPNETDB.MDF file, during deployment you either have to migrate your local database or (probably more common) re-create it. For novice users, deploying the database isn’t necessarily a trivial task, so it's either re-create, as noted, or some drill-down to figure out how to do this.
In conclusion ... This is just a quick summary of what's going on with the new template. Interestingly, for those of us on the ASP.NET documentation team, the template means that we need to go revisit some of our docs and tweak them. For example, a lot of our walkthroughs (tutorials) were written with the assumption that you'd have to create these pages -- master page, CSS, login -- by hand as part of the tutorial. Not any more! Plus of course we need some documentation that guides users toward what to do next after they've created a Web site. But we can't really complain, since the change overall should make it easier for users (novices and experienced users, we hope) to get going with new Web sites.
[categories]
aspnet
|
Friday, 15 January 2010
|
ASP.NET page life cycle
posted at
09:51 AM
|
trackback
|
|
link
Just a quick note to draw your attention to an updated ASP.NET page life-cycle diagram that my colleague Tom has done for the docs:
ASP.NET Page Life Cycle Diagram
Here's a little peek (I don't want to steal his thunder, so I won't show the whole thing):
[categories]
aspnet
|
Wednesday, 6 January 2010
|
Straight into the vein
posted at
10:01 AM
|
trackback
|
|
link
From a post on the O'Reilly Radar blog. I wonder if this is the year we'll start hearing about people who will try to return to the (digital) simple life and go off the (virtual) grid.Email was the first electronic medium to raise my clock speed, and also my first digital distraction problem. After some "ding, you have mail," I turned off the blackberry notification buzz, added rationing to my kit bag of coping strategies, and kept on concentrating. Then RSS came along and it was like memetic crystal meth. The pursuit of novelty in super-concentrated form delivered like the office coffee service. Plus, no one had to worry about all that behind-the-counter pseudoephedrine run around. "Hey, read as much as you want, no houses were blown up in Indiana to make your brain buzz."
It was a RUSH to know all this stuff, and know it soonest; but it came like a flood. That un-read counter was HARD to keep to zero and there was always one more blog to add. Read one interesting post and be stuck with them forever. In time keeping up with my RSS reader came to be like Lucy in the chocolate factory with the conveyor belt streaming by. From my vantage point today, RSS seems quaint.
The good old days. I gave it up for good last year when I finally bought an iPhone and tapped Twitter straight into the vein. Yeah, I went real time.
Now I can get a hit at every stop light. Between previews at the movies. Waiting for the next course at a restaurant. While you are talking to me on a conference call (it's your fault, be interesting). When you look down at dinner to check yours. Last thing before I go to sleep. The moment I wake up. Sitting at a bar. Walking home. While opening presents on Christmas morning (don't judge me, you did it too). In between the sentences of this paragraph.
I am perfectly informed (I will know it before it hits the New York Times home page) and I'm utterly distracted.
-- Jim Stogdill
[categories]
technology
|
Sunday, 27 December 2009
|
"But we invented English!"
posted at
07:48 AM
|
trackback
|
|
link
Now and again, an Englishperson will utter what they imagine to be the ultimate argument for why their particular brand of English is the One True Language: "But we invented English!"
This is, needless to say, a specious argument. Except apparently it is needful to say, because I keep running across this argument. (#, #, #, #, #, #, ...) Herewith, therefore, a short guide to just why the argument "But we invented English" is nonsense.
1. No one invented English. What, you did? You and your sisters, and your cousins, and your aunts? Not quite. English has been in development, via many fascinating historical and linguistic turns, since before the Saxons and Danes established themselves in the British Isles in pre-Medieval times. Since that time, this once purely Germanic language has taken on a heavy dose of Old French, a healthy helping of Latin and Greek, and some tang from practically every other language it's ever come into contact with. This was not exactly a guided enterprise.
2. We invented English, too. If your ancestors invented English (which they didn't, see previous point), so did mine. British and American English began their split around 1600. That's still about 800 years of common Anglo-Saxon history and 500 years of common Anglo-Norman history before the split. Many people (maybe more) in the New World share that linguistic ancestry with everyone living in Engelond.
3. American English is more conservative than British English. American English preserves older grammatical and vocabulary and pronunciation (!) features, hence by some additional specious logic, is more "authentic" to the "original" version of English. The list of ways in which American English is "purer" than British English is too long to recount here. But as a good summary, try the first chapter of Origins of the Specious by Patricia O'Conner and Stewart Kellerman.
4. Conversely, British English is more "corrupted". British English has changed more with respect to "original" English than other dialects. Notably American, of course. See point #3: if you are British and speak English in some other way than Shakespeare did, how is it you're not speaking a "corrupted" English?
5. The English themselves don't even speak one version of English. From Newcastle to Norwich to Eastbourne to Penzance, England alone has more ways to speak English than the rest of the world. I exaggerate, but not much. The English, they invented English, and Scouse, and Geordie, and Brummie, and, what, a hundred other ways to not speak English the way it was invented by the English.
6. So what? Even if the English "invented" English -- but see points 1 through 5 -- why does that matter? Consider an analogy. The style of music known as rock-and-roll originated in the United States. (Note that I did not say "was invented" in the U.S.[1]) So Americans were the first to play rock-and-roll. Does this mean that a) the only way to play rock-and-roll correctly is the way that Americans do (whatever that might be), and b) Americans can run around the world telling people that they don't play rock-and-roll right? I'm trying to imagine how well that would go over. Especially in England.
Then again, I might be off base (<--Americanism) here. Perhaps English is like Szechuan cuisine, and the only way to get the authentic thing is to go to the source. Feel free to explain to me how this inventing-English thing works.
[categories]
language
|
posted at
10:03 AM
|
trackback
|
|
link
We tend to think of emergencies in terms of if -- "If this [dire situation] comes to pass, be prepared." When it comes to computers, tho, if is definitely the wrong word; it is (always) when. In particular, it's "When your hard disk crashes, be prepared".
I'm thinking about this because a) I've been digitizing LPs at a steady clip, which has garnered me many gigs of .wav files[1] that I do not want to have to reconstruct; b) Jeff Atwood today recounts a bitter lesson he learned when his service provider lost a disk and took with it his archive of blog posts; and c) I had a hard-disk failure of my own last week.
Can you throw a rock and hit someone who does not regularly back up their data? Probably all you had to do was reach up and conk yourself on the noggin. Unless you've dedicated some time to a plan and unless you dedicate time to a regular routine, odds are that there is stuff on your computer that you would lose if it went kablooey in the next 60 seconds. My kids have each lost substantial collections of music when a hard disk went south, for example.
An aside ... one disaster that I am not generally prone to these days is losing a document while I'm working on it due to the computer freezing or the power going out. As I work on documents, I save compulsively (SHIFT+F12 in Word, for example) -- essentially, each time I lift my fingers off the keyboard, I just hit Save. Too often in the past I have lost hours of work on a doc simply because it was all still in memory. Not so much any more.[ 2] Even as aware as I am of all this, and even having at times lost data that made me, you know, sad, I am still spotty about backing up. But I'm not hopeless. What it requires from me is two things:- The discipline to remind myself that the computer can crash at any time. This helps me overcome the "I'll get to it soon" mentality.
- A reasonably convenient way to actually back up. I note this because CDs and DVDs are not it for me, not when it takes an hour to burn a DVD, times however many disks it takes.
With this in mind, I have become a fan of portable storage. For work I'm currently engaged in, I use a thumbdrive that goes with me pretty much everywhere. If I'm editing book files, or spending days on a particularly gnarly spreadsheet, I have an up-to-date copy of it on the thumbdrive. And I'm pretty good about copying the documents off to the drive the actual same day that I have worked on them. (This had the added advantage of giving me access to the file(s) more-or-less at all times. Although that then introduces an issue of version control.)
For "real" backup I use portable USB hard drives. I have my music and photo collection at home, of course, and on a 500GB drive that I sling around with me in my backpack. A second such USB drive lives in my office at work. The manufacturers of these devices generally include backup software that's probably pretty sophisticated, but I don't use that. I just copy the data to the drive.
Second aside. My most recent hard-disk failure was the USB hard disk itself. I have a Hitachi Soft-Tough that proved not to be very tough at all. Portable devices are subject to their own slings and arrows of unfortunate fortune. See Joel's post (below). This is not a backup strategy, of course. This is just a backup tactic that gives me reason not to simply fling myself off a building if the computer dies or some other disaster transpires. I would of course still have to reconstuct all the programs I use and so on, and while that's an odious task, it's doable. Trying to recover all the actual data would be well-nigh impossible.
And -- my overall point -- this still is some sort of backup. We have oodles of computers in the house, and I'm quite sure that all of them have data on them that will result in tears and gnashing of teeth when (not if) the drives in those computers fail.
What's your story?
More reading:
[categories]
technology
|
posted at
12:24 PM
|
trackback
|
|
link
In my work, we deal with a lot of uses of the term and that are defined rigorously, speaking in the logical sense. Which is to say, in the programming sense. For example:
If firstTime = True And listCount > 0 Then ... End If
The AND expression here is clear: both conditions must apply in order for the result of the If test to resolve as true.
So that's programming (and formal logic). English syntax is a bit looser. What do you make of a sentence like this?This property returns true when the HiddenInput attribute is true and the HiddenInputAttribute.DisplayValue property is set to false. The scope of the word and here is not exactly clear. Does it mean (condensing here):
The property returns true when HiddenInput is true, and it also returns true when DisplayValue is true. Which would basically make the grammatical and (illogically?) into a logical OR. Or does it mean ...
The property is set to true when both HiddenInput is true and DisplayValue is true. Meaning that both conditions must be true.
What do you think?
[categories]
writing, editing
|
posted at
09:52 PM
|
trackback
|
|
link
I ran across an interesting article ("Is Bad Documentation Derailing Linux?") that floats the thesis that the lack of good documentation is hurting Linux acceptance. I don't use Linux (perhaps for obvious reasons?), so I don't have any first-hand thots on the state of docs for that product.
However, I do understand that good docs are an investment and that complete docs are practically impossible, even if you're paying a fleet of tech writers. As I've noted before, we have various reasons, some of them involuntary, to spend considerable effort on providing at least some docs for every last flippin' member in the .NET Framework. The count of a list of these members goes well into 6 figures.
At various times, folks I've worked with have done analyses of some open-source docs. There is much very fine work out there, no question. A comment that comes up, tho, is that the docs for OSS tend to cover cherry-picked topics -- there is excellent documentation for interesting features, but the quantity and quality tends to fall off as the scenarios get less mainstream. This is hardly surprising -- who wants to contribute to a community by slaving away at documentation that's obscure?
The article makes various interesting points, most of which are true of any software, open or otherwise. The point of the article, of course, is that with an OSS project, there's no management team to convince that these things are true. Instead, you have to convince your community.
"I think one thing we need to explore, though, is how to make technical writing economically feasible in the open source economy."
[...]
"The problem with documentation is that it's hard for the original developer to know what to document ... We all know we need it, but we never know how to write it without being either too sparse or too verbose and covering the wrong things anyway."
[...]
[N]ewbies "cannot be expected to read the source code."
[...]
"It can be done: examples, examples, examples ... When there are too many options, parameters and commands, examples cut through the noise to the cases most people need and the usage becomes clear."
[...]
"If the docs aren't done then the software isn't done and shouldn't be released." As the article says, it's a call to arms. I'd love to hear how this is received in the community.
[categories]
writing, technology
|
|
|