RESTful WCF at Atlanta Code Camp#

gullivers_travels

This past Saturday was the Atlanta Code Camp.  I want to be make a point of thanking Cliff Jacobson, Dan Attis, Doug Ware, Glen Gordon, Jeff Ammons and all the other organizers who made this a brilliant event.

My company, Magenic Technologies, presented at seven of the sessions this year. 

Sergey Barskiy, who was a developer on the CSLA-Lite team, presented on Building Silverlight Business Applications using CSLA.NET for Silverlight.

Whitney Weaver, another of our principal consultants and a master of all things data, spoke on What’s my data doing while I sleep? Tracking data changes in SQL Server 2008.

Colin Whitlatch presented an Introduction to ASP.NET MVC, and is planning to extend his presentation over the next few weeks on his blog, where he will be digging deep into ASP.NET MVC and helping others to do the same.

Jason Rainwater needs a blog, because he is currently one of the best WPF experts in Atlanta and there aren't enough venues at this point for him to show off everything he knows.  He did two presentations this year: WPF Custom Controls and WPF DataBinding.

I presented on REST-ful WCF (the hyphen is a personal grammatical quirk rather than any attempt to make a philosophical point) and Mocking with Rhino Mocks and TypeMock: A Head-to-head Comparison.  I also got to make a short app-dev appearance in Tejas Patel's Use of data mining controls with ASP.NET presentation.

As promised to the attendees, I'm making the code samples and slide-decks available.  Please excuse the lack of organization in the code -- it's pretty much just what I was writing while I was on-stage, but should be helpful if anyone is looking for samples.  All the code uses Visual Studio 2008.  The mocking samples will require that you have the appropriate dll's for Rhino Mocks, which is free,  and TypeMock Isolator, which has a 30-day trial.

I am indebted to Pedram Rezaei for getting me started on the WCF-to-Flikr sample.

The Rest-ful WCF slide-deck and code can be downloaded here.

The Mocking powerpoint and samples are available here.

Posted by James Ashley Sunday, March 15, 2009 11:53:42 AM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Meatware#

A Gibsonesque cyber-word, meatware refers, somewhat contemptuously, to those aspects of information processing that are neither software nor hardware.  Programming is a grueling mental activity, and there is a tendency among software programmers to, shall we say, not look after themselves.  There is an old adage that one should never trust a thin cook, and this might be extended to programmers also.  The most consummate technologists spend so much of their time in virtual worlds that their bodies often get neglected.  The state of their bodies becomes, consequently, an ironic badge of their devotion to their craft.

It has been said, mainly by its critics, that Modernism in philosophy since Descartes is distorted by the implicit assumption that object of philosophy is strictly rational, conscious, and intellectual.  This trend was turned back, somewhat, by Heidegger's discussion of Mood in his masterpiece Being and Time.  Maurice Merleau-Ponty's Phenomenology of Perception, which at times reads like a rewriting of Being and Time much as Sartre's Being and Nothingness does, takes this battle further by placing himself within the heart of the intellectual tradition, Husserl's Phenomenology, and emphasizing the point that all perception, all experience, occurs through the medium of our bodies.  This was, strangely enough, a revolutionary insight at the time.

Eventually Feminism (or at least certain branches of Feminist thought) took up this controversy and used it as a central template for understanding the misunderstandings between men and women.  Men misunderstand humanity as a primarily intellectual (and phallic) being.  Women, on the other hand, implicitly understand the role of the body in the same way that tides understand gravity.   It is an inescapable aspect of a woman's existence, which the scholars of women's issues tend to call "embodiment".

It can't be said that software programmers really learned anything from the insights of Feminism other than the fact that they would prefer to have very little to do with the body.  If there is such a thing as human nature, software programming tends to distort it and encourage anti-social behaviors such as distractedness, obsessiveness and self-medication.  Exemplary programmers need not be exemplary human beings, and perhaps ought not to be, to Aristotle's dismay.

Stephen Dubner at Our Daily Bleg suggests an economic explanation for the rise in American obesity.  He suggests that the elimination of outhouses and dramatic improvements in indoor plumbing may have led to the rapid increase in median weight.  Our improved ability to vacate our own waste, he avers, has lowered the inconvenience of indulging in the gastronomic pastime, and so we do.  It depends, I imagine, on whether one seeks answers in the superstructure or in the base. 

Vanity Fair, on the other hand, has a series of articles currently online which may provide a glimpse at what the unhealthy have to look forward to.  Though not himself a programmer, Christopher Hitchens has drunk, smoked and eaten himself to the point that he can be mistaken for one.  At 58, he attempts to turn back the clock of desultory living with a check-in at a spa, and writes about it. 

The articles are accompanied by illustrative photos which highlight this cautionary tale about the importance of maintaining your meatware.

Posted by James Ashley Thursday, September 18, 2008 4:39:50 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Extending the Ajax Control Toolkit Tab Container with Lazy Loading#

multi-tabs

 

download source code

ASP.NET has been missing a good, free tab control for a long time.  With the ACT Tab Container, we were finally given one.  It typically runs in client-side only mode, but can interact with server-code if we set its AutoPostback property to true.

Compared to what we had before, it is a huge improvement.  The peculiar thing about it, however, is that it isn't actually an Ajax control.  It doesn't use asynchronous postbacks or web service calls to talk to the server -- instead you just have these two mode: run it using client script only, or run it using server-side events and code-behind only.

So a few months ago I rectified this for a project, and only found out afterwards that Matt Berseth had already outlined the technique on his blog.  You basically run the tab container in client-side mode, and add update panels to the tab panels that you want to be ajaxy.  You then hook up the client-side ActivePageChanged event in such a way that it spoofs the Update Panel contained in the tab, causing an asynchronous (or partial) postback.

Matt also gave this technique a cool name.  He called it 'lazy loading the tab panel'.  Like lazy loading in OOP, using this technique the update panels inside each tab panel only do something when its tab is selected.  Information is loaded only when its needed, and not before.

I must admit that I hold some resentment against Matt for coming up with this first, and for coming up with the cool moniker for it.  On the other hand, the solution I came up with encapsulates all of the javascript needed for this into a nice simple extender control that you can drop on your page, which his does not, and I'm rather proud of this.

The VS 2008 project for this extender is linked at the top of this post.  To use it, you need to compile the project and add the compiled assembly to your project, or else just add the project to your solution and add a project reference.

1. Drop the TabContainerExtender control into your page.

2. Set the Extender's TargetControlID property to your TabContainer's ID.

3. In the RegisterUpdatePanels element of the Extender, map your tabs to your update panels.  This mapping tells the extender which Update Panels to activate when each tab is selected.

Your markup will look something like this:

    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 

4. If you want to add some code-behind to your active tab changed event, add set the OnActiveTabChanged property of the Extender to the name of your handler.  The thrown event will pass the correct Index number for the active Tab, as well as the ID of the mapped Update Panel.  The handler's signature looks like this:

        protected void ActiveTabChanged(int index, string panelID)

        {

            ...

        }

I highly encourage you to read Matt Berseth's blog entry (which I have to admit is pretty good) to get a clear idea of the techniques being applied in this ajax extender.  If you just need a quick solution, however, feel free to download this code from the link at the top and use it any way you like with no strings attached.  There is a sample project attached to the solution that will demonstrate how to use the Tab Container Extender, in case you run into any problems with lazy loading your panels.

For reference, here is the code for the sample implementation, which loads controls on the fly based on the tab selected:

    <cc1:TabContainer ID="TabContainer1" runat="server">
    <cc1:TabPanel ID="TabPanel1" runat="server" HeaderText="Tab Panel 1">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
        Content 1 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel2" runat="server" HeaderText="Tab Panel 2">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server">
        <ContentTemplate>
        Content 2 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel3" runat="server" HeaderText="Tab Panel 3">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel3" runat="server">
        <ContentTemplate>
        Content 3 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
    </cc1:TabContainer>
    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 
Posted by James Ashley Friday, June 13, 2008 2:35:50 PM (Eastern Daylight Time, UTC-04:00) #    Comments [4]
 del.icio.us | DiggThis

 

Navel Gazing#

orestes

In Greek, it is called Omphaloskepsis -- though the provenance of this term appears to be fairly recent.  Its origins seem to be found in Eastern meditative practices in which the subject concentrates on his navel, the center of his being, in order to shut out all worldly distractions.  The significance of the navel is also found in the origins of Western culture.  Omphalos, literally "navel", was used to describe the terrestrial location from which all life sprang.  It was also the name of the stone found in the temple at Delphi, purported to be the stone which Rhea swaddled in baby clothes and which the titan Chronos swallowed, believing it to be his son Zeus, prophesied to one day overthrow him.  Because of its divine origins, the Omphalos was believed to be a point of contact between the celestial and the terrestrial, and gazing at the Omphalos was equivalent to gazing into the realm of the gods.

It is also a mode of reflection common in times of uncertainty.  The IT industry is at such a point.  Any software professional who went through the .NET bust at the turn of the millennium and through the financial decline following 9/11 has an ingrained sense that changes in the economy can radically alter the face of IT.  The past five years have seen the emergence and adoption of various tools and methodologies, from Agile to Responsibility Driven Design to Domain Driven Design to alt.net, all premised on the notion that things haven't been going well, and if we all just put our heads together we will find a better way. 

Marshall McLuhan -- I believe it was in The Medium is the Massage -- tells an anecdote about a factory that brought in consultants to change their internal processes, resulting in a 10% increase in productivity.  A year later, for unspecified reasons, the factory reverted to its previous processes, and surprisingly increased productivity by another 10%.  This suggested to McLuhan that sometimes what one does to bring about change is not significant in itself.  Sometimes it is simply the message of change, rather than any particular implementation, which provides results.

The various methodologies, philosophies and practices of the past few years seem to have made improvements in some software houses, but it is not clear that this is due to the inherent wisdom of the prescribed techniques rather than, as McLuhan might say, the simple message that things aren't quite right with our industry.  The acolytes of each methodology that comes along initially cite, quite properly, Fred Brooks's influential articles The Mythical Man-Month and No Silver Bullet.  What they rarely do, once their movements achieve a certain momentum, is revisit those early arguments and evaluate whether they have accomplished what they set out to do.  Did they solve the problems raised by Fred Brooks?  Or do they just move on and "evolve"?

Besides all the process related changes that have been introduced over the pass few years, Redmond is currently caught up in a flurry activity, and has been releasing not only new versions of their standard development tools, but a slew of alpha and beta frameworks for new technologies such as Presentation Foundation, Silverlight, Entities Framework, and MVP which threaten to radically alter the playing field, and leaves developers in a quandary about whether to become early adopters -- risking the investment of lots of energy for technology that may potentially never catch on (DNA and Microsoft's DHTML come to mind) -- or stick with (now) traditional windows forms and web forms development, which may potentially become obsolete.

We also face the problem of too many senior developers.  There was a time when the .NET bubble drove all companies to promote developers rapidly in order to keep them, a tendency that kept expectations high and that did not really end with the collapse of the bubble.  Along with this, companies set the standard for senior developers, generally the highest level developers can attain short of management, as someone with ten years of development experience, a standard which, given the compact time frames of the IT industry, must have seemed a long way off.  But now we have lots of people in lots of IT departments with 10 years of experience, and they expect to be confirmed as senior developers.  Those that are already senior developers are wondering what their career path is, and management is not particularly forthcoming.

The combination of these factors means the IT population is graying but not necessarily maturing.  Management in turn is looking at ways to outsource their IT labor, under the misapprehension that IT fits into an assembly line labor model rather than a professional model in which system and business knowledge should ideally be preserved in-house.  IT, for most companies, falls on the expense side of the ledger, and one expects to find ways to make it more efficient.  The immature state of the profession, compared to medicine or teaching or even engineering, makes these efficiencies difficult to find.

Add to this an economy headed toward a recession or already in recession, and we have all the necessary ingredients for a period of deep navel gazing.  My feed reader recently picked up three, and I suspect this is only the beginning.

 

Martin Fowler's Bliki contains a recent entry on SchoolsOfSoftwareDevelopment which deals with the problem of competing methodologies, and the Habermassian problem of agreeing on a common set of criteria upon which they may be judged.

Instead what we see is a situation where there are several schools of software development, each with its own definitions and statements of good practice. As a profession we need to recognize that multiple schools exist, and that their approaches to software development are quite different. Different to the point that what one school considers to be exemplary is considered by other schools to be incompetent. Furthermore, we don't know which schools are right (in part because we CannotMeasureProductivity) although each school thinks of itself as right, with varying degrees of tolerance for the others.

 

A Canadian developer, D'Arcy from Winnipeg, wonders what the new Microsoft technology map entails for him.

For the last 7 years we've been learning the web form framework, learning the ins and outs of state management (regardless of your opinion if its good or bad), how to manage postbacks, and how to make the web bend and do summersaults based on what our needs were. And here we are again, looking at the next big paradigm shift: Webforms are still around, Rails-like frameworks are the new trend, and we have a vector based Flash-like framework that we can code in .NET. I find it funny that so many are wondering whether web forms will go away because of the new MVC framework Microsoft is developing, and *totally* ignore the bigger threat: being able to develop winform-like applications that will run on the web using Silverlight.

 

Finally, Shawn Wildermuth, the ADOGuy, has posted an existential rant on the state of the industry and the mercenary mentality on the part of management as well as labor, and the long-term implications of this trend.

In some sense we developers are part of the problem. Quitting your $75K/yr job to be hired back at $75/hr seems like a good deal, but in fact it is not a good deal for either party.  Your loyalty is to the paycheck and when you leave, the domain knowledge goes with you...

At the end of the contract you just move on, forcing you to divest in a personal stake. I miss that part of this business.  I have had more enjoyment about projects that didn't work than all the mercenary positions I've ever held...

So do I have a call for action?  No. I think that domain knowledge is an important idea that both developers and companies need to address, but I don't have a nice and tidy solution. This is a shift that I think has to happen in software development. Both sides of the table need to look long at the last five to ten years and determine if what we're doing now is better than before.  Does it only feel better because each line of code is cheaper to produce (mostly a product of better platforms, not better coders). I hope this can change.

 

Something is in the air.  A sense of uneasiness.  A rising dissatisfaction.  An incipient awareness of mauvaise foi.  Or perhaps just a feeling that the world is about to change around us, and we fear being left behind either because we didn't try hard enough, or because we weren't paying attention.

Posted by James Ashley Thursday, April 24, 2008 2:35:58 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Interop Forms Toolkit 2.0 Tutorial#

I originally wrote the prize-winning Interop Forms article below for code project.  The prize, an XBox 360 Elite system, was pretty sweet.  Even sweeter, however, was the nod I received from the Microsoft VB Team here: http://blogs.msdn.com/vbteam/archive/2007/06/01/so-what-does-lt-comclass-gt-actually-do.aspx and here: http://blogs.msdn.com/vbteam/archive/2007/06/04/interopforms-2-0-tip-1-font-property.aspx.

Posted by James Ashley Monday, October 08, 2007 10:52:05 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

sassy.net: Fall Fashions for .NET Programmers#

janerussell

This fall programmers are going to be a little more sassy.  Whereas in the past, trendy branding has involved concepts such as paradigms, patterns and rails, principles such as object-oriented programming, data-driven programming, test-driven programming and model-driven architecture, or tags like web 2.0, web 3.0, e-, i-, xtreme and agile, the new fall line features "alternative" and the prefix of choice: alt-.  The point of this is that programmers who work with Microsoft technologies no longer have to do things the Microsoft way.  Instead, they can do things the "Alternative" way, rather than the "Mainstream" way.  In the concrete, this seems to involve using a lot of open source frameworks like NHibernate that have been ported over from Java ... but why quibble when we are on the cusp of a new age.

Posted by James Ashley Saturday, October 06, 2007 5:25:35 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Coding is not a Spectator Sport#

matrix

 

This past Tuesday I attended a Microsoft technology event at a local movie theater.  Ever since the Matrix, movie theaters are apparently the convenient place to go to get technology updates these days.  If you've never been to one of these events, they involve a presenter or two with a laptop connected to the largest movie screen in the building.  The presenters then promote new Microsoft offerings by writing code on the big screen while software programmers who have somehow gotten the afternoon off from their bosses watch on.

Jim Wooley presented on LINQ, while a Microsoft employee presented on WCF.  The technologies looked pretty cool, but the presentations were rather dull.  I don't think this was really the fault of the presenters, though.  The truth is, watching other people code is a bit like watching paint dry, and seems to take longer.  Perhaps this is why pair programming, one of the pillars of extreme programming, has never caught on (failing to document your code, however, another pillar of extreme programming, has been widely adopted and, like Monsieur Jourdain, many developers have found that they'd been doing XP for years without even realizing it). 

Within these constraints -- that is that you are basically doing the equivalent of demonstrating how to hammer nails into a board for four hours -- the presenters did pretty well, although Mr. Wooley appeared to be somewhat nervous and kept insisting he was doing "Extreme Presenting" whenever he made a coding mistake and the greediest members of the audience would compete with one another to point out his failings.  The Microsoft presenter didn't encounter any compile errors like Mr. Wooley did, but on the other hand he was following a script and kept referring to it as he typed the code that we were all watching.  Why you should need a script to write uninteresting demo code that ultimately just emits "Hello, world" messages is beyond me, but that's what he did, and he demonstrated that there could be something even less able to hold the attention than watching someone write code -- watching someone write code by rote.

But it is easy to criticize, and in truth I never got to see the presentation on Silverlight given by Shawn Wildermuth (aka "adoguy"), which for all I know may have been much more entertaining and might have undermined my mantra that coding is not a spectator sport, but I'll never know because I had to skip out on it in order to attend a company dinner.  How I got invited to this dinner I'll never know, because I wasn't really very involved in the project that the dinner was intended to celebrate.

I arrived fashionably late by an hour, and as I entered I realized the only seat left was squeezed in between my manager, the CFO of the company and the Senior VP of IT.  This is a dreadful spot to be in, and into that spot I deposited myself.  The problem with being situated next to one's uppers at a social event is that one spends an inordinate amount of time trying to think of something to say that will impress one's uppers, while simultaneously trying to avoid saying anything to demonstrate one's utter unfitness for one's position.  And here I was next to my boss, who was sitting across from his boss, who was sitting across from his boss.  And as I sat, watching what appeared to be scintillating conversation at the opposite end of the table, my end was completely silent with an air of tension about it.

So I picked up a menu and tried to order.  This was a steak and seafood restaurant, and judging by the prices, approximately twice as good as Longhorn or Outback.  I took the highest priced item, divided the cost by half, and ordered the crawfish pasta with a glass of wine.  Then I sat back to listen to the silence.  Finally someone struck up a conversation about insurance (my industry).  If you want to know how dreadfully dull insurance talk is, it's a bit like -- actually, there is nothing as boring as insurance talk because it is the sine qua non against which all boredom should be judged.  Listening to insurance talk is the sort of thing that makes you want to start cutting yourself for distraction (it's an old POW trick), and just as I was reaching for the butter knife I found myself telling the jazz story.

The jazz story went over well and seemed to break the ice, so I followed it up with the Berlin mussels story, which was also a hit.  I drank more wine and felt like I was really on a roll.  I'd demonstrated my ability to talk entertainingly around my bosses and as the food arrived I was able to maintain the mood with a jaunty disquisition on men's fashion and how to select a good hunting dog.  But I grew overconfident.  Over dessert, I decided to play the teacup game, which is a conversation game my friend Conrad at The Varieties had taught me, and it was a disaster.  Apparently I set it up wrong, because a look of disgust formed on the CFO's face.  My manager tried to save with a distracting story about hygiene, but rather than leave things well enough alone, I decided to continue with the asparagus story, and pretty well ruined the evening.  Oh well.  Bye-bye annual bonus.

Which all goes to show, entertainment is a damnably difficult business.

eddie

I can probably improve my dinner conversation by reading a bit more P.G. Wodehouse and bit less of The New Yorker (which is where I got the fateful asparagus story) but how to improve a Microsoft presentation is a much trickier nut to crack.  How much can you realistically do to dress up watching other people code?

Then again, it is amazing what passes for a spectator sport these days, from Lumberjack Olympics to Dancing with the Stars.  Perhaps one of the strangest cultural trends is the popularity of poker as a spectator sport -- something that would have seemed unimaginable back in the day.  The whole thing revolves around a handful of people dressed up in odd combinations of wigs, sunglasses and baseball caps to hide their tells playing a card game that depends largely on luck, partly on a grasp of probabilities, and partly on being able to guess what your opponents are guessing about you.  Is there anything in this jumble of crazy costumes, luck and skill that can be used to improve a typical Microsoft presentation?

The truth is, even skill isn't so important in creating a successful spectator sport.  Take quiz shows, which once were devoted to very tough questions that left the audience wondering how the contestants could know so much (it turned out, of course, that often they were cheating).  Over time, these shows became simpler and simpler, until we ended up with shows like Are You Smarter Than a 5th Grader (which makes you wonder how they find contestants so dumb) and the very successful Wheel of Fortune (in which you are challenged to list all the letters of the alphabet until a hidden message becomes legible).  Demonstrating skill is not the essence of these games.

If you have ever seen National Lampoon's Vegas Vacation (fourth in the series, but my personal favorite), you will recall the scene where, after loosing a large portion of his life savings at a casino, Chevy Chase is taken by his cousin Eddie to a special place with some non-traditional games of luck such as rock-paper-scissors, what-card-am-I-holding, and pick-a-number-between-one-and-ten.  This, it turns out, is actually the premise of one of the most popular American game shows of the year, Deal Or No Deal, hosted by the failed-comedian-actor-turned-gameshow-host Howie Mandel.  The point of this game is to pick a number between one and twenty-six, which has a one in twenty-six chance of being worth a million dollars.  The beauty of the game is that the quick and the slow, the clever and the dim, all have an equal chance of winning.  The game is a great leveler, and the apparent pleasure for the audience is in seeing how the contestants squirm.

I had initially thought that Mr. Wooley's palpable nervousness detracted from his presentation, but the more I think about it, the more I am convinced that his error was in not being nervous enough.  The problem with the format of Microsoft presentations is that there is not enough at stake.   A presenter may suffer the indignity of having people point out his coding errors on stage or of having bloggers ask why he needs a script to write a simple demo app -- but at the end of the day there are no clear stakes, no clear winners, no clear losers.

The secret of the modern spectator sport -- and what makes it fascinating to watch -- is that it is primarily about moving money around.  Televised poker, Survivor-style Reality shows, and TV game shows are all successful because they deal with large sums of money and give us an opportunity to see what people will do for it.  Perhaps at some low level, it even succeeds at distracting us from what we are obliged to do for money.

And money is the secret ingredient that would liven up these perfunctory Microsoft events.  One could set a timer for each code demonstration, and oblige the presenter to finish his code -- making sure it both compiles and passes automated unit tests -- in the prescribed period in order to win a set sum of money.  Even better, audience members can be allowed to compete against the official Microsoft presenters for the prize money.  Imagine the excitement this would generate, the unhelpful hints from the audience members to the competitors, the jeering, the side-bets, the tension, the drama, the spectacle.  Imagine how much more enjoyable these events would be.

Microsoft events are not the only places where money could liven things up, either.  What if winning a televised presidential debate could free up additional dollars to presidential candidates?  What if, along with answering policy questions, we threw in geography and world event questions with prize money attached?  Ratings for our presidential debates might even surpass the ratings for Deal Or No Deal.

Academia would also be a wonderful place to use money as a motivator.  Henry Kissinger is reported to have said that academic battles are so vicious because the stakes are so low.  Imagine how much more vicious we could make them if we suddenly raised the stakes, offering cash incentives for crushing intellectual blows against one's enemies in the pages of the Journal of the History of Philosophy, or a thousand dollars for each undergraduate ego one destroys with a comment on a term paper.  Up till now, of course, academics have always been willing to do this sort of thing gratis, but consider how much more civilized, and how clearer the motives would be, if we simply injected money into these common occurrences.

Posted by James Ashley Sunday, September 23, 2007 4:38:57 PM (Eastern Daylight Time, UTC-04:00) #    Comments [2]
 del.icio.us | DiggThis

 

Do Computers Read Electric Books?#

In the comments section of a blog I like to frequent, I have been pointed to an article in the International Herald about Pierre Bayard's new book,  How to Talk About Books You Haven't Read.

Bayard recommends strategies such as abstractly praising the book, offering silent empathy regarding someone else's love for the book, discussing other books related to the book in question, and finally simply talking about oneself.  Additionally, one can usually glean enough information from reviews, book jackets and gossip to sustain the discussion for quite a while.

Students, he noted from experience, are skilled at opining about books they have not read, building on elements he may have provided them in a lecture. This approach can also work in the more exposed arena of social gatherings: the book's cover, reviews and other public reaction to it, gossip about the author and even the ongoing conversation can all provide food for sounding informed.

I've recently been looking through some AI experiments built on language scripts, based on the 1966 software program Eliza, which used a small script of canned questions to maintain a conversation with computer users.  You can play a web version of Eliza here, if you wish.  It should be pointed out that the principles behind Eliza are the same as those that underpin the famous Turing Test.  Turing proposed answering the question can machines think by staging an ongoing experiment to see if machines can imitate thinking.  The proposal was made in his 1950 paper Computing Machinery and Intelligence:

The new form of the problem can be described in terms of a game which we call the 'imitation game." It is played with three people, a man (A), a woman (B), and an interrogator (C) who may be of either sex. The interrogator stays in a room apart front the other two. The object of the game for the interrogator is to determine which of the other two is the man and which is the woman. He knows them by labels X and Y, and at the end of the game he says either "X is A and Y is B" or "X is B and Y is A." The interrogator is allowed to put questions to A and B thus:

C: Will X please tell me the length of his or her hair?

Now suppose X is actually A, then A must answer. It is A's object in the game to try and cause C to make the wrong identification. His answer might therefore be:

"My hair is shingled, and the longest strands are about nine inches long."

In order that tones of voice may not help the interrogator the answers should be written, or better still, typewritten. The ideal arrangement is to have a teleprinter communicating between the two rooms. Alternatively the question and answers can be repeated by an intermediary. The object of the game for the third player (B) is to help the interrogator. The best strategy for her is probably to give truthful answers. She can add such things as "I am the woman, don't listen to him!" to her answers, but it will avail nothing as the man can make similar remarks.

We now ask the question, "What will happen when a machine takes the part of A in this game?" Will the interrogator decide wrongly as often when the game is played like this as he does when the game is played between a man and a woman? These questions replace our original, "Can machines think?"

The standard form of the current Turing experiments is something called a chatterbox application.  Chatterboxes abstract the mechanism for generating dialog from the dialog scripts themselves by utilizing a set of rules written in a common format.  The most popular format happens to be an XML standard called AIML (Artificial Intelligence Markup Language).

What I'm interested in, at the moment, is not so much whether I can write a script that will fool people into thinking they are talking with a real person, but rather whether I can write a script that makes small talk by discussing the latest book.  If I can do this, it should validate Pierre Bayard's proposal, if not Alan Turing's.

Posted by James Ashley Thursday, March 01, 2007 11:46:18 AM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

Speech Recognition And Synthesis Managed APIs In Windows Vista: Part II#

Playing with the speech synthesizer is a lot of fun for about five minutes (ten if you have both Microsoft Anna and Microsoft Lila to work with)  -- but after typing "Hello World" into your Speechpad document for the umpteenth time, you may want to do something a bit more challenging.  If you do, then it is time to plug in your expensive microphone, since speech recognition really works best with a good expensive microphone.  If you don't have one, however, then go ahead and plug in a cheap microphone.  My cheap microphone seems to work fine.  If you don't have a cheap microphone, either, I have heard that you can take a speaker and plug it into the mic jack of your computer, and if that doesn't cause an explosion, you can try talking into it.

While speech synthesis may be useful for certain specialized applications, voice commands, by cantrast, are a feature that can be used to enrich any current WinForms application. With the SR Managed API, it is also easy to implement once you understand certain concepts such as the Grammar class and the SpeechRecognitionEngine.

We will begin by declaring a local instance of the speech engine and initializing it. 

	#region Local Members
		
        private SpeechSynthesizer synthesizer = null;
        private string selectedVoice = string.Empty;
        private SpeechRecognitionEngine recognizer = null;
        
        #endregion
        
        public Main()
        {
            InitializeComponent();
            synthesizer = new SpeechSynthesizer();
            LoadSelectVoiceMenu();
            recognizer = new SpeechRecognitionEngine();
            InitializeSpeechRecognitionEngine();
        }
        
        private void InitializeSpeechRecognitionEngine()
        {
            recognizer.SetInputToDefaultAudioDevice();
            Grammar customGrammar = CreateCustomGrammar();
            recognizer.UnloadAllGrammars();
            recognizer.LoadGrammar(customGrammar);
            recognizer.SpeechRecognized += 
            	new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized);
            recognizer.SpeechHypothesized += 
            	new EventHandler<SpeechHypothesizedEventArgs>(recognizer_SpeechHypothesized);
        }
   
        private Grammar CreateCustomGrammar()
        {
            GrammarBuilder grammarBuilder = new GrammarBuilder();
            grammarBuilder.Append(new Choices("cut", "copy", "paste", "delete"));
            return new Grammar(grammarBuilder);
        }
        

The speech recognition engine is the main workhorse of the speech recognition functionality.  At one end, we configure the input device that the engine will listen on.  In this case, we use the default device (whatever you have plugged in), though we can also select other inputs, such as specific wave files.  At the other end, we capture two events thrown by our speech recognition engine.  As the engine attempts to interpret the incoming sound stream, it will throw various "hypotheses" about what it thinks is the correct rendering of the speech input.  When it finally determines the correct value, and matches it to a value in the associated grammar objects, it throws a speech recognized event, rather than a speech hypothesized event.  If the determined word or phrase does not have a match in any associated grammar, a speech recognition rejected event (which we do not use in the present project) will be thrown instead.

In between, we set up rules to determine which words and phrases will throw a speech recognized event by configuring a Grammar object and associating it with our instance of the speech recognition engine.  In the sample code above, we configure a very simple rule which states that a speech recognized event will be thrown if any of the following words: "cut", "copy", "paste", and "delete", is uttered.  Note that we use a GrammarBuilder class to construct our custom grammar, and that the syntax of the GrammarBuilder class closely resembles the syntax of the StringBuilder class.

This is the basic code for enabling voice commands for a WinForms application.  We will now enhance the Speechpad application by adding a menu item to turn speech recognition on and off,  a status bar so we can watch as the speech recognition engine interprets our words, and a function that will determine what action to take if one of our key words is captured by the engine.

Add a new menu item labeled "Speech Recognition" under the "Speech" menu item, below "Read Selected Text" and "Read Document".  For convenience, name it speechRecognitionMenuItem.  Add a handler to the new menu item, and use the following code to turn speech recognition on and off, as well as toggle the speech recognition menu item.  Besides the RecognizeAsync() method that we use here, it is also possible to start the engine synchronously or, by passing it a RecognizeMode.Single parameter, cause the engine to stop after the first phrase it recognizes. The method we use to stop the engine, RecognizeAsyncStop(), is basically a polite way to stop the engine, since it will wait for the engine to finish any phrases it is currently processing before quitting. An impolite method, RecognizeAsyncCancel(), is also available -- to be used in emergency situations, perhaps.

        private void speechRecognitionMenuItem_Click(object sender, EventArgs e)
        {
            if (this.speechRecognitionMenuItem.Checked)
            {
                TurnSpeechRecognitionOff();
            }
            else
            {
                TurnSpeechRecognitionOn();
            }
        }

        private void TurnSpeechRecognitionOn()
        {
             recognizer.RecognizeAsync(RecognizeMode.Multiple);
             this.speechRecognitionMenuItem.Checked = true;       
        }

        private void TurnSpeechRecognitionOff()
        {
            if (recognizer != null)
            {
                recognizer.RecognizeAsyncStop();
                this.speechRecognitionMenuItem.Checked = false;
            }
        }
        

We are actually going to use the RecognizeAsyncCancel() method now, since there is an emergency situation. The speech synthesizer, it turns out, cannot operate if the speech recognizer is still running. To get around this, we will need to disable the speech recognizer at the last possible moment, and then reactivate it once the synthesizer has completed its tasks. We will modify the ReadAloud() method to handle this.

 
       private void ReadAloud(string speakText)
       {
            try
            {
               SetVoice();
               recognizer.RecognizeAsyncCancel();
               synthesizer.Speak(speakText);  
               recognizer.RecognizeAsync(RecognizeMode.Multiple);
            }
            catch (Exception ex)
            {
               MessageBox.Show(ex.Message);
            }
       
       }
The user now has the ability to turn speech recognition on and off. We can make the application more interesting by capturing the speech hypothesize event and displaying the results to a status bar on the Main form.  Add a StatusStrip control to the Main form, and a ToolStripStatusLabel to the StatusStrip with its Spring property set to true.  For convenience, call this label toolStripStatusLabel1.  Use the following code to handle the speech hypothesized event and display the results:
        
        private void recognizer_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            GuessText(e.Result.Text);
        }

        private void GuessText(string guess)
        {
            toolStripStatusLabel1.Text = guess;
            this.toolStripStatusLabel1.ForeColor = Color.DarkSalmon;
        }
        

Now that we can turn speech recognition on and off, as well as capture misinterpretations of the input stream, it is time to capture the speech recognized event and do something with it.  The SpeechToAction() method will evaluate the recognized text and then call the appropriate method in the child form (these methods are accessible because we scoped them internal in the Textpad code above).  In addition, we display the recognized text in the status bar, just as we did with hypothesized text, but in a different color in order to distinguish the two events.

        
        private void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            string text = e.Result.Text;
            SpeechToAction(text);
        }

        private void SpeechToAction(string text)
        {
            TextDocument document = ActiveMdiChild as TextDocument;
            if (document != null)
            {
                DetermineText(text);
                
                switch (text)
                {
                    case "cut":
                        document.Cut();
                        break;
                    case "copy":
                        document.Copy();
                        break;
                    case "paste":
                        document.Paste();
                        break;
                    case "delete":
                        document.Delete();
                        break;
                }
            }
        }

        private void DetermineText(string text)
        {
            this.toolStripStatusLabel1.Text = text;
            this.toolStripStatusLabel1.ForeColor = Color.SteelBlue;
        }

        

Now let's take Speechpad for a spin.  Fire up the application and, if it compiles, create a new document.  Type "Hello world."  So far, so good.  Turn on speech recognition by selecting the Speech Recognition item under the Speech menu.  Highlight "Hello" and say the following phrase into your expensive microphone, inexpensive microphone, or speaker: delete.  Now type "Save the cheerleader, save the".  Not bad at all.

Posted by James Ashley Saturday, February 24, 2007 2:31:13 PM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

Speech Recognition And Synthesis Managed APIs In Windows Vista: Part I#

VistaSpeechAPIDemo.zip - 45.7 Kb

VistaSpeechAPISource.zip - 405 Kb

Introduction

One of the coolest features to be introduced with Windows Vista is the new built in speech recognition facility.  To be fair, it has been there in previous versions of Windows, but not in the useful form in which it is now available.  Best of all, Microsoft provides a managed API with which developers can start digging into this rich technology.  For a fuller explanation of the underlying technology, I highly recommend the Microsoft whitepaper. This tutorial will walk the user through building a common text pad application, which we will then trick out with a speech synthesizer and a speech recognizer using the .Net managed API wrapper for SAPI 5.3. By the end of this tutorial, you will have a working application that reads your text back to you, obeys your voice commands, and takes dictation. But first, a word of caution: this code will only work for Visual Studio 2005 installed on Windows Vista. It does not work on XP, even with .NET 3.0 installed.

Background

Because Windows Vista has only recently been released, there are, as of this writing, several extant problems relating to developing on the platform.  The biggest hurdle is that there are known compatibility problems between Visual Studio and Vista.  Visual Studio.NET 2003 is not supported on Vista, and there are currently no plans to resolve any compatibility issues there.  Visual Studio 2005 is supported,  but in order to get it working well, you will need to make sure you also install service pack 1 for Visual Studio 2005.  After this, you will also need to install a beta update for Vista called, somewhat confusingly, "Visual Studio 2005 Service Pack 1 Update for Windows Vista Beta".  Even after doing all this, you will find that all the new cool assemblies that come with Vista, such as the System.Speech assembly, still do not show up in your Add References dialog in Visual Studio.  If you want to have them show up, you will finally need to add a registry entry indicating where the Vista dll's are to be found.  Open the Vista registry UI by running regedit.exe in your Vista search bar.  Add the following registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\v3.0 Assemblies with this value: C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\v3.0. (You can also install it under HKEY_CURRENT_USER, if you prefer.)  Now, we are ready to start programming in Windows Vista.

Before working with the speech recognition and synthesis functionality, we need to prepare the ground with a decent text pad application to which we will add on our cool new toys. Since this does not involve Vista, you do not really have to follow through this step in order to learn the speech recognition API.  If you already have a good base application, you can skip ahead to the next section, Speechpad, and use the code there to trick out your app.  If you do not have a suitable application at hand, but also have no interest in walking through the construction of a text pad application, you can just unzip the source code linked above and pull out the included Textpad project.  The source code contains two Visual Studio 2005 projects, the Textpad project, which is the base application for the SR functionality, and Speechpad, which includes the final code.

All the same, for those with the time to do so, I feel there is much to gain from building an application from the ground up. The best way to learn a new technology is to use it oneself and to get one's hands dirty, as it were, since knowledge is always more than simply knowing that something is possible; it also involves knowing how to put that knowledge to work. We know by doing, or as Giambattista Vico put it, verum et factum convertuntur.

Textpad

Textpad is an MDI application containing two forms: a container, called Main.cs, and a child form, called TextDocument.csTextDocument.cs, in turn, contains a RichTextBox control.

Create a new project called Textpad.  Add the "Main" and "TextDocument" forms to your project.  Set the IsMdiContainer property of Main to true.  Add a MainMenu control and an OpenFileDialog control (name it "openFileDialog1") to Main.  Set the Filter property of the OpenFileDialog to "Text Files | *.txt", since we will only be working with text files in this project.  Add a RichTextBox control to "TextDocument", name it "richTextBox1"; set its Dock property to "Fill" and its Modifiers property to "Internal".

Add a MenuItem control to MainMenu called "File" by clicking on the MainMenu control in Designer mode and typing "File" where the control prompts you to "type here".  Set the File item's MergeType property to "MergeItems". Add a second MenuItem called "Window".  Under the "File" menu item, add three more Items: "New", "Open", and "Exit".  Set the MergeOrder property of the "Exit" control to 2.  When we start building the "TextDocument" form, these merge properties will allow us to insert menu items from child forms between "Open" and "Exit".

Set the MDIList property of the Window menu item to true.  This automatically allows it to keep track of your various child documents during runtime.

Next, we need some operations that will be triggered off by our menu commands.  The NewMDIChild() function will create a new instance of the Document object that is also a child of the Main container.  OpenFile() uses the OpenFileDialog control to retrieve the path to a text file selected by the user.  OpenFile() uses a StreamReader to extract the text of the file (make sure you add a using declaration for System.IO at the top of your form). It then calls an overloaded version of NewMDIChild() that takes the file name and displays it as the current document name, and then injects the text from the source file into the RichTextBox control in the current Document object.  The Exit() method closes our Main form.  Add handlers for the File menu items (by double clicking on them) and then have each handler call the appropriate operation: NewMDIChild(), OpenFile(), or Exit().  That takes care of your Main form.

        #region Main File Operations
		
        private void NewMDIChild()
        {
            NewMDIChild("Untitled");
        }

        private void NewMDIChild(string filename)
        {
            TextDocument newMDIChild = new TextDocument();
            newMDIChild.MdiParent = this;
            newMDIChild.Text = filename;
            newMDIChild.WindowState = FormWindowState.Maximized;
            newMDIChild.Show();
        }

        private void OpenFile()
        {
            try
            {
                openFileDialog1.FileName = "";
                DialogResult dr = openFileDialog1.ShowDialog();
                if (dr == DialogResult.Cancel)
                {
                    return;
                }
                string fileName = openFileDialog1.FileName;
                using (StreamReader sr = new StreamReader(fileName))
                {
                    string text = sr.ReadToEnd();
                    NewMDIChild(fileName, text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void NewMDIChild(string filename, string text)
        {
            NewMDIChild(filename);
            LoadTextToActiveDocument(text);
        }

        private void LoadTextToActiveDocument(string text)
        {
            TextDocument doc = (TextDocument)ActiveMdiChild;
            doc.richTextBox1.Text = text;
        }

        private void Exit()
        {
            Dispose();
        }
        
        #endregion
        

To the TextDocument form, add a SaveFileDialog control, a MainMenu control, and a ContextMenuStrip control (set the ContextMenuStrip property of richTextBox1 to this new ContextMenuStrip).  Set the SaveFileDialog's defaultExt property to "txt" and its Filter property to "Text File | *.txt".  Add "Cut", "Copy", "Paste", and "Delete" items to your ContextMenuStrip.  Add a "File" menu item to your MainMenu, and then "Save", Save As", and "Close" menu items to the "File" menu item.  Set the MergeType for "File" to "MergeItems". Set the MergeType properties of "Save", "Save As" and "Close" to "Add", and their MergeOrder properties to 1.  This creates a nice effect in which the File menu of the child MDI form merges with the parent File menu.

The following methods will be called by the handlers for each of these menu items: Save(), SaveAs(), CloseDocument(), Cut(), Copy(), Paste(), Delete(), and InsertText(). Please note that the last five methods are scoped as internal, so they can be called by the parent form. This will be particularly important as we move on to the Speechpad project.

        
        #region Document File Operations

        private void SaveAs(string fileName)
        {
            try
            {
                saveFileDialog1.FileName = fileName;
                DialogResult dr = saveFileDialog1.ShowDialog();
                if (dr == DialogResult.Cancel)
                {
                    return;
                }
                string saveFileName = saveFileDialog1.FileName;
                Save(saveFileName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SaveAs()
        {
            string fileName = this.Text;
            SaveAs(fileName);
        }

        internal void Save()
        {
            string fileName = this.Text;
            Save(fileName);
        }

        private void Save(string fileName)
        {
            string text = this.richTextBox1.Text;
            Save(fileName, text);
        }

        private void Save(string fileName, string text)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(fileName, false))
                {
                    sw.Write(text);
                    sw.Flush();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }    
        }
        
        private void CloseDocument()
        {
            Dispose();
        }

        internal void Paste()
        {
            try
            {
                IDataObject data = Clipboard.GetDataObject();
                    if (data.GetDataPresent(DataFormats.Text))
                    {
                        InsertText(data.GetData(DataFormats.Text).ToString());
                    }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        internal void InsertText(string text)
        {
            RichTextBox theBox = richTextBox1;
            theBox.SelectedText = text;
        }

        internal void Copy()
        {
            try
            {
                RichTextBox theBox = richTextBox1;
                Clipboard.Clear();
                Clipboard.SetDataObject(theBox.SelectedText);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        internal void Cut()
        {
            Copy();
            Delete();
        }

        internal void Delete()
        {
            richTextBox1.SelectedText = string.Empty;
        }

        #endregion
        

Once you hook up your menu item event handlers to the methods listed above, you should have a rather nice text pad application. With our base prepared, we are now in a position to start building some SR features.

Speechpad

Add a reference to the System.Speech assembly to your project.  You should be able to find it in C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\.  Add using declarations for System.Speech, System.Speech.Recognition, and System.Speech.Synthesis to your Main form. The top of your Main.cs file should now look something like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Speech;
using System.Speech.Synthesis;
using System.Speech.Recognition;

In design view, add two new menu item to the main menu in your Main form labeled "Select Voice" and "Speech".  For easy reference, name the first item selectVoiceMenuItem.  We will use the "Select Voice" menu to programmatically list the synthetic voices that are available for reading Speechpad documents.  To programmatically list out all the synthetic voices, use the following three methods found in the code sample below.  LoadSelectVoiceMenu() loops through all voices that are installed on the operating system and creates a new menu item for each.  VoiceMenuItem_Click() is simply a handler that passes the click event on to the SelectVoice() method. SelectVoice() handles the toggling of the voices we have added to the "Select Voice" menu.  Whenever a voice is selected, all others are deselected.  If all voices are deselected, then we default to the first one.

Now that we have gotten this far, I should mention that all this trouble is a little silly if there is only one synthetic voice available, as there is when you first install Vista. Her name is Microsoft Anna, by the way. If you have Vista Ultimate or Vista Enterprise, you can use the Vista Updater to download an additional voice, named Microsoft Lila, which is contained in the Simple Chinese MUI.  She has a bit of an accent, but I am coming to find it rather charming.  If you don't have one of the high-end flavors of Vista, however, you might consider leaving the voice selection code out of your project.

        
        private void LoadSelectVoiceMenu()
        {
            foreach (InstalledVoice voice in synthesizer.GetInstalledVoices())
            {
                MenuItem voiceMenuItem = new MenuItem(voice.VoiceInfo.Name);
                voiceMenuItem.RadioCheck = true;
                voiceMenuItem.Click += new EventHandler(voiceMenuItem_Click);
                this.selectVoiceMenuItem.MenuItems.Add(voiceMenuItem);
            }
            if (this.selectVoiceMenuItem.MenuItems.Count > 0)
            {
                this.selectVoiceMenuItem.MenuItems[0].Checked = true;
                selectedVoice = this.selectVoiceMenuItem.MenuItems[0].Text;
            }
        }
        
        private void voiceMenuItem_Click(object sender, EventArgs e)
        {
            SelectVoice(sender);
        }
        
        private void SelectVoice(object sender)
        {
            MenuItem mi = sender as MenuItem;
            if (mi != null)
            {
                //toggle checked value
                mi.Checked = !mi.Checked;

                if (mi.Checked)
                {
                    //set selectedVoice variable
                    selectedVoice = mi.Text;
                    //clear all other checked items
                    foreach (MenuItem voiceMi in this.selectVoiceMenuItem.MenuItems)
                    {
                        if (!voiceMi.Equals(mi))
                        {
                            voiceMi.Checked = false;
                        }
                    }
                }
                else
                {
                    //if deselecting, make first value checked, 
                    //so there is always a default value
                    this.selectVoiceMenuItem.MenuItems[0].Checked = true;
                }
            }
        }
        

We have not declared the selectedVoice class level variable yet (your Intellisense may have complained about it), so the next step is to do just that.  While we are at it, we will also declare a private instance of the System.Speech.Synthesis.SpeechSynthesizer class and initialize it, along with a call to the LoadSelectVoiceMenu() method from above, in your constructor:

	
	#region Local Members
		
        private SpeechSynthesizer synthesizer = null;
        private string selectedVoice = string.Empty;
        
        #endregion
        
        public Main()
        {
            InitializeComponent();
            synthesizer = new SpeechSynthesizer();
            LoadSelectVoiceMenu();
        }
   

To allow the user to utilize the speech synthesizer, we will add two new menu items under the "Speech" menu labeled "Read Selected Text" and "Read Document".  In truth, there isn't really much to using the Vista speech synthesizer.  All we do is pass a text string to our local SpeechSynthesizer object and let the operating system do the rest.  Hook up event handlers for the click events of these two menu items to the following methods and you will be up and running with an SR enabled application:

        
        #region Speech Synthesizer Commands

        private void ReadSelectedText()
        {
            TextDocument doc = ActiveMdiChild as TextDocument;
            if (doc != null)
            {
                RichTextBox textBox = doc.richTextBox1;
                if (textBox != null)
                {
                    string speakText = textBox.SelectedText;
                    ReadAloud(speakText);
                }
            }
        }

        private void ReadDocument()
        {
            TextDocument doc = ActiveMdiChild as TextDocument;
            if (doc != null)
            {
                RichTextBox textBox = doc.richTextBox1;
                if (textBox != null)
                {
                    string speakText = textBox.Text;
                    ReadAloud(speakText);
                }
            }
        }

        private void ReadAloud(string speakText)
        {
            try
            {
                SetVoice();
                synthesizer.Speak(speakText);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void SetVoice()
        {
                try
                {
                    synthesizer.SelectVoice(selectedVoice);
                }
                catch (Exception)
                {
                MessageBox.Show(selectedVoice + "\" is not available.);
                } 
        }

        #endregion
        
Posted by James Ashley Friday, February 23, 2007 11:07:16 AM (Eastern Standard Time, UTC-05:00) #    Comments [5]
 del.icio.us | DiggThis

 

Two Kinds of Jargon#

I had taken it for granted that "Web 2.0" is simply a lot of hype until I came across this defense of the term by Kathy Sierra by way of Steve Marx's blog.  Kathy Sierra argues that "Web 2.0" is not simply a buzzword because it is, in fact, jargon.  She goes on to explore the notion of jargon and to explain why jargon is actually a good thing, and shamefully maligned.  This, I thought, certainly goes against the conventional wisdom. 

In my various careers, I have become intimately familiar with two kinds of jargon: academic jargon and software jargon.  I will discuss academic jargon first, and see if it sheds any light on software jargon.  The English word jargon is derived from the Old French word meaning "a chattering," for instance of birds.  It is generally used somewhat pejoratively, as in this sentence from an article by George Packer in the most recent New Yorker concerning the efforts of anthropologists to make the "war on terror" more subtle as well as more culturally savvy:

One night earlier this year, Kilcullen sat down with a bottle of single-malt Scotch and wrote out a series of tips for company commanders about to be deployed to Iraq and Afghanistan.  He is an energetic writer who avoids military and social-science jargon, and he addressed himself intimately to young captains who have had to become familiar with exotica such as "The Battle of Algiers," the 1966 film documenting the insurgency against French colonists.

 

In this passage, jargon is understood as a possibly necessary mode of professional language that, while it facilitates communication within a professional community, makes the dissemination of ideas outside of that community of speakers difficult.

Even with this definition, however, one can see how there is a sense in which the use of professional jargon is not a completely bad thing, but is in fact a trade-off.  While it makes speaking between professional communities difficult, as well as initiation into such a community difficult -- for instance the initiation of young undergraduates into philosophical discourse--, once one is initiated into the argot of a professional community, the special language actually facilitates communication by serving as a short-hand for much larger concepts and by increasing the precision of the terms used within the community, since non-technical language tends to be ambiguous in a way that technical jargon, ideally, is not.  Take, for instance, the following sentences:

The question about that structure aims at the analysis of what constitutes existence. The context of such structures we call "existentiality". Its analytic has the character of an understanding which is not existentiell, but rather existential. The task of an existential analytic of Dasein has been delineated in advance, as regards both its possibility and its necessity, in Dasein's ontical constitution.

 

This passage is from the beginning of Martin Heidegger's Being and Time, as translated by John Macquarrie and Edward Robinson.  To those unfamiliar with the jargon that Heidegger develops for his existential-phenomenology, it probably looks like balderdash.  One can see how potentially, with time and through reading the rest of this work, one might eventually come to understand Heidegger's philosophical terms.  Jargon, qua jargon, is not necessarily bad, and much of the bad rap that jargon gets is often due to the resistance to comprehension and the sense of intellectual insecurity it engenders when one first encounters it.  Here is another example of jargon I pulled from a recent technical post on www.beyond3d.com called Origin of Quake3's Fast InvSqrt():

The magic of the code, even if you can't follow it, stands out as the i = 0x5f3759df - (i>>1); line. Simplified, Newton-Raphson is an approximation that starts off with a guess and refines it with iteration. Taking advantage of the nature of 32-bit x86 processors, i, an integer, is initially set to the value of the floating point number you want to take the inverse square of, using an integer cast. i is then set to 0x5f3759df, minus itself shifted one bit to the right. The right shift drops the least significant bit of i, essentially halving it.

 

I don't understand what the author of this passage is saying, but I do know that he is enthusiastic about it and assume that, as with the Heidegger passage, I can come to understand the gist of the argument given a week and a good reference work.  I also believe that the author is trying to say what he is saying in the most precise and concise way he is able, and this is why he resorts to one kind of  jargon to explain something that was originally written in an even more complicated technical language: a beautiful computer algorithm.

However there is another, less benign, definition for jargon that sees its primary function not in clarifying concepts, but in obfuscating them.  According to Theodor Adorno, in his devastating and unrelenting attack on Heidegger in The Jargon of Authenticity, jargon is "a sublanguage as superior language."  For Adorno jargon, especially in Heidegger's case, is an imposture and a con.  It is the chosen language of charlatans. Rudolf Carnap makes a similar, but not so brutal, point in section 5 of his "Overcoming Metaphysics" entitled "Metaphysical Pseudo-Sentences", where he takes on Heidegger's notorious sentence from Being and Time, "Das Nichts selbst nichtet" (Nothingness itself nothings) for its meaninglessness.

We might be tempted to try to save jargon from itself, then, by distinguishing two kinds of jargon: good jargon and bad jargon.  Turning to distinctions is at least as old as the use of jargon in order to clarify ideas, and goes back as far as, if not farther than, Phaedrus's distinction between the heavenly and the common Aphrodites in Plato's The Symposium.  With Phaedrus we can say that the higher and the baser jargon can be distinguished, as he distinguishes two kinds of love, by the intent of the person using jargon.  When jargon is used in order to clarify ideas and make them precise, then we are dealing with proper jargon.  When jargon is used, contrarily, to obfuscate, or to make the speaker seem smarter than he really is, then this is deficient or bad jargon.

There are various Virgin and the Whore problems with this distinction, however, not least of which is how to tell the two kinds of jargon apart.  It is in fact rather rare to find instances of bad jargon that everyone concedes is bad jargon, with the possible exception of hoaxes like the Sokal affair, in which physicist Alan Sokal wrote a jargon laden pseudo-paper about post-modernism and quantum mechanics, and got it published in a cultural studies journal.  Normally, however, when certain instances of jargon are identified as "bad" jargon, we also tend to find defenders who insist that it is not and claim that, to the contrary, those calling it bad jargon simply do not understand it.  This is a difficulty not unlike one which a wit described when asked to define bad taste.  "Bad taste," he said, "is the garden gnome standing in my neighbors front lawn."  When asked to define good taste, the wit continued, "Good taste is that plastic pink flamingo standing in my lawn."

There are more difficulties with trying to distinguish good jargon from bad jargon, such as cases where good jargon becomes bad over time, or even cases where bad jargon becomes good.  Cases of the latter include Schopenhauer's reading of a popular and apparently largely incorrect account of of Indian philosophy and then absorbing this into his own very insightful and influential philosophical project.  Georges Bataille's misreading of Hegel and Jacques Lacan's misreading of Freud also bore impressive fruit.  Finally, there's the (probably apocryphal) story of the student of Italian who approached T.S. Eliot and began asking him about his peculiar and sometimes incorrect use of Italian in his poetry, until Eliot finally broke off the conversation with the admission, "Okay, you caught me."   Cases such as these undermine the common belief that it is intent, or origins, which make a given jargon good or bad.

The opposite can, of course, also happen.  Useful jargon may, over time, become bad and obfuscating.  We might then say that while the terms used in Phenomenology proper are difficult but informative, they were corrupted when Heidegger took them up in his Existential-Phenomenology, or we might say that Heidegger's jargon is useful but later philosophers influenced by his philosophy such as Derrida and the post-structuralists corrupted it, or finally we might even say that Derrida got it right but his epigones in America were the ones who ultimately turned his philosophical insights into mere jargon.  This phenomenon is what I take Martin Fowler to be referring to in his short bliki defense of the terms Web 2.0 and Agile entitled Semantic Diffusion.  According to Fowler:

Semantic diffusion occurs when you have a word that is coined a person or group, often with a pretty good definition, but then gets spread through the wider community in a way that weakens that definition. This weakening risks losing the definition entirely - and with it any usefulness to the term.

Thus Fowler takes up Kathy Sierra's defense of Web 2.0 as jargon, recognizes some weaknesses in this explanation, and then fortifies the defense of the term with the further explanation that while the term may be problematic now, it was right in its origins, and pure in its intent.

Fowler here makes a remarkably Heideggerian observation.  Heidegger was somewhat obsessed with language and believed that language tends, over time, to hide and obfuscate meaning, when it should rather shed light on things.  Along this vein,  Being and Time begins with the claim that we today no longer understand the meaning of Being, and that this forgetting is so thorough that we are not even any longer aware of this absence of understanding, so that even the question "What Is Being?", which should be the most important question for us, is for the most part ignored and overlooked.  To even begin understanding Being, then, we must first try to understand the meaning of the question of Being.  We must first come to the realization that there is even a problem there in the first place which needs to be resolved.  Heidegger's chosen solution to this problem involves the claim that while language conceals meaning, it also, in its origins, is able to reveal it if we are able to come to understand language correctly.  He gives an example with the term aletheia, which in Greek means truth.  By getting to the origins of language and the experience of language, we can reveal aletheia. Aletheia, etymologically, means not-forgetting (thus the river Lethe is, in Greek mythology, the river of forgetting that the dead must cross before resting in Hades), and so the truth is implicitly an unconcealment that recovers the meanings implicit in language.  The authentic meaning of jargon, Fowler similarly claims, can be arrived at if we remove the accretions caused by "semantic diffusion" and get back to the original intent.

But is this true?  Do apologetics for terms such as "Web 2.0" and "Agile" insisting that they are "jargon" ultimately succeed?  Do such attempts reveal the original intent implicit in the coining of these terms or do they simply conceal the original meanings even further?

My personal opinion is that jargon, by its nature, never really reveals, but always in one way or another, by condensing thought and providing a shorthand for ideas, conceals.  It can of course be useful, but it can never be instructive, but rather gives us a sense that we understand things we do not understand simply because we know how to use a given jargon.  At best, jargon can be used as an indicator that points to a complex of ideas shared by a given community.  At worse, it is used as shorthand for bad or incoherent ideas that never themselves get critical treatment because the jargon takes the place of ideas, and becomes mistaken for ideas.  This particularly seems to be the case with the defense of "Web 2.0" and "Agile" as "jargon", as if people have a problem with the terms themselves rather than what they stand for.  "Jargon", as a technical term, is not particularly useful.  It is to some extent already corrupt from the get-go.

One way around this might be to simply stop using the term "jargon", whether bad or good, when discussing things like Web 2.0 and Agile.  While it is common in English to use Latin derived terms for technical language and Anglo-Saxon words for common discourse, in this case we might be obliged to make the reverse movement as we look for an adequate replacement term for "jargon".

In 2005, the Princeton philosopher Harry Frankfurt published a popular pamphlet called On Bullshit that attempts to give a philosophical explanation of the term. On first blush, this title may seem somewhat prejudicial, but I think that, as with jargon, if we get away from pre-conceived notions as to whether the term is good or bad, it will be useful as a way to get a fresh look at the term we are currently trying to evaluate, "Web 2.0".  It can also be used most effectively if we do the opposite of what we did with "jargon"; jargon was first taken to appropriately describe the term "Web 2.0", and then an attempt was made to understand what jargon actually was.  In this case, I want to first try to understand what bullshit is, and then see if it applies to "Web 2.0".

Frankfurt begins his analysis with a brief survey of the literature on bullshit, which includes Max Black's study of "humbug" and Augustine of Hippo's analysis of lying.  From these, he concludes that bullshit and lying are different things, and as a preliminary conclusion, that bullshit falls just short of lying.  Moreover, he points out that it is all pervasive in a way that lying could never be.

The realms of advertising and of public relations, and the nowadays closely related realm of politics, are replete with instances of bullshit so unmitigated that they can serve among the most indisputable and classic paradigms of the concept.

Not satisfied with this preliminary explanation, however, Frankfurt identifies further elements that characterize bullshit, since there are many things that can fall short of a lie and yet, perhaps, not rise to the level of bullshit.  He then identifies inauthenticity as the hallmark that distinguishes bullshit from lies, on the one hand, and simple errors of fact, on the other.

For the essence of bullshit is not that it is false but that it is phony. In order to appreciate this distinction, one must recognize that a fake or a phony need not be in any respect (apart from authenticity itself) inferior to the real thing. What is not genuine need not also be defective in some other way. It may be, after all, an exact copy. What is wrong with a counterfeit is not what it is like, but how it was made.

 

It is not what a bullshitter says, then, that marks him as a bullshitter, but rather his state-of-mind when he says it.  For Frankfurt, bullshit doesn't really even belong on the same continuum with truth and falsehood, but is rather opposed to both.  Like the Third Host in Dante's Inferno, it is indifference to the struggle that ultimately identifies and marks out the class of bullshitters.

Again, there are echoes of Heidegger here.  According to Heidegger, we are all characterized by this "thrownness", which is the essence of our "Being-In-The-World".  In our thrownness, we do not recognize ourselves as ourselves, but rather as das Man, or as the they-self,

which we distinguish from the authentic Self – that is, from the Self which has been taken hold of in its own way [eigens ergriffenen]. As they-self, the particular Dasein has been dispersed into the ‘they’, and must first find itself.” And further “If Dasein discovers the world in its own way [eigens] and brings it close, if it discloses to itself its own authentic Being, then this discovery of the ‘world’ and this disclosure of Dasein are always accomplished as a clearing-away of concealments and obscurities, as a breaking up of the disguises with which Dasein bars its own way.

The main difference between Frankfurt's and Heidegger's analysis of authenticity, in this case, is that Frankfurt seems to take authenticity as normative, whereas Heidegger considers authenticity as the zero-point state of man when we are first thrown into the world.

For now, however, the difference isn't all that important.  What is important is Frankfurt's conclusion about the sources of bullshit.  At the end of his essay, Frankfurt in effect writes that there are two kinds of bullshit, one of which is defensible and one of which is not.  The indefensible kind of bullshit is based on a subjectivist view of the world which denies truth and falsity altogether (and here I take Frankfurt to be making a not too veiled attack on the relativistic philosophical disciplines that are based on Heidegger's work).  The defensible form of bullshit -- I hesitate to call it good bullshit -- is grounded in the character of our work lives, which force us to work with and represent information that is by its nature too complex for us to digest and promulgate accurately.  This, I take it, is the circumstance academic lecturers and others frequently find themselves in, as the stand behind the podium and are obliged to talk authoritatively about subjects they do not feel up to giving a thorough, much less an authentic, account of.

Bullshit is unavoidable whenever circumstances require someone to talk without knowing what he is talking about. Thus the production of bullshit is stimulated whenever a person’s obligations or opportunities to speak about some topic are more excessive than his knowledge of the facts that are relevant to that topic.

 

This class of speech is the result of our inability to apply Wittgenstein's dictum, "Whereof one cannot speak, thereof one must be silent."  There are times when we are not in a position to remain silent, and so are obligated to bullshit.  Bullshit, in these cases, is a way of making the best of our situation.

Per the original arrangement, it is now time to put  "bullshit" to the test and see if either cynical bullshit or benign bullshit can be ascribed to the term "Web 2.0".  For better or worse, I am going to use Jeffrey Zeldman's blog on Web 2.0 (titled, confusingly enough, "Web 3.0") as the main text for this analysis.  Zeldman is generally sympathetic to the ideas and phenomena the "Web 2.0" is meant to encompass, but he also points out the aspects of the term that grate.  The most salient is the degree to which it smells like a sales pitch.

 

It soon appeared that “Web 2.0” was not only bigger than the Apocalypse but also more profitable. Profitable, that is, for investors like the speaker. Yet the new gold rush must not be confused with the dot-com bubble of the 1990s:

“Web 1.0 was not disruptive. You understand? Web 2.0 is totally disruptive. You know what XML is? You’ve heard about well-formedness? Okay. So anyway—”

And on it ran, like a dentist’s drill in the Gulag.

Zeldman associates Web 2.0 with marketing, which Frankfurt in turn associates with bullshit.  Frankfurt even goes so far as identifying sales and its related disciplines as "the most indisputable and classic paradigms of the concept."  Moreover, the defense that Web 2.0 describes a real phenomenon, as Fowler insists and Zeldman grants, doesn't make it not bullshit, since Frankfurt concedes that bullshit can just as well be true as false.  What is important is the authenticity or inauthenticity of the original claim, and the sense that something is a sales pitch is already an indication that something inauthentic is going on.  So "Web 2.0" certainly meets Frankfurt's criteria for bullshit.

The more important question is what kind of bullshit is it?  Is it benign, or cynical?  According to Frankfurt's distinction, again, the difference is whether the bullshit is grounded in the nature of one's work or rather in some sort of defect of epistemic character.

Here the answer is not so simple, I think, since software has two strands, one going to the hobbyist roots of programming, and the other to the monetizing potential of information technology.  Moreover, both strands tend to struggle within the heart of the software engineering industry, with the open source movement on the one hand (often cited as one key aspect of Web 2.0) emblematic of the purist strain, and the advertising prospects on the other (with Google in the vanguard, often cited as a key exemplar of the Web 2.0 phenomena) symbolic of the notion that a good idea isn't enough -- one also has to be able to sell one's ideas.

Software programming, in its origins, is a discipline practiced by nerds.  In other words, it is esoteric knowledge, extremely powerful, practiced by a few and generally misunderstood by the majority of people.  As long as there is no desire to explain the discipline to outsiders, there is no problem with treating software programming as a hobby.  At some point, however, every nerd wants to be appreciated by people who are not his peers, and to accomplish this, he is forced to explain himself and ultimately to sell himself.  The turning point for this event is well documented, and occurred on February 3rd, 1973, when Bill Gates wrote an open letter to the hobbyist community stating that software had economic value and that it was time for people to start paying for it. 

This was a moment of triumph for nerds everywhere, though this was not at first understood, and still generates resentment to this day, because it irrevocably transformed the nature of software programming.  Once software was recognized as something of economic value, it also became clear that software concepts now had to be marketed.  The people who buy software are typically unable to distinguish good software from bad software, and so it becomes the responsibility of those who can to try to explain why their software is better in terms that are not, essentially, technical.  Instead, a hybrid jargon-ridden set of terms had to be created in order to bridge the gap between software and the business appetite for software.  Software engineers, in turn, learned to see selling themselves, to consumers, to their managers, and finally to their peers, as part of the job of software engineering -- though at the same time, this forced obligation to sell themselves continues to be regarded with with suspicion and resentment.  The hope held out to such people is that through software they will eventually be able to make enough money, as Bill Gates did, as Steve Jobs did, to finally give up the necessity of selling themselves and return to a pure hobbyist state-of-mind once again.  They in effect want to be both the virgin and the whore.  This is, of course, a pipe dream.

Consequently, trying to determine whether Web 2.0 is benign bullshit or cynical bullshit is difficult, since sales both is and is not an authentic aspect of the work of software engineering.  What seems to be the case is that Web 2.0 is a hybrid of benign and cynical bullshit.  This schizophrenic character is captured in the notion of Web 2.0 itself, which is at the same time a sales pitch as well as an umbrella term for a set of contemporary cultural phenomena.

Now that we know what bullshit is, and we know that Web 2.0 is bullshit, it is time to evaluate what Web 2.0 is.  In Tim O'Reilly's original article that introduced the notion of Web 2.0, called appropriately What Is Web 2.0, O'Reilly suggests several key points that he sees as typical of the sorts of things going on over the past year at companies such as Google, Flikr, YouTube and Wikipedia.  These observations include such slogans as "Harnessing Collective Intelligence", "Data is the Next Intel Inside" and "End of the Software Release Cycle".  But it is worth asking if these really tell us what Web 2.0 is, or if they are simply ad hoc attempts to give examples of what O'Reilly says is a common phenomenon?  When one asks for the meaning of terms such as Web 2.0, what one really wants is the original purpose behind coining the term.  What is implicit in the term Web 2.0, as Heidegger would put it, that at the same time is concealed by the language typically used to explain Web 2.0.

As Zeldman points out, one key (and I think the main key) to understanding Web 2.0 is that it isn't Web 1.0.  The rise of the web was marked by a rise in bluff and marketing that created what we now look back on as the Internet Bubble.  The Internet Bubble, in turn, was a lot of marketing hype and the most remarkable stream of jargon used to build up a technology that, in the end, could not sustain the amount of expectation with which it was overloaded.  By 2005, this bad reputation that had accrued to the Web from the earlier mistakes had generated a cynicism about the new things coming along that really were worthwhile -- such as the blogging phenomenon, Ajax, Wikipedia, Google, Flikr and YouTube.  In order to overcome the cynicism, O'Reilly coined a term that, successfully, distracted people from the earlier debacle and helped to make the Internet a place to invest money once again.  Tim O'Reilly, even if his term is bullshit, as we have already demonstrated above, ultimately has done us all a service by clearing out all the previous bullshit.  In a very Heideggerian manner, he made a clearing [Lichtung] for the truth to appear.  He created, much as Heidegger attempted to do for Being, a conceptual space for new ideas about the Internet to make themselves apparent.

Or perhaps my analogy is overwrought. In any case, the question still remains as to what one does with terms that have outlived their usefulness.  In his introduction to Existentialism and Human Emotions, Jean-Paul Sartre describes the status the term "existentialism" has achieved by 1957.

Someone recently told me of a lady who, when she let slip a vulgar word in a moment of irritation, excused herself by saying, "I guess I'm becoming an existentialist."

...

Most people who use the word would be rather embarrassed if they had to explain it, since, now that the word is all the rage, even the work of a musician or painter is being called existentialist.  A gossip columnist in Clartes signs himself The Existentialist, so that by this time the word has been so stretched and has taken on so broad a meaning, that it no longer means anything at all.

 

Sartre spent most of the rest of his philosophical career refining and defending the term "existentialism," until finally it was superceded by post-structuralism in France. The term enjoyed a second life in America, until post-structuralism finally made the Atlantic crossing and superceded it there, also, only in turn to be first treated with skepticism, then with hostility, and finally as mere jargon.  It is only over time that an intellectual clearing can be made to re-examine these concepts.  In the meantime, taking a cue from Wittgenstein, we are obliged to remain silent over them.

Posted by James Ashley Thursday, December 21, 2006 5:44:33 PM (Eastern Standard Time, UTC-05:00) #    Comments [1]
 del.icio.us | DiggThis

 

Long Dark Night of the Compiler#

In his book on the development the C++ language, The Design and Evolution of C++, Bjarne Stroustrup says that in creating C++ he was influenced by the writings of Søren Kierkegaard.  He goes into some detail about it in this recent interview:

 

A lot of thinking about software development is focused on the group, the team, the company. This is often done to the point where the individual is completely submerged in corporate "culture" with no outlet for unique talents and skills. Corporate practices can be directly hostile to individuals with exceptional skills and initiative in technical matters. I consider such management of technical people cruel and wasteful. Kierkegaard was a strong proponent for the individual against "the crowd" and has some serious discussion of the importance of aesthetics and ethical behavior. I couldn't point to a specific language feature and say, "See, there's the influence of the nineteenth-century philosopher," but he is one of the roots of my reluctance to eliminate "expert level" features, to abolish "misuses," and to limit features to support only uses that I know to be useful. I'm not particularly fond of Kierkegaard's religious philosophy, though.

 

Stroustrup is likely referring to philosophical observations such as this:

 

Truth always rests with the minority, and the minority is always stronger than the majority, because the minority is generally formed by those who really have an opinion, while the strength of a majority is illusory, formed by the gangs who have no opinion--and who, therefore, in the next instant (when it is evident that the minority is the stronger) assume its opinion . . . while Truth again reverts to a new minority.

-- Søren Kierkegaard

 

Coincidentally, Kierkegaard and Pascal are often cited as the fathers of modern existentialism, and where Kierkegaard appears to have influenced the development of C++, Pascal's name lives on in the Pascal programming language as well as the Pascal case, used as a stylistic device in most modern languages.  The Pascal language, in turn, was contemporary with the C language, which was the syntactic precursor to C++.

So just as the Catholic Church holds that guardian angels guide and watch over individuals, cities and nations, might it not also be the case that specific philosophers watch over different programming languages?  Perhaps a pragmatic philosopher like C. S. Peirce would watch over Visual Basic.  A philosopher fond of architectonics, like Kant, would watch over Eiffel.  John Dewey could watch over Java, while Hegel, naturally, would watch over Ruby.

Posted by James Ashley Tuesday, December 05, 2006 11:23:08 AM (Eastern Standard Time, UTC-05:00) #    Comments [2]
 del.icio.us | DiggThis

 

Converting to ASP.NET Ajax Beta 2 (A Guide for the Perplexed)#
There are a few good guides already on the internet that provide an overview of what is required to convert your Atlas CTP projects to Ajax Extensions. This guide is intended to consolidate some of the advice already provided, as well as offer a few pointers alluded to by others but not explained. In other words, this is the guide I wish I had before I began my own conversion project.
Posted by James Ashley Friday, November 17, 2006 5:28:37 PM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

V. ASP.NET Ajax Imperative Dropzones#
To create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior...
Posted by James Ashley Friday, November 17, 2006 12:36:11 PM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

IV. ASP.NET Ajax Declarative Dropzones#
Being able to drag html elements around a page and have them stay where you leave them is visually interesting. To make this behavior truly useful, though, an event should be thrown when the drop occurs. Furthermore, the event that is thrown should depend on where the drop occurs. In other words, there needs to be behavior that can be added to a given html element that will turn it into a "dropzone" or a "drop target", the same way that the floating behavior can be added to an html div tag to turn it into a drag and drop element. In the following examples, I will show how Atlas supports the concept of dropzones.
Posted by James Ashley Friday, November 17, 2006 12:14:45 PM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

III. ASP.NET Ajax Dynamic Drag and Drop#
Since the declarative model is much cleaner than the imperative model, why would you ever want to write your own javascript to handle Ajax Extensions behaviors? You might want to roll your own javascript if you want to add behaviors dynamically. One limitation of the declarative model is that you can only work with objects that are initially on the page. If you start adding objects to the page dynamically, you cannot add the floating behavior to them using the declarative model. With the imperative model, on the other hand, you can.
Posted by James Ashley Friday, November 17, 2006 11:56:44 AM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

II. ASP.NET Ajax Imperative Drag and Drop#
To accomplish the same thing using a programmatic model requires a bit more code, but not much more. It is important to understand that when you add an Ajax Extensions Script Manager component to your page, you are actually giving instructions to have the Ajax Extensions javascript library loaded into your page. The Ajax Extensions library, among other things, provides client-side classes that extend the DOM and provide you with tools that allow you to code in a browser agnostic manner (though there currently are still issues with Safari compatibility). These client-side classes also allow you to add behaviors to your html elements.
Posted by James Ashley Friday, November 17, 2006 11:48:53 AM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

I. ASP.NET Ajax Declarative Drag and Drop#
The first task is to use XML markup to add drag-drop behavior to a div tag. By drag and drop, I just mean the ability to drag an object and the have it stay wherever you place it. The more complicated behavior of making an object actually do something when it is dropped on a specified drop target will be addressed later in this tutorial.
Posted by James Ashley Friday, November 17, 2006 11:39:09 AM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

Microsoft ASP.NET Ajax Drag and Drop Tutorial#
The hardworking Atlas/Ajax team has greatly improved the architecture of the Ajax Extensions framework with the Beta 2, making it much more rational and easy to use for future adopters. Sadly, for us early adopters, this also meant a large number of breaking changes and a bit of a struggle trying to figure out the new paradigms for programming ASP.Net. At this point in time, the documentation hasn't yet caught up with the innovation, and so the best place to look for reliable information about how to use ASP.Net is to go the professional blogs of the various Microsoft developers: Bertrand LeRoy, Eilon Lipton, Scott Guthrie. The blog of Miljan Braticevic of Component Art was also extremely helpful.
Posted by James Ashley Friday, November 17, 2006 11:21:56 AM (Eastern Standard Time, UTC-05:00) #    Comments [0]
 del.icio.us | DiggThis

 

Technological Similes (e.g., Ajax is like...)#

 As mentioned in a previous post, programmers typically explain one technology by referencing another more familiar technology.  What sometimes happens, however, is that the technology that was thought to be more familiar, and consequently believed to have explanatory power, in fact was simply originally explained by referencing some third vaguely understood technology; but time made the simile comfortable and vanity made it acceptable.  We only become aware of the semantic web we programmers weave when we are finally forced to use one of the referenced technologies and discover, once again, what a strange and incomprehensible thing programming is.  The experience is a bit like the shock felt by the woman who brought home a stray dog from Paris only to discover that it was really a large tailless rat.

To find out what one of the trendier new technologies is really like, I recently consulted Google.  A google search on "Ajax is like..." turns up the following results:

"Comparing Java and AJAX is like comparing apples and blue."

"[U]sing Ajax is like consuming alcohol in public."

"[A]jax is like instant messaging...."

"Customers asking for AJAX is like a prospective homeowner walking over to the contractors hired to do the building and handing them a saw."

"AJAX is like Flash or HTML."

"AJAX is like a javascript."

"AJAX is like Javascript on steroids."

"AJAX is like web services."

"[A]jax is like everything else on line, it will be abused by various low lifes."

"Ajax is like to partial update in Intraweb I am wrong?"

"Ajax is like 'roller skates for the web.'"

"Ajax is like shell, Perl, Ruby. Ajax is like UNIX."

"AJAX is like a Hooker turn School Teacher, it has a dirty secret and unless you get it alone and play with it, you won't pickup on it's secrets until it's too late."

"Ajax is, like stated in the essay, a new way to think about user interfaces on the web...."

"AJAX is like wearing 70's djeans with an Hugo Boss Shoes...."

"AJAX is like Dinosaur cloning in Jurassic park."

"AJAX is like folding a web page origami-style into a Lego brick...."

"AJAX is like a house of cards, and when a browser vendor screws up on a revision it'll all come tumbling down."

"AJAX is like putting a tiny bandage on a gaping wound the size of a grapefruit."

"Ajax is like DHTML was 4 years ago, like javascript was 6 years ago, like applets were 8 years ago."

"AJAX is like the killer buzzword."

Posted by James Ashley Wednesday, October 25, 2006 12:32:44 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

IE7 CSS Rendering Problem for DasBlog Project84 Theme#

This site uses DasBlog as it's blogging engine.  One of the themes that comes with DasBlog, Project84, has a rendering problem in IE7 that causes the footer to bleed into the main page somewhere a few inches from the top, when it should, of course, display at the bottom of the page.

The problem turns out to be only one line in the style.css file:

html, body{height:100%;}

Comment this out and the page should render correctly.  This also affects the Project84Green theme.

I viewed the corrected style in Firefox 1.5, IE6 and IE7 and did not note any issues. 

Posted by James Ashley Sunday, October 22, 2006 8:08:16 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Metaphors and Software Development#
"But the greatest thing by far is to have a mastery of metaphor. This alone cannot be imparted by another; it is the mark of genius, for to make good metaphors implies an eye for resemblances."  -- Aristotle, The Poetics

 

It is a trivial observation that software programmers use a lot of metaphors.  All professions are obliged to invoke metaphors in one way or another, but in software programming I think the program is so extensive that we are not even aware of the fact that creating metaphors is our primary job.  We are only ever immediately aware of the metaphorical character of our profession when we use similes to explain technical matters to our managers.  Such-and-such technology will improve our revenue stream because it is like a new and more reliable conduit for information. It can be combined with sundry-and-other technology, which acts as a locked box for this information.

When speaking with technical colleagues, in turn, we use a different set of metaphors when explaining unfamiliar technology.  We say that "Ajax is like Flash", "Flash is like instant messaging", "instant messaging is like talking to services in a SOA", "SOA is like mainframe programming", b is like c, c is like d, d is like e, and so on.  Every technology is explained in reference to another technology, which in turn is just a metaphor for something else.  But does explicating one metaphor by simply referencing another metaphor really explain anything?  Is there a final link in the chain that ultimately cascades meaning back up the referential chain?

I have occasionally seen these referential chains referred to as a prison house of language, though perhaps a house of mirrors would be more appropriate in this case.  We work with very complex concepts, and the only way to communicate them is through metaphors, even when, as in a fun house, the only points of reference we have for explaining these concepts are other concepts we find reflected in a reflection of a reflection.  This metaphorical character of our occupation, however, is typically hidden from us because we use a different set of terms to describe what we do.  We don't typically speak about metaphors in our programming talk; instead we speak of abstractions.

Not only are abstractions explained in terms of other abstractions, but they are also typically abstractions for other abstractions.  In Joel Spolsky's explication of "Leaky Abstractions" (which is, yes, also a metaphor) we discover that TCP is really an abstraction thrown over IP.  But IP is itself an abstraction of other technologies, which in turn may in themselves also involve further abstractions.  At what point do the abstractions actually end?  Is it when we get to the assembler language level?  Is it when we get to machine language?  Do we finally hit bottom when we reach the point of talking about electricity and circuit boards?

Again, I will posit (in a handwaving and unsubstantiated manner) that the main occupation of a software programmer is working with metaphors.  Taking this as a starting point, it is strange that in the many articles and discussion threads addressing the question, what makes a good programmer?, poetry is never brought up. Overlooking Aristotle's professed opinion that a gift for metaphor is something that cannot be taught, we might assume that if it is indeed something that can be cultivated, a likely starting point is through the reading and writing of poetry.  It would be a pleasant change if in looking over technical resumes, we also starting looking for signs that prospective employees to BigTech.com also were published in poetry journals or participated in local poetry readings.

But perhaps that is asking for too much.  The only other profession in which metaphors are applied extensively is in politics.  Just as metaphors are called abstractions in programming, in politics they are called "framing".  Behind the notion of framing in politics is the assumption that certain metaphors are simply more naturally appealing than others.  The proper metaphor will motivate one's audiences emotions either toward one's platform or against one's opponents platform.  The mastery of metaphor in politics, consequently, entails being able to associate one's own position with the most emotively powerful metaphor into which one can fit one's position. 

One interesting aspect of the endeavor of framing is that a political metaphor is required to be fitting, that is the metaphor one uses to explain a given position or argument must be appropriate to that argument, and an absence of fitting will generally detract from the force of the metaphor.  That there is this question of fittingness provides two ways to characterize political metaphors.  There are metaphors that seem to naturally apply to a given circumstance, and hence garner for the person who comes up with such metaphors a reputation for vision and articulateness.  Then there are metaphors that are so powerful that it does not matter so much that the circumstance to which it is applied is not so fitting, in which case the person who comes up with such metaphors gains a reputation as a scheming framer.

Determining which is which, of course, generally depends on where one is standing, and in either case we can say that both are masters of metaphor in Aristotle's sense.  However, because there is so much question about the integrity of metaphors in politics, it is tempting to eschew the whole thing.  As wonderful as metaphors are, politics tends to make everything dirty in the end.

Which leaves software programming as the only place where metaphors can be studied and applied in a disinterested manner.  In programming, the main purpose of our abstractions is not to move people's emotions, but rather to clarify concepts, spread comprehension and make things work better.  It is the natural home not only for mathematicians, but for poets.

Posted by James Ashley Wednesday, October 18, 2006 1:38:27 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

V. Imperative Dropzones#

 

To create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior:

function addDropZoneBehavior(ctrl){
    var dropZone = new Sys.UI.Control(ctrl);
    var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
    dropZone.get_behaviors().add(dropZoneBehavior);
    dropZoneBehavior.initialize();
}

To finish hooking everything up, call this addDropZoneBehavior function from the Atlas pageLoad() method, as you did in earlier examples for the addFloatingBehavior function. This will attach the proper behaviors to their respective HTML elements and replicate the drag and dropzone functionality you created above using declarative markup. If you want to make this work dynamically, just add the createDraggableDiv() function you already wrote for the previous dynamic example. As a point of reference, here is the complete code for creating programmatic dropzones:

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Imperative Drop Targets</title>
<script type="text/javascript">
    function addFloatingBehavior(ctrl, ctrlHandle){
        var floatingBehavior = new Sys.UI.FloatingBehavior();
        floatingBehavior.set_handle(ctrlHandle);
        var dragItem = new Sys.UI.Control(ctrl);
        dragItem.get_behaviors().add(floatingBehavior);
        floatingBehavior.initialize();
    }
    function addDropZoneBehavior(ctrl){
        var dropZone = new Sys.UI.Control(ctrl);
        var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
        dropZone.get_behaviors().add(dropZoneBehavior);
        dropZoneBehavior.initialize();
    }
 
    function pageLoad(){
        addDropZoneBehavior($('dropZone'));
        addFloatingBehavior($('draggableDiv'),$('handleBar')); 
    }
</script>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
<atlas:ScriptReference Path="scriptLibrary/DropZoneBehavior.js" />
</Scripts>
</atlas:ScriptManager>
<h2>Imperative Drop Targets with javacript</h2> 
<div style="background-color:Red;height:200px;width:200px;">
    <div id="draggableDiv" 
         style="height:100px;width:100px;background-color:Blue;">
        <div id="handleBar" 
             style="height:20px;width:auto;background-color:Green;">
        </div>
    </div>
</div>
<div id="dropZone" style="background-color:cornflowerblue;
              height:200px;width:200px;">Drop Zone</div>
</form>
</body>
</html>
 

Conclusion

Besides the dropzone behavior, you may want to also write your own floating behavior. For instance, by default, elements decorated with the floating behavior simply stay where you drop them. You may want to extend this so that your floating div will snap back to its original location when you drop it outside of a drop zone. Additionally, you may want to change the way the dragged element looks while you are dragging it, either by making it transparent, changing its color, or replacing the drag image altogether. All this can be accomplished by creating a behavior that implements the IDragSource interface in the same way you created a custom class that implements the IDropTarget interface.

This tutorial should provide you with a starting point for extending the basic drag drop functionality provided with Atlas, to create your own behaviors and provide your own functionality. The next step is to build on this to create controls. Using this tutorial as a starting point, you can go on to create Atlas extender controls that implement your behaviors using declarative markup, or even turn around and create server-side controls that automatically create HTML elements with Atlas behaviors, with the choice being, once again, one between creating server-side controls that are either declarative, and consequently static, or imperative, and consequently slightly more complex but also more flexible. This is a topic that is much too large for the current tutorial; however, I hope that in the near future, someone will try to do for server-side Atlas programming what this tutorial attempts to do for client-side Atlas scripting.

Posted by James Ashley Wednesday, October 18, 2006 8:57:50 AM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

IV. Declarative Dropzones#

 

Being able to drag HTML elements around a page and have them stay where you leave them is visually interesting. To make this behavior truly useful, though, an event should be thrown when the drop occurs. Furthermore, the event that is thrown should depend on where the drop occurs. In other words, there needs to be behavior that can be added to a given HTML element that will turn it into a "dropzone" or a "drop target", the same way that the floating behavior can be added to an HTML div tag to turn it into a drag and drop element.

In the following examples, I will show how Atlas supports the concept of dropzones. In its current state, Atlas does not support an out-of-the-box behavior for creating dropzone elements in quite the same way it does for floating elements. It does, however, implement behaviors for a DragDropList element and a DraggableListItem element which, when used together, allow you to create lists that can be reordered by dragging and dropping. If you would like to explore this functionality some more, there are several good examples of using the DragDropList behavior on the web, for instance, Introduction to Drag And Drop with Atlas.

The main disadvantage of the dragdropzone behavior is that it only works with items that have been decorated with the DragDropList behavior. The functionality that this puts at your disposal is fairly specific. To get the sort of open-ended dropzone functionality I described above, that will also work with the predefined floating behavior, you will need to write your own dropzone behavior class in JavaScript. Fortunately, this is not all that hard.

Atlas adds several OOP extensions to JavaScript in order to make it more powerful, extensions such as namespaces, abstract classes, and interfaces. You will take advantage of these in coding up your own dropzone behavior. If you peer behind the curtain and look at the source code in the AtlasUIDragDrop.js file, (you can do this with the Visual Studio debugger), you will find several interfaces defined there, including one for Sys.UI.DragSource and one for Sys.UI.DropTarget. In fact, both the FloatingBehavior class and the DraggableListItem class implement the Sys.UI.DragSource interface, while Sys.UI.DropTarget is implemented by the DragDropList class. The code for these two interfaces looks like this:

Sys.UI.IDragSource = function() {
    this.get_dataType = Function.abstractMethod;
    this.get_data = Function.abstractMethod;
    this.get_dragMode = Function.abstractMethod;
    this.onDragStart = Function.abstractMethod;
    this.onDrag = Function.abstractMethod;
    this.onDragEnd = Function.abstractMethod;
}
Sys.UI.IDragSource.registerInterface('Sys.UI.IDragSource');
Sys.UI.IDropTarget = function() {
    this.get_dropTargetElement = Function.abstractMethod;
    this.canDrop = Function.abstractMethod;
    this.drop = Function.abstractMethod;
    this.onDragEnterTarget = Function.abstractMethod;
    this.onDragLeaveTarget = Function.abstractMethod;
    this.onDragInTarget = Function.abstractMethod;
}
Sys.UI.IDropTarget.registerInterface('Sys.UI.IDropTarget');

Why do you need to implement these interfaces instead of simply writing out brand new classes to support drag, drop, and dropzones? The secret is that, behind the scenes, a third class, called the DragDropManager, is actually coordinating the interactions between the draggable elements and the dropzone elements, and it only knows how to work with classes that implement the IDragSource or the IDropTarget. The DragDropManager class registers which dropzones are legitimate targets for each draggable element, handles the MouseOver events to determine when a dropzone has a draggable element over it, and a hundred other things you do not want to do yourself. In fact, it does it so well that the dropzone behavior you are about to write is pretty minimal. First, create a new JavaScript file called DropZoneBehavior.js. I placed my JavaScript file under a subdirectory called scriptLibrary, but this is not necessary in order to make the dropzone behavior work. Next, copy the following code into your file:

Type.registerNamespace('Custom.UI');

Custom.UI.DropZoneBehavior = function() {

    Custom.UI.DropZoneBehavior.initializeBase(this);
    this.initialize = function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, 'initialize');
        // Register ourselves as a drop target.
        Sys.UI.DragDropManager.registerDropTarget(this); 
    }
    this.dispose = function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, 'dispose');
    }
    this.getDescriptor = function() {
        var td = Custom.UI.DropZoneBehavior.callBaseMethod(this, 'getDescriptor');
        return td;
    } 

    // IDropTarget members.
    this.get_dropTargetElement = function() {
        return this.control.element;
    }
    this.drop = function(dragMode, type, data) { 
        alert('dropped');
    }
    this.canDrop = function(dragMode, dataType) {
        return true;
    }
    this.onDragEnterTarget = function(dragMode, type, data) {
    }
    this.onDragLeaveTarget = function(dragMode, type, data) {
    }
    this.onDragInTarget = function(dragMode, type, data) {
    }
}
Custom.UI.DropZoneBehavior.registerClass('Custom.UI.DropZoneBehavior', 
       Sys.UI.Behavior, Sys.UI.IDragSource, 
       Sys.UI.IDropTarget, Sys.IDisposable);
Sys.TypeDescriptor.addType('script', 'DropZoneBehavior', 
                           Custom.UI.DropZoneBehavior);

I need to explain this class a bit backwards. The first thing worth noticing is the second to last line that begins with "Custom.UI.DropZoneBehavior.registerClass". This is where the dropZoneBehaviorClass defined above gets registered with Atlas. The first parameter of the registerClass method takes the name of the class. The second parameter takes the base class. The remaining parameters take the interfaces that are implemented by the new class. The line following this makes your class available for declarative markup scripting. Now back to the top, the "Type.registerNamespace" method allows you to register your custom namespace. The next line declares our new class using an anonymous method syntax. This is a way of writing JavaScript that I am not particularly familiar with, but is very important for making JavaScript object oriented, and is essential for designing Atlas behaviors. Within the anonymous method, the class methods Initialize, Dispose, and getDescriptor are simply standard methods used for all behavior classes, and in this implementation, all you need to do is call the base method (that is, the method of the base class that you specify in the second to last line of this code sample.) The only thing special you do is to register the drop target with the Sys.UI.DragDropManager in the Initialize method. This is the act that makes much of the drag drop magic happen.

Next, you implement the IDropTarget methods. In this example, you are only implementing two methods, "this.canDrop" and "this.drop". For "canDrop", you are just going to return true. More interesting logic can be placed here to determine which floating div tags can actually be dropped on a given target, and even to determine what sorts of floating divs will do what when they are dropped; but in this case, you only want a bare-bones implementation of IDropTarget that will allow any floating div to be dropped on it. Your implementation of the "drop" method is similarly bare bones. When a floating element is dropped on one of your drop targets, an alert message will be thrown indicating that something has occurred. And that's about it. You now have a drop behavior that works with the floating behavior we used in the previous examples.

You should now write up a page to show off your new custom dropzone behavior. You can build on the previous samples to accomplish this. In the Atlas Script Manager, besides registering the AtlasUIDragDrop script, you will also want to register your new DropZoneBehavior script:

<atlas:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
        <atlas:ScriptReference Path="scriptLibrary/DropZoneBehavior.js" />
    </Scripts>
</atlas:ScriptManager>

Next, you will want to add a new div tag to the HTML body, that can be used as a drop target:

<div style="background-color:Red;height:200px;width:200px;">
    <div id="draggableDiv" style="height:100px;width:100px;background-color:Blue;">
        <div id="handleBar" style="height:20px;width:auto;background-color:Green;">
        </div>
    </div>
</div>

<div id="dropZone" style="background-color:cornflowerblue;height:200px;width:200px;">
    Drop Zone
</div>

Finally, you need to add a declarative markup element to add your custom DropZone behavior to the div you plan to use as a dropzone element. The XML markup should look like this:

<script type="text/xml-script">
    <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
        <components>
            <control id="dropZone">
                <behaviors>
                    <DropZoneBehavior/>
                </behaviors>
            </control>
            <control id="draggableDiv">
                <behaviors>
                    <floatingBehavior handle="handleBar"/>
                </behaviors>
            </control>
        </components>
    </page>
</script>

The code you have just written should basically add a dropzone to the original declarative drag and drop example. When you drop your drag element on the dropzone, an alert message should appear. You can expand on this code to make the drop method of your custom dropzone behavior do much more interesting things, such as firing off other JavaScript events in the current page, or even calling a webservice, using Atlas, that will in turn process server-side code for you.

Posted by James Ashley Tuesday, October 17, 2006 10:15:26 AM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

III. Dynamic Drag Drop#

 

Since the declarative model is much cleaner than the imperative model, why would you ever want to write your own JavaScript to handle Atlas behaviors? You might want to roll your own JavaScript if you want to add behaviors dynamically. One limitation of the declarative model is that you can only work with objects that are initially on the page. If you start adding objects to the page dynamically, you cannot add the floating behavior to them using the declarative model. With the imperative model, on the other hand, you can.

Building on the previous example, you will replace the "pageLoad()" function with a function that creates floating divs on demand. The following JavaScript function will create a div tag with another div tag embedded to use as a handlebar, then insert the div tag into the current page, and finally add floating behavior to the div tag:

function createDraggableDiv() {
    var panel= document.createElement("div");
    panel.style.height="100px";
    panel.style.width="100px";
    panel.style.backgroundColor="Blue";
    var panelHandle = document.createElement("div");
    panelHandle.style.height="20px";
    panelHandle.style.width="auto";
    panelHandle.style.backgroundColor="Green";
    panel.appendChild(panelHandle);
    var target = $('containerDiv').appendChild(panel);
    addFloatingBehavior(panel, panelHandle);
}

You will then just need to add a button to the page that calls the "createDraggableDiv()" function. The new HTML body should look something like this:

<input type="button" value="Add Floating Div" onclick="createDraggableDiv();" />
<div id="containerDiv" style="background-color:Purple;height:800px;width:600px;"/>

This will allow you to add as many draggable elements to your page as you like, thus demonstrating the power and flexibility available to you once you understand the relationship between using Atlas declaratively and using it programmatically. As a point of reference, here is the complete code for the dynamic drag and drop example:

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Imperative Drag and Drop II</title>
<script type="text/javascript">
    function createDraggableDiv() {
        var panel= document.createElement("div");
        panel.style.height="100px";
        panel.style.width="100px";
        panel.style.backgroundColor="Blue";
        var panelHandle = document.createElement("div");
        panelHandle.style.height="20px";
        panelHandle.style.width="auto";
        panelHandle.style.backgroundColor="Green";
        panel.appendChild(panelHandle);
        var target = $('containerDiv').appendChild(panel);
        addFloatingBehavior(panel, panelHandle);
    }
    function addFloatingBehavior(ctrl, ctrlHandle){
        var floatingBehavior = new Sys.UI.FloatingBehavior();
        floatingBehavior.set_handle(ctrlHandle);
        var dragItem = new Sys.UI.Control(ctrl);
        dragItem.get_behaviors().add(floatingBehavior);
        floatingBehavior.initialize();
    }
</script>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
    </Scripts>
</atlas:ScriptManager>
<h2>Imperative Drag and Drop Code with javascript: 
            demonstrate dynamic loading of behaviors</h2>
<input type="button" value="Add Floating Div" onclick="createDraggableDiv();" />
<div id="containerDiv" style="background-color:Purple;height:800px;width:600px;"/>
</form>
</body>
</html>
Posted by James Ashley Monday, October 16, 2006 10:44:35 AM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

Microsoft Atlas Drag and Drop Tutorial#

Source Code: AtlasDragNDrop.zip (467.5 KB)

Preface

I'm not sure if this explanation belongs in the preface or in the introduction, or what the exact difference is between the two.  In any case, this purpose of this preface is to explain why this tutorial is here.  I wrote it originally for a different site, codeproject.com, to which I have since lost my password.  At the same time, the underlying Atlas framework, upon which this tutorial is based and for which it is written, has gone through several iterations, thus obligating me to update this tutorial to make sure it is still valid.  So I've placed it here, in an easily accessible location, where I can quickly edit the text of this tutorial for as long as I can remember the password.  Who knows, should I find myself short of material again, I may start posting my journal article on Vico, grad school essays, and so on...

Introduction

This tutorial is intended to help readers understand how certain aspects of Microsoft's new Atlas technology works. Atlas is intended to simplify the development of AJAX-style functionality. As with all technologies, however, to use a tool well, it is important to understand the underlying technology that Atlas abstracts. One of the key Atlas abstractions is the new XML markup syntax developed to make coding with Atlas easier. With XML markup, developers can modify their code declaratively. However, there are times when a developer may want to be able to change her code programmatically, and in order to accomplish this, she will need to understand that underneath the markup abstraction, she is actually dealing with good 'ol JavaScript and some custom JavaScript libraries developed by Microsoft. In order to demonstrate the relationship between the Atlas declarative model and the programmatic model, I will go through a series of examples in which the same task will be accomplished both declaratively and programmatically. I will be demonstrating how to use the AtlasUIDragDrop library file to perform basic drag-drop operations as well as set up drop zones.

Background

As I write this, Atlas is still in beta, and continues to change. These examples apply to the April CTP of Atlas. Newer releases of Atlas may affect the accuracy of this tutorial. I will attempt to update the code as new versions of Atlas become available. Atlas only works with .NET 2.0.

Posted by James Ashley Friday, October 13, 2006 3:37:07 PM (Eastern Daylight Time, UTC-04:00) #    Comments [0]
 del.icio.us | DiggThis

 

All content © 2010, James Ashley
On This Page
Calendar
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
Blogroll
Archives
Tag Cloud
Disclaimer

Powered by: newtelligence dasBlog 2.2.8279.16125

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme based on design by Jelle Druyts