Measuring ROI – Moving from Cost Center To Strategic Partner

MoneymanI ran across this article on ZDNet (Wanted: ROI for internal app development)  that really worried me. My friends at PreEmptive Solutions ran a survey across a wide number of developers that included people from 21 different industry segments in 33 countries asking about how the company measure the ROI of an application that they are building. The terrifying part is that the survey found that 58% of companies don’t bother measuring ROI on their internal applications and the majority of the ones that do measure don’t do so in a consistent and proven way.

This means that you are almost positively throwing away time and effort and therefore money. For some crazy reason, companies don’t like that.

image

Of all of the companies surveyed, only 6% have a consistent and reliable approach to measuring ROI. That terrifies me.

What are your Goals?

For a long time I’ve been preaching that IT needs to become a strategic partner to the business.

The issue is that most IT departments are considered cost centers. This means that they are the first to be cut when times get tough, they are the least invested in, they are the last at the table to be heard and they are pushed around by all of the other departments. This is not a good position to be in. This is why a lot of companies look to outsource IT. Since they don’t see it as a strategic asset and partner it doesn’t matter if they keep it close.

The way to move from cost center to strategic partner is to start showing value and to start pushing the edge on ideas that will drive a great ROI for the business.

But, if you’re not measuring the ROI, how can you talk to the business about the possible ROI?

Explaining the numbers...And every time that someone asks me how to sell their management on usability studies or spending any time on a UI, I tell them to go to the numbers.

And every time someone asks me how to sell their management on buying a given tool, I tell them to go to the numbers.

And every time someone asks me how to sell their management on training, I tell them to go to the numbers.

And every time someone asks me how to sell their management on anything at all, I tell them to go to the numbers.

ROI really it comes down to a simple question. How much money did the business make or save based on their investment in the software that they just paid to have developed?

There are two ways businesses think about investments. ROI, the first, is the percentage of return over a given period of time. Payback, the second, very closely related to ROI but very importantly different, is the length of time that it takes to recoup the investment. The reason that payback is important is because once you hit the payback point everything else is profit.

image I borrowed the graphic to the left from Paul Sheriff’s article called The Business Value of .NET.

An overly simplistic example is as follows. Let’s say a company wants to build a new online e-commerce site. If it takes 4 developers whose salaries are each $100,000.00 working for 3 months on a project with tools that they already own and so on. That means that it cost $100,000.00 to build. If the new site generates an average of an additional $15,000.00 a month for the first year, the gross profit is $180,000.00 with a net of $80,000.00.

We look at that as $80,000.00. That’s a good thing. However, there are two ways that the business is going to look at this example. The ROI is 180% and the payback is 6.6 months. Now, if the business sees an investment in another department that could yield a higher percentage or lower payback, that department is more likely to get the investment.

This is not a new problem. Back in 1999, Bill Gates wrote

image“When I sit down with developers to review product specifications, or with Microsoft’s product divisions to review their three-year business plans, or with our sales groups to review their financial performance, we work through the difficult issues. We discuss feature tradeoffs vs. time to market, marketing spend vs. revenue, head count vs. return and so on. Through human intelligence and collaboration, we transform static sales, customer, and demographic data into the design of a product or a program.”
Business @ the Speed of Thought : Using a Digital Nervous System
By: Bill Gates

Whether you are selling software or building internal applications, you need to go through the same process.

 

There are two basic ways to increase ROI, produce things cheaper or provide more value.

How did it cost to develop the software?

Money fightThe problem is that this includes more than just the developer’s salary. This includes how much were the machines, rent for the building they were in, telecom costs, training costs, their secretaries, management, consultants, tools, components that they bought and more.

You can keep costs down in a tremendous number of different ways.

Understanding what you’re building – There are many different types of processes that are out there that are more or less efficient depending on the team, project and a whole lot of different requirements. There are a handful of absolutes.

image The first is that you need to know that you’re building. You can accomplish this through solid requirements analysis.

Martin Shoemaker makes An Argument for Requirements Analysts where he points out research done by Boehm and published in Software Cost Estimation with COCOMO II found that “Excellent requirements analysts can reduce a project’s schedule by almost 30%, while inadequate analysis can increase the schedule by over 40%.”.

image David Platt has been talking about this same problem for years as “Why Software Sucks”. He’s been on ArCast twice, once with Ron Jacobs and once again with Bob Familiar. And he’s got a book on the topic called Why Software Sucks…and What You Can Do About It

Before you freak out, this does not mean Waterfall. This means that you understand what you’re going to be building and have a good grasp on the requirements. You’re going to make different web framework decisions if you have to scale to 10 users verses scaling to a million users. You’re going to make different input type decisions if your users are working outside and likely to be wearing gloves. You’re going to make different data locale choices if your user is going to be sitting in the corporate office next to the data center verses sitting in India or somewhere.

image With the Unified Modeling Language (UML), which can be leveraged with almost any process, requirements are captured in Use Case Diagrams. Check out Martin Shoemaker‘s UML Applied for a light weight process he calls 5 step UML.

In Extreme Programming, one of the Agile methodologies, these requirements are captured in User Stories. Regardless of your process, there is a way to do requirements analysis and it’s absolute that you have to do it.

Another absolute when it comes to process is that you need to have some form of user acceptance. A huge issue with most waterfall methodologies is that they push this user acceptance to the end of the project. At this point in time, the cost of fixing issues that the user finds with the software is prohibitively expensive. This is why Agile methodologies have the user involved in the project the whole way through and get smaller bits of functionality in front of the user earlier and more often. Course corrections along the way are a lot less costly than reversing and undoing months of work.

Buying a component or application – Building software is expensive. Going shopping againMost of the time, it’s cheaper to acquire something than to write it yourself. The question is, how close is the component or application to what you needed and how much customization do you need? Many people have heard me talk about “Buy, Rent or Generate”. If it’s not adding to your business’ bottom line, why are you spending the time and energy to build up the intellectual property yourself?

Think about a control suite such as NetAdvantage for WPF from Infragistics. It’s a $995.00 price tag. At first glance that’s a lot of money but how long would it take for you to write a control such as their xamChart that does 2D and 3D charting? A month? Two? Let’s be overly optimistic and confident like all of us technical folk are and say a week. If you’re making $50,000.00 a year, you just broke even if you actually hit the ridiculously tight deadline (technically you still lost because of all of the other factors that go into the cost of supporting you as a developer but for the moment, let’s pretend that you broke even…). What about support or feature enhancements?

The question you have to answer is does building the control, component, application yourself worth more to the company than buying it? What’s the (you should have seen this coming) Return on Investment?

With any of type of components or applications, you have to look at the full cost however. Often you’ll find that the licensing cost is a small part of the overall acquisition. How long does it take to integrate with the rest of your application? How much modification does it require? How much maintenance does it require? Whether it’s free (as in beer – i.e. no licensing fees) or not, there’s a cost associated. People who charge money for their software, open source or not, are betting on the fact that the cost of acquisition is going to be lower than you building it yourself. Sometimes they’re right, sometimes they’re wrong.

More efficient tools – The more efficient you are with your tools, the less time it will take for you to get features and functionality in front of the business.

Right tool for the job...For example, if you start leveraging CodeRush and/Or Resharper on top of Visual Studio, it will save you a lot of time. Or if you are leveraging tools that cut down on the amount of time you spend reporting or anything else you are saving time.

Again, pull out the numbers. If you can prove that you’ll have a 5 minute a day savings in time by leveraging CodeRush for example you might have a good case. At $50,000.00 a year / 2080 paid hours per year = about $24 an hour and a savings of 5 minutes * work days (with two weeks of vacation) is a savings of 900 minutes or 15 hour which equals $360.00. This means that at a price tag of $249.00, the ROI is 144% with a payback of 8.3 months.

The same type exercise applies if you are looking at buying a source control management system, bug tracking system or any other set of tools such as VSTS and Team System. In fact, there’s a whole lot of case studies that lay out the ROI of VSTS and Team Suite.

Not building a feature – The cheapest feature is the one that you don’t build in the first place. The When it would have been better with a planquestion is, how do you know which features you need to build in the first place? First and foremost, you need to understand the user. This is accomplished by doing user research. Next you need to, going back to my first point, do solid requirements analysis so that you know what you are supposed to build. And most importantly, you need to look at partnering with the business to build out the application. This is a core tenet all of the Agile methodologies. This means that you’re going to be building only the features that the folks on the business side want, not the features that you think that they need.

The second question here is after you build a feature, do you measure to see if the users are actually using a given feature? In other words, if you spent X amount of time and energy building out a specific set of functionality, how do you know that the business is actually realizing the potential return? It’s a simple matter of logging when a given menu item or button is clicked or code path is executed. There are tools that will automate setting all of this up. PreEmptive Solutions, for example, can build this functionality into your application without you having to write any code with their 2010 Dotfuscator application.

How much does it cost to run the software?

When money wins the raceThere’s a lot that goes into calculating the cost of running the software. It includes not only the cost of running the data center, hardware that the users use, the electricity to run the machines and the like but it also includes training to user to use the software, the user’s salary while they wait on latency issues and a whole lot more.

Again, there’s a tremendous amount of ways that you can save money in this arena.

Deploy in the cloud –  The idea of utility computing is that you only pay for the service that you use just like the electric bill. In a recent conversation with a friend whose company maintains MASSIVE data centers, he said that the servers were averaging less than 15% utilization. This is nuts but smart at the same time. On the one hand, you’ve got 6-7 times the data center that you need. On the other hand, you’re ready to handle spike traffic. The issue is that you’re still paying for that unused 85%.

This is where Windows Azure and other cloud computing platforms comes in. By deploying to the cloud you are cutting the costs of the data center down to what you are utilizing rather than what you anticipate as the possible high water marks.

This comes back to the question, however, what’s more valuable to the company? Keeping the data and processing in-house or saving the cost of the data center. A key architectural decision that you need to make here is what’s business critical to keep in house and how can you architect to keep that in house while rolling other parts out to rented data centers?

Build a better UX – If done correctly, this can make you user more efficient, cut down on the training costs and reduce support costs. 

image A great book that talks about UX is The Inmates Are Running the Asylum: Why High Tech Products Drive Us Crazy and How to Restore the Sanity by Alan Cooper. I can recommend reading not only any book that Alan Cooper has written but also can recommend reading his blog. In this book, Alan makes the analogy that most technology is like the dancing bear at the circus. The reality is that the bear is not a great dancer but people still flock to the circus to see the bear dance because, well, it’s a dancing bear. Many (maybe even most) of our technology solutions are really not that great for the user but the fact that it does anything at all is a novelty.

Principles of Software Engineering ManagementIn Principles Of Software Engineering Management, Tom Gilb wrote that “The rule of thumb in many usability-aware organizations is that the c
ost-benefit ratio for usability is $1:$10-$100.”

This cost benefit ratio is realized in several ways. Users will often call support to figure out how accomplish a given task. These calls can be eliminated by careful building of the user experience so that it’s “intuitive”. To figure out what’s “intuitive” to your users, you need to understand who they are and how they work. You can attract new users to your application. As mentioned before, you cut down on the number of features that you build that don’t get used and more.

Reduce the cost to maintain the software – This includes support calls, time and effort finding and fixing bugs, adding new features and the like. Dealing with legacy systems is what a very high percentage of developers do in their day to day jobs. The cost of maintenance can be mitigated on the front end in a number of ways.

There are a ton of books out there that cover this topic in great detail.

First, you have to have sound architectural principles and rigor. The larger the application is, the more important this is. If you can separate out your business logic from your data tier from your UI cleanly and absolutely, you have a much better chance of being able to do maintenance on one piece without devastating the rest of the pile of spaghetti.

image Second, you have to write maintainable code. The definition of “Maintainable” varies but my go to book in this topic is Code Complete: A Practical Handbook of Software Construction. I had the great fortune to have the first edition of Code Complete. It taught me things from properly named variables to building high performance data structures. I highly recommend anything that McConnell writes.

Third, find a good way to do a given task and make it the standard. For example, if you’ve got 3 different logging mechanisms, that’s probably 2 too many. If you’re doing one off security mechanisms in every application or even different parts of the same application, you’ve got huge headaches. If you have many different mechanisms for hitting the database you need to simplify and standardize.

There are lots of other techniques that will cut down on the amount of time and effort that it takes to maintain the software. However, there is a tipping point where it makes a lot more sense to do a rewrite than it does to keep maintaining the existing code base. This tipping point depends on the function of the application, state of the code, state of the architecture, practices used to build the application in the first place, availability of tools, availability of talent who understand the technologies used to write it in the first place and the requirements for new features. Determine whether it’s going to be more cost effective, given all of those variables, to do a rewrite or to keep maintaining.

This is not an easy decision. You have to fully understand the risks. Legacy code contains often vast amounts of implicit requirements: lessons learned that were never documented anywhere but the code. They should be documented elsewhere, but reality says otherwise. This is especially common when the original developers are no longer around: the new developers, in their hubris, assume all the old code is junk and can be “easily” replaced. Along the way, they lose implicit requirements that they’ll have to relearn the hard way. Additionally, rewrites from the ground up invariably take longer than adding a single small feature. Joel Spolsky is talks about these risks in an article called Things You Should Never Do, Part I.

Even with Joel’s wise words of warning, there comes a time when it’s cost effective to do a rewrite. In 2004, Rutherford and Associates took their 15 year product and rewrite 80-90% of their existing functionality and enabled a tremendous amount of new functionality with a 6-9 month investment of time from 3 developers. They had gotten to the point where they were not able to respond in an efficient manner to new customer requirements with the existing C code base. Of course, part of that code base was their own database engine because when they started 15 years prior, there was not a database engine for mobile devices.

But again, that’s going back to the numbers and understanding the needs of the business.

What’s the return?

Thinking "more"This is the really difficult part to measure. Most of the time there’s a way to measure how much your application costs to develop in the first place but there are many ways to measure return.

Returns come in three basic forms, money saved, time saved or new business enabled which brings in more revenue.

To really bring and measure a great return, you have to understand the current state of the business. This involves studying how the company earns money today and how they spend that money. When you understand this, you can start looking for ways to improve things.

Money Saved is not hard to explain but you can look for it in a lot of different places. One contract that I did before joining Microsoft was building out a specialized survey engine specific to the medical field to replace the paper one that they were currently using. This saved on printing costs, typists to type in the returned results into a spreadsheet but the real savings came in shipping costs. That alone paid for my contract within the first year.

Are you cutting back the costs in the data center or even cutting portions of it by rolling out to the cloud?

Are you cutting the power requirements of the client software by employing green methodologies?

Time Saved is a little more nebulous to measure but possible. Are you cutting down on the amount of time that it takes to process an order? One CTO of a call center told me that if he could save an average of 3 seconds a call, he would save 2 million a year. That’s a lot of money. Because of that level of savings, he was willing to spend a lot of time and money researching where users were spending time and what we cut. Latency issues were a killer. Near side caching, GEO location of data and many other relatively simple things shaved seconds and therefore saved time and money. 

Are you automating currently manual processes? If so, how long do those tasks take and what’s that cost?

Enabling New Business is where you want to be. This is where you start to become that strategic partner to the business and get a first class seat at the table w
ith the rest of the business leadership team.

Growing...Are you increasing capacity? This has to be carefully examined. If you are increasing the capacity to take orders but not the capacity to fulfill those orders, this is wasted effort. For benefit from the increased capacity, capacity for ordering, fulfillment and marketing all have to be working in concert. This comes back to understanding the business and asking people “where are the bottlenecks?”.

Are you attracting new customers to the business? Is your new online presence ranks higher in the search engines or taping into social media to leverage the “word of mouth” marketing that happens in that arena?

Are you making it simpler for people to buy your products? I recently blogged about Jarod Spool and how he changed the text on a button and created The $300 Million Button. The quick moral of the story was that the old wording was confusing customers and driving them away. The new button brought in $300 Million dollars.

Are you enabling new lines of business?  One example of enabling new business is when a wine distributor bought EO Star‘s distribution management application and realized that they could start managing and distributing many different types of foods with their wine and manage those as easily sold and packaged deals. A counter example is where one restaurant chain couldn’t offer a new type of food because they had to rewrite their menu application to handle it.

Conclusion

Money as a positionAs technology folk, we have to understand business or we will be at the mercy of the business. The primary motivation for all businesses is making money. This is measured via ROI and payback.

In order to become a strategic partner to the business you have to prove that you are providing a great ROI for the business’s investments in you.

You can improve your projects ROI by reducing development costs, runtime costs, maintenance costs and by saving the company time, money and enabling new business.

While this measurement can be a lot of work and a little scary sometimes, it will prove to be absolutely essential because once you have that data, you will be in a great position with the business.

Taking The Polar Plunge

If you would like to donate to the 2010 Polar Plunge please visit my 2010 Polar Plunge Donation Page

Josh Holmes doing the Polar PlungeAs I talked about in a recent post, I recently participated in a fund raiser for the Special Olympics of Michigan. The end of the fund raiser was that I did a Polar Plunge.

clip_image002This is a charity that is special to me because of my youngest daughter, Maura, who has a lot of challenges of her own. One day, my hope is to see her compete in the Special Olympics.

 

To find out more about Maura, see the “About” page at Wonderpuzzle.org. http://www.wonderpuzzle.org/site/About.aspx

 

Turns out a lot of people wanted to see me jump in a frozen lake… 🙂 In the end, I raised $725.00 + whatever we get through matching funds so probably a little over $1000.00. So, for all of you who paid to see me do it – here’s the video.

 

Special thanks to all of you who donated – many of who are friends on twitter…

Display Name Date Amount  Comment
Omar Greene 2/14/2009 $50.00 Josh is a fine person. Known him since his boyhood.  
JSConf 2009 2/13/2009 $100.00  
Michael Eaton 2/13/2009 $25.00  
David Giard 2/13/2009 $25.00  
Aaron Lerch 2/13/2009 $25.00  
Carey Payette 2/13/2009 $25.00 Great Cause 
tye 2/12/2009 $25.00  
Anonymous 2/12/2009 $25.00 good luck! 
Dennis Burton 2/12/2009 $25.00  
Frank Martin 2/11/2009 $25.00 Happy to help this cause. 
Susan Holmes 2/11/2009 $25.00 Because we love you and yours 
kellie englund 2/10/2009 $25.00 hope Phoebe gets your new suit done in time!!! 
Denny Boynton 2/10/2009 $50.00 Because you’re even willing to do it… 
Pandamonial 2/10/2009 $40.00 Good luck!  
Ryan Stewart 2/10/2009 $50.00  
Anonymous 2/9/2009 $20.00 don’t freeze your butt off! 
Bruce Szabo 2/9/2009 $25.00 Good Luck! 
Anonymous 2/9/2009 $40.00 Good luck!  
Tim Adams 2/9/2009 $100.00 God Bless!!! 

 
 
Grand Total: $725.00

It was a surreal experience. I watched how far across the water it was and decided that I just needed to make a dive for it. The water was about 8 foot deep where I made the jump. When I hit the water, every last bit of breath left my body. As one person said, that’s God’s way of making sure you don’t yell bad words when you hit the surface. I said something about “Man that’s cold” but it came out “BBBBBRBRRRBBRBBBRBBRBBRBRBRB”. The really bizarre thing was getting out of the water and realizing that I was walking across the snow and my feet didn’t feel cold. The snow actually felt a little warm. I got in and changed the feelings got more bizarre as my skin warmed up but I was still cold inside – exactly the opposite of normal when it’s cold outside your skin is usually the first to get cold.

I just got off the phone with a friend who asked “Would you do it again?”. I answered “Yes”. He rephrased the question with “Would you do it again if there wasn’t a good cause involved?”. I answered “No…”

Look for me to do it again next year but I’m going to go bigger on the fund raising and possibly go with a costume…

Three Essential Expression Blend Add-ins

image Expression Blend, believe or not, has an add-in model. It’s highly unsupported but it exists. The unsupported nature of it means that you have to do a little Red Green style patching to get them to run in the first place and if they cause instability, don’t call Microsoft support. However, there are a couple of really cool ones that are out there.

There are three that I think that you have to have – Unify, Colorful Expression and BlendSense: XAML Intellisense for Expression Blend.

Getting a Blend Add-in to run

Because it’s not a supported add-in model, there’s not a built in add-in manager that does the heavy lifting like the Visual Studio Add-In manager.

imageWhat you have to do is open up Expression Blend (or Design) passing in your add-in as a command line option. This starts up blend with that add-in enabled. The good news is that you don’t have to do any type of COM registration or anything to get it to work. The bad news is that it’s a hassle for those of us who don’t live on the command line like some people.

imageAnother other option, is to alter your Blend Shortcut to include the –addin parameter. This accomplishes the same task as the command line, it just does so without all the hassle of opening a command line.

There are multiple problems with both of these solutions.

First, it is only able to handle one add-in at a time. Second, that only loads the add-in when you specifically click on that shortcut but doesn’t work from a lot of other places, like launching from Visual Studio.

The great news about the first issue is that it can be solved by another add-in.

Unify Add-in

imageUnify is an add-in manager. It’s going to do all of the heavy lifting of loading and launch a number of different plug-ins such as the Xaml Intellisense for Blend and Colorful.

When Unify installs it automatically gives you a prompt that starts the Unify add-in. However, that still only solves the first problem of getting the add-in loaded when we deliberately set out to do so.

Launching Blend with Unity from Anywhere

The second problem, as mentioned above, is a little harrier. It’s that the shortcut is not the only way to run Blend. What you have to do is fix all of the different ways that you can run Blend. That includes selecting a project file from Windows Explorer and clicking Edit in Blend in Visual Studio.

This, unfortunately requires some registry hacks and the like but you can get there from here. The first registry hack to fix is the opening a solution from Windows Explorer. To accomplish this, the following code copied into a reg file works on a 64X machine. You’ll have to remove the (86) on a 32X machine.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Expression.Blend.ProjectFile\Shell\Open\Command]
@=”\”c:\\Program Files (x86)\\Microsoft Expression\\Blend 2\\Blend.exe\” \”%1\” /addin:Unify.dll”

The second registry hack to fix is the launching from Expression Blend by right-clicking on a XAML file in Visual Studio and selecting “Edit in Expression Blend”. To do this requires understanding how the right click in Visual Studio works. The list of available commands comes from the registry. When selected, it passes in two parameter. The first is the path to the actual solution and the second is a /file:filename.extension parameter. It looks as follows:

“C:\Program Files (x86)\Microsoft Expression\Blend 2\blend.exe” “C:\Projects\QuickNavigation\QuickNavigation.csproj” /file:”Page.xaml”

What we have to do is redirect this in the registry to a bat file that will pass in our /addin parameter. Personally, I created a BlendWithUnify.bat file in the /Blend directory as follows:

start “Blend” “C:\Program Files (x86)\Microsoft Expression\Blend 2\blend.exe” /addin:Unify.dll %1 %2

Technically, we could have used the .bat file with the first mechanism as well. We need to fix the registry key as follows:

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Expression\Blend\VS]
“BlendLaunchPath”=”\”c:\\Program Files (x86)\\Microsoft Expression\\Blend 2\\BlendWithUnify.bat\””

Now we are cooking with gas and are ready to investigate a few more add-ins.

Colorful Expression Add-In

imageColorful Expression was directed to me by Jared Bienz after the Expression Design tutorial that I talked about recently. It’s a sweet add-in to Expression Blend (or Design) that gives you access to a ton of different color swatches that are out there on the web. Specifically, it taps into Kulor on the Adobe site. These are mostly swatches put together by pro-designers. These are also rated so you can pick the higher rated groups to be sure. In any case, they are definitely better than the ones that my color-blind self can choose.

imageJonas Follesø saw that Kulor has a open restful API and couldn’t resist playing with it. Combine that with the (unfortunately unsupported – see below on how to get it to actually run in Blend…) add-in model for Blend and magic happens.

What it does is that it shows up as a tab in Expression Blend (or Design) and alls you to browse color pallets from Kulor for use in your application. There are a couple of slick ways that you can do that.

First, if you are running Design, you can hit the down arrow looking thing under a swatch and save it as an Expression Design Color Swatch. The next two work in either Blend or Design.

First, you can click the # button or select the swatch and hit Ctrl-C to copy the swatch to the clip board. If you paste that on a Page or UserControl, you get the swatch, but more importantly, you get the colors created as static resource brushes. You can also just go into the XAML in either the UI surface or the app.xaml and paste them that way.

Second, you can use the color picker from the normal color picker to select an individual color. This is pretty cool as well as it allows you to be very selective about your colors.

You can also run it as a standalone application if you want to pick a color swatch for use in something other than Blend or Design. I can see using to figure out color pallets for my CSS style sheets. I’m also going to contact Jonas and see if he has thought about building it for Expression Web. But that’s just me wishing and hoping until I hear back from him.

Check out Colorful Expression and give it a whirl. I’m interested to see how you use it.

BlendSense: XAML Intellisense for Expression Blend Add-in

image Just yesterday I was on a call with a guy who was frustrated by the fact that there’s no Intellisense in Blend for XAML. Well, ask and you shall receive. There’s a skunk works project called BlendSense that was put up at http://code.msdn.microsoft.com/BlendSense but it was only for the Beta versions of Expression Blend 2.5. They haven’t updated it for the release which was actually called Expression Blend 2 SP1. So, the good folks at http://www.rhizohm.net recompiled the code for us and posted it at BlendSense: XAML Intellisense for Expression Blend.

There are a couple of limitations on it’s functionality. right now, it’s using the WPF namespace types and the like for it’s Intellisense. That means that it’s not ideal for Silverlight as the Intellisense might be lie to you – but that would just take me back to my MFC days… The second limitation is that it doesn’t handle custom namespaces and the like so you’re out of luck if you are using a custom control or third party components.

Technically, it’s using an XSD file that is built for Intellisense so you could edit it to fit your needs.

Conclusion

These three add-ins are fantastic and I’m thrilled that they are here. Both of them have already, in the day that I’ve been using them, saved me time and energy in some things that I’m working on. It’s a little bit of a frustrating process to get Unify running for every scenario but it’s worth it and hopefully I’ve done the leg work on figuring it out for for you.

Polar Plunging for the Special Olympics

What I’m doing:

I’m going to be polar plunging to raise money for the Special Olympics Michigan this coming weekend in Belleville.

clip_image002This is a charity that is special to me because of my youngest daughter, Maura, who has a lot of challenges of her own. One day, my hope is to see her compete in the Special Olympics.

To find out more about Maura, see the “About” page at Wonderpuzzle.org.

http://www.wonderpuzzle.org/site/About.aspx

 

How you can help:

If you can donate, please check out my donation page at http://www.firstgiving.com/joshholmes.  

 

About the Event:

If you want to watch (video – whatever), come and ‘bear’ the elements at the 2009 Polar Plunge – Belleville at 11:30 a.m. Saturday, Feb. 14 at the Belleville Moose Lodge (831 East Huron Dr. Belleville, MI 48111). Registration begins at 10:30 a.m. with the plunge and parade of costumes beginning at 11:30 a.m. with a warm post-plunge party at 12:30 p.m.

The polar plunge is a fun-filled event open to all courageous and community-minded individuals willing to plunge into the cold water and raise critical funds to support the year-round athletic training of more than 16,000 athletes across the state. Be sure to pre-register to receive detailed information.

 

About the Special Olympic Michigan:

The mission of Special Olympics Michigan is to provide sports training and athletic competition in a variety of Olympic-type sports for the children and adults with intellectual disabilities. Athletes are given continuing opportunities to develop physical fitness; demonstrate courage; experience joy; and participate in a sharing of gifts, skills, and friendship with their families, other Special Olympics athletes and the community. Through Special Olympics, athletes gain self-confidence and prove their own capabilities.

UI Design for Developers Series, by Total Training.

image

I’m at an internal conference at Microsoft this week and one of the sessions that I attended was called Practical Design tips and tricks for Developers. It was a set of hands on labs that were created out of the Expression team. It was really slick and I learned a whole lot of new techniques and am feeling a whole lot more confident in my Expression Blend abilities. The really slick part is that you get to work through those same labs if you are interested because they have been posted on Arturo’s blog.

This 13 part video series will walk you through creating a workable color palate with a range of colors which all work together, creating brush resource out of those, creating shapes all the way from simple straight and curved lines to glass button effects with the simplest possible steps and really sets you up with the basics of what you need to know. It was really cool to be able to walk through those labs.

The labs are as follows:

1Principles of Design Series:  Learning about Balance using Expression Design

2Principles of Design Series:  Learning about Rhythm using Expression Design

3Principles of Design Series:  Learning about Emphasis using Expression Design

4Principles of Design Series:  Learning about Symmetry and Asymmetry using Expression Design

5Principles of Design Series: Learning about Unity using Expression Design

6Principles of Design Series:  Learning about Points, Lines, and Form using Expression Design

7Choosing Colors to Complement Your User Interface with Expression Design

8 – Experimenting with User Interface Colors with Expression Design

9 – Creating Mosaic and Tiled Patterns using Expression Design
10 – Learning to Create Icons using Expression Design
11 – Creating a Sample Icon using Expression Design
12 – Designing a Glassy Button using Expression Design
13 – Applying Effects to Bitmap Images using Expression Design

 

For links to the videos and digital assets that you need to accomplish the the labs, check out Arturo’s post on it at ux.artu.tv » Blog Archive » New Video Series: UI Design for Developers Series, by Total Training.

Adding Paging to the Simple Photo Gallery

Turn the pageOver my last handful of posts, Building a Simple Photo Gallery in ASP.NET MVC Framework, Returning Thumbnails With the MVC Framework and Adding Lighbox.js to the Simple Photo Gallery I’ve built a simple photo gallery on the ASP.NET MVC framework.

In this post, we’re going to continue that project by adding paging rather than showing all of the pictures on the one page.

Adding Paging to the Model with LINQ

Since we are simply using an XML file for the storage, we need to do the paging manually against our set of objects that we have in memory. This method works well any time you have client side caching as well.

public class ImageModel : List<Image>
{
    public ImageModel() : this(1, 10)
    {
    }

    private List<Image> GetAllImages()
    {
        string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
        XDocument imageMetaData = XDocument.Load(imagesDir + @"/ImageMetaData.xml");
        var images = from image in imageMetaData.Descendants("image")
                     select new Image(image.Element("filename").Value,
                     image.Element("description").Value);
        
        TotalCount = images.Count<Image>();

        return images.ToList<Image>();
    }

    public int TotalCount { get; set; }
    public int CurrentPage { get; set; }
    public int PageSize { get; set; }
    public ImageModel(int pageNum, int pageSize)
    {
        CurrentPage = pageNum;
        PageSize = pageSize;

        var images = GetAllImages();

        this.AddRange(images.Skip((pageNum - 1) * 
            pageSize).Take(pageSize).ToList());
    }
}

Notice that I added a new constructor that takes as parameters page number and page size. This will allow us, from the controller, to control the action happening here. The next thing to notice is that the default constructor is now calling the new constructor passing in default parameters of 1 and 10. Notice that we’re starting with 1 instead of 0. This will make a ton more sense to the user and makes mapping the pages a lot simpler. Lastly, notice that we’re setting some parameters (TotalCount, CurrentPage and PageSize). We’ll use these in the view in a little bit.

If we run right now, we’ll only get the first 10 pictures. If you happen to be following along and coding this with me, go ahead and try it.

Adding the Custom Route

Next, we need to add a route to handle the page mechanism.

In the global.asax.cs file, in the method called RegisterRoutes add the following route.

routes.MapRoute(
    "ImagePaging",                                              // Route name
    "{controller}/Page{pagenumber}",                           // URL with parameters
    new { controller = "Home", action = "Page", pagenumber = "1" }  // Parameter defaults
);

Notice how the routes are built. It’s a series of url parts and named parameters. For example, the Page2 is going to pass in 2 as the selected pagenumber. We actually could have hard coded the whole path except for the page number.

Adding the Paging Action to the Controller

Now that we’ve got data routing to the an Action, we need to make sure that we’re handling it.

Turns out, this was the easiest piece of all.

public ActionResult Page(string pagenumber)
{
    ImageModel model = new ImageModel(int.Parse(pagenumber), 10);
    return View("index", model);
}

Notice that we are just creating the ImageModel leveraging our new constructor and passing it into a view. The view that we’re using is still the index view, which is the default. We don’t have to go build a new view for the paging, we just need to alter the data that we’re passing into our current view.

If you want, you can go test by browsing to /image/page2 and see what it shows.

Adding the Navigation Links

The last thing to do is to add the navigation links to the view. If you use the <% %> tags in any ASPX it runs on the server side. What this is actually doing is that the ASPX page is parsed and generated into code and compiled into a .NET assembly on the server side and the code inside the <% %> just gets copied into that generated code before it’s compiled. This means that the code that’s inside your brackets must match the language that you set at the top of the page.

<%if (ViewData.Model.TotalCount > ViewData.Model.PageSize){ %>
<div class="paging">
    <%if (ViewData.Model.CurrentPage > 1) { %>
        <%= Html.ActionLink("Back", 
"Page" +
(ViewData.Model.CurrentPage - 1).ToString(), "Image")%>&nbsp; <% }%> <%decimal numberOfPages =
decimal.Divide(ViewData.Model.TotalCount, ViewData.Model.PageSize); int lastPageNumber = (int)decimal.Ceiling(numberOfPages); for (int i = 1; i <= lastPageNumber; i++) { if (i != ViewData.Model.CurrentPage) { %> <%= Html.ActionLink(i.ToString(), "Page" + i.ToString(), "Image")%>&nbsp; <% } }%> <%if (ViewData.Model.CurrentPage < lastPageNumber) { %> <%= Html.ActionLink("Next",
"Page" + (ViewData.Model.CurrentPage + 1).ToString(), "Image")%> <% }%> <%=lastPageNumber%> </div> <% }%>

Notice that we’re using the properties set by back in the model here. There’s three different sections here. The first checks to see if we need a back button. The second loops over the pages and creates step links. And the third checks to see if we need a next button.

The navigation links in the view turned out to be the most complicated part of adding paging to the photo gallery.

Stay tuned to future posts for styling with CSS, adding a Silverlight front end and more.

Adding Lighbox.js to the Simple Photo Gallery

image In my previous two posts, Building a Simple Photo Gallery in ASP.NET MVC Framework and Returning Thumbnails With the MVC Framework, I built a simple photo gallery on the ASP.NET MVC framework. In this post we are going to start making this a little prettier. To start with, we are going to leverage an JavaScript project called Lightbox.js that’s released under the Creative Commons Attribution 2.5 License.

One cool part about it is that you can get a tremendous amount of functionality with little to no JavaScript coding on your own. It leverages a couple of different JavaScript libraries including Prototype and Scriptaculous. These do a lot of generic HTML Dom manipulation and visualization.

The result of leveraging Lightbox.js is that when you click on one of the thumbnails that we started showing in Returning Thumbnails With the MVC Framework the full sized picture will show in a really nice lightbox style effect.

First, you need to download the Lightbox.js project. It comes in a zip file that comes with a sample application. Unzip the contents into the appropriate folders. This means that the .js files go in your /scripts directors and the images and the css in the /content folder.

The cool part is that since you have the source to it all, rock on and modify it to your heart’s content. And we’re going to do a light modification right off the bat. We could have put the images from the Lightbox.js project in the /images folder but we’re already using that for something else so we put them in the /content folder. That means that you need to open up lightbox.js and change the directory of the loading and close images to point to the correct directory.

LightboxOptions = Object.extend({
    fileLoadingImage:        'content/loading.gif',
    fileBottomNavCloseImage: 'content/closelabel.gif',

That’s the only mod that we *need* to make at the moment. If you feel like it, you can fix the image paths in lighthouse.css as well.

#prevLink:hover, #prevLink:visited:hover { background: 
url(Content/prevlabel.gif) left 15% no-repeat; } #nextLink:hover, #nextLink:visited:hover { background:
url(Content/nextlabel.gif) right 15% no-repeat; }

The only thing left to do is update the Images/index view to take advantage of our new capabilities. There are two mods to make. First, we need to include links to the lightbox.css and the required 3 JavaScript files (prototype.js, scriptaculous.js and lighbox.js). Second, we need to add a rel=”lightbox” to the anchor tag around our picture.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Index.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Index" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <link rel="stylesheet" href="content/lightbox.css" type="text/css" media="screen" /> <script src="scripts/prototype.js" type="text/javascript"></script> <script src="scripts/scriptaculous.js?load=effects,builder" type="text/javascript"></script> <script src="scripts/lightbox.js" type="text/javascript"></script> <p><%= Html.ActionLink("Add your own image", "Upload", "Image")%></p> <% foreach (var image in ViewData.Model) { %> <span class="image"> <a href="/images/<%= image.Path %>" rel="lightbox">
<
img src="/image/thumbnail/<%= image.Path %>" />
</
a> <span class="description"><%= image.Description %></span> </span> <% }%> </asp:Content>

It’s that simple. This will render a really nice little lightbox effect on our images.

Stay tuned for future posts about styling the CSS, paging the pictures and a whole lot more.

Returning Thumbnails With the MVC Framework

In my last post, we put together a quick and simple photo gallery. This post will be building on that.

Depending on the size of your photo, however, it didn’t have the worlds greatest user experience. I’ll be playing with the CSS, JavaScript and a ton more over time. Today, however, I’m going to be just returning a thumbnail rather than the full picture to show in the view.

I don’t want to have to physically create each of the thumbnails so we’ll generate those dynamically on the fly.

Creating a Custom ActionResult

To return a given type of result, you have to return an ActionResult of that type. The types that are currently built in are View, Redirect, RedirectToAction, RedirectToRoute, Content, or Json. We need to create a specific action type that we’ll call the ThumbnailResult. It will be created with a virtual path to the picture that we need to show. When it’s executed, it will generate and return the thumbnail.

public class ThumbnailResult : ActionResult
{
    public ThumbnailResult(string virtualPath)
    {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath {get;set;}

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = "image/bmp";

        string fullFileName =
            context.HttpContext.Server.MapPath("~/images/" + VirtualPath);
        using (System.Drawing.Image photoImg =
            System.Drawing.Image.FromFile(fullFileName))
        {
            using (System.Drawing.Image thumbPhoto =
                photoImg.GetThumbnailImage(100, 100, null, new System.IntPtr()))
            {
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    thumbPhoto.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    context.HttpContext.Response.BinaryWrite(ms.ToArray());
                    context.HttpContext.Response.End();
                }
            }
        }
    }
}

Notice that we’ve set the HttpContext.Response.ContentType to “image/bmp”. This is critical for the browser to understand the data that it recieves.

Leveraging the Custom ActionResult

The next step is to add a method to the controller that will return the ThumbnailResult.

public ActionResult Thumbnail(string id)
{
    return new ThumbnailResult(id);
}

And lastly we need to update the view to leverage this new thumbnail action.

<a href=”/images/<%= image.Path %>“><img src=”/image/thumbnail/<%= image.Path %>” /></a>

When you run now, you should get the thumbnails instead of the full sized picture. However, you should still be able to click through to the actual picture. In an upcoming blogpost, we’ll change this to use lightbox.js.

Building a Simple Photo Gallery in ASP.NET MVC Framework

image I decided to create a simple photo gallery in the ASP.NET MVC framework. The fun part is that this level of application is really the new “Hello World”. It takes less time to build than the “Hello World” did back in the day.

In this post, I’ll walk you through the process of creating this simple photo gallery with the MVC framework.

First, let’s talk a little about what the ASP.NET MVC framework is. It’s a web framework built on .NET with the principles of the MVC architecture behind it.

The MVC Architecture

MVC architecture divides the responsibilities of an application into three main components – models, views, and controllers.

image“Models” are responsible for the the data access. The data is often times in a database but it doesn’t have to be. The model could be over an XML file or whatever other data store that you happen to use. By default the ASP.NET MVC framework uses the Entity Framework. However, it can work with any data access type that returns a set of objects that the view can access. Most of the time, this will be an ORM such as the Entity Framework, NHibernate or SubSonic. In our demo below we’re actually going to just be reading in an XML file from the disk.

“Views” are responsible for the actual user interface. Typically this is HTML but it could be XML, JSON or any other number types of display/service response. Most of the time, these displays/responses are built based on model data.

“Controllers” are responsible for the actual logic. It handles the end user interaction, manipulates the data in the model and decides which view to return to the user. Simple enough? 

Creating the ASP.NET MVC Framework Project

image I started out creating an ASP.NET MVC Web Application called PhotoGalleryMVC. There are a couple of very important things to notice in an ASP.NET MVC framework project.

First, look at the Global.asax and it’s code behind. It’s got a really important method called RegisterRoutes where you define your routes.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", 
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "" }
    );

}

These routes define what happens when your application receives a request. The controller is a class and the action is a method on that class. The parts after that are parameters to the method. We’ll see more with this in a few moments.

The next thing is to notice the controllers. The default method that you get in the helper class is as follows:

public ActionResult Index()
{
    ViewData["Title"] = "Home Page";
    ViewData["Message"] = "Welcome to ASP.NET MVC!";

    return View();
}

This is the default action for the controller. It’s simply setting some properties on the View and then returning it. Notice that we’re not instantiating a copy of the view and setting properties directly on it. Instead, we’re staying with the very loosely coupled method of using a ViewDataDictionary called ViewData. This is a dictionary of items that both the view and the controller have access to.

Creating the ImageModel

The first thing I want to create is a way to get the images in the first place. Rather than creating a database, we’re going to simply use an XML file as our storage for our information about our images.

Create a folder called Images under the root of the project. This will be where we put the images.

As a file ImagesMetaData.xml in the images directory following the format below. Feel free to substitute your own data in for the data I have below…

<?xml version="1.0" encoding="utf-8" ?>
<images>
  <image>
    <filename>IMG_3717.JPG</filename>
    <description>Paul playing Guitar Hero.</description>
  </image>
  <image>
    <filename>IMG_3720.JPG</filename>
    <description>Phizzpop Signin.</description>
  </image>
</images>

Add a class called Image under the model folder. For now this will be really simple.

namespace PhotoGalleryMVC.Models
{
    public class Image
    {
        public Image(string path, string description)
        {
            Path = path;
            Description = description;
        }
        public string Path { get; set; }
        public string Description { get; set; }
    }
}

All this class provides for now is a holder for the image path and description. We’ll do more with this class in the future.

The next thing that we need to do is create a way to get those images from the disk. This will be in a class called ImageModel. To make this really simple, we will inherit from a generic list of Image. This gives us a lot of functionality already. What we need to add is a constructor that will retrieve the images from the disk.

namespace PhotoGalleryMVC.Models
{
    public class ImageModel : List<Image>
    {
        public ImageModel()
        {
            string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
            XDocument imageMetaData = XDocument.Load(imagesDir + @"/ImageMetaData.xml");
            var images = from image in imageMetaData.Descendants("image")
                         select new Image(image.Element("filename").Value,
                         image.Element("description").Value);
            this.AddRange(images.ToList<Image>());
        }
    }
}

All this model is doing is reading in the XML file and creating a list of images based on that metadata.

Creating the Controller

The next step is to create the controller. Again, for the moment, this will be extremely simple. We’ll do more with it in the future.

namespace PhotoGalleryMVC.Controllers
{
    public class ImageController : Controller
   
{
        public ActionResult Index()
        {
            return View(new ImageModel());
        }
    }
}

Notice that this is slightly different than the default controller as it’s passing in the ImageModel. We’ll have to create the View to accept it here in just a moment.

Creating the View

Now we need to add a folder to the hold our images view in the Views folder. Now to create the view in the Images view folder, right-click on the folder and select Add View. Name the view Index.

Now that we have our view, modify it’s declaration to accept the ImageModel class.

namespace PhotoGalleryMVC.Views.Image
{
    public partial class Index : ViewPage<ImageModel>
    {
    }
}

What this does is set up our view based on a generic ViewPage with ImageModel as it’s base.

And lastly we need to add the HTMLish stuff to do the actual display.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Index.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Index" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <% foreach (var image in ViewData.Model) { %> <span class="image"> <a href="images/<%= image.Path %>"><img src="images/<%= image.Path %>" /></a> <span class="description"><%= image.Description %></span> </span> <% }%> </asp:Content>

If you’ve ever done ASP Classic or PHP, this HTMLish stuff shouldn’t look too odd. If you strip out the HTML code, you’ve got a normal foreach loop written in C#. The bad news about this approach is that there’s a lot less controls, such as the datagrid and such, available to you. The good news is that you’ve got absolute control over the HTML that is produced.

You should notice, however, that we’re able to leverage master pages as we do in ASP.NET 2. This is great because it allows us to define our look and feel in a master page. There’s a great amount of flexibility and power in that.

Last step is that we need to add a tab on the main navigation to get to the images page. We do that in the /views/shared/site.master

<ul id="menu">
    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
    <li><%= Html.ActionLink("Images", "Index", "Image")%></li>
    <li><%= Html.ActionLink("About Us", "About", "Home")%></li>
</ul>

Even though we’ve got few controls at out disposal, there are some interesting helpers such as this Html.ActionLink. This returns a link that points to the appropriate controller and action without us having to divine what that link should be based on the current routes. 

At this point, the application runs and shows really big pictures (assuming that you’ve put a few in the images folder in the first place).

Adding a New Picture

Now that we’ve got a few manually placed a few of the pictures in the folders and gotten them to display on the view, we need a way for the user to add their own pictures to the site. We’re going to do this one in reverse order where we create the view and work backwards from there.

Step one is that we need a new view and a way to get to it from the images page. We can accomplish that with a simple Html.ActionLink in the Image Index view.

    <p><%= Html.ActionLink("Add your own image", "Upload", "Image")%></p>

Now we need to create the view for the New action. Simply right click on the View folder and select Add|View. Name this view “Upload”.

In the view, we need to create a form that will do the post.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Upload.aspx.cs"
Inherits="PhotoGalleryMVC.Views.Image.Upload" %>

<asp:ContentID=”Content1″ContentPlaceHolderID=”MainContent”runat=”server”>
<
form method=”post” action=”<%=Url.Action(“save”) %>enctype=”multipart/form-data”>
    <
input type=”file” name=”file” />
    <input type=”submit” value=”submit” /> <br />
    <input type=”text” name=”description” />
</form>
</
asp:Content>

It’s not the world’s prettiest form but it’s functional. Notice the action on the form tag. It’s using another helper called Url.Action. This maps to the same controller but a different action.

Now we need to add the upload and save action to the controller. The Upload action is very simple. It simply returns the Upload view. The Save is a little more complicated as it has to do the actual logic of getting the files and descriptions and putting those on the model.

namespace PhotoGalleryMVC.Controllers
{
    public class ImageController : Controller
    {
        public ActionResult Index()
        {
            return View(new ImageModel());
        }

        public ActionResult Upload()
        {
            return View();
        }

        public ActionResult Save()
        {
            foreach (string name in Request.Files)
            {
                var file = Request.Files[name];

                string fileName = System.IO.Path.GetFileName(file.FileName);
                Image image = new Image(fileName, Request["description"]);

                ImageModel model = new ImageModel();
                model.Add(image, file);
            }
            return RedirectToAction("index");
        }
    }
}

The important part here is that this controller is not actually doing the logic of saving out to the disk. This is important because it gives us the flexibility to alter the model switch from file based storage to a database and so on. This separation is key to the success of the architecture.

Last thing to do is alter the model to actually save out to the disk.

public void Add(Image image, HttpPostedFileBase file)
{
    string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
    file.SaveAs(imagesDir + image.Path);

    this.Add(image);
    XElement xml = new XElement("images",
            from i in this
            orderby image.Path
            select new XElement("image",
                      new XElement("filename", i.Path),
                      new XElement("description", i.Description))
            );

    XDocument doc = new XDocument(xml);

    doc.Save(imagesDir + "/ImageMetaData.xml");
}

The LINQ makes creating the XML document really simple.

There are a lot of optimizations that could be done here such as storing off the model in memory and the like so that we’re not constantly reading/writing to the disk and the like. That’s not the point of this exercise. The point here is to work with the MVC framework.

At this point we’ve got a functioning image gallery with uploads and a view.

In my next post, I’ll alter this to serve up thumbnails and give a nicer user experience.

Ann Arbor Day of .Net

Wow I’ve been swamped. There’s so much to blog about in the past couple of weeks so I’m just going to catch some of the highlights.

Ann Arbor Day of .NET was on 5/5/2007. It was fantastic! It sold out at 250 people and of that there were 210 people show up. That’s actually really good as most free events have a 40% droppoff and they had less than 20% droppoff. The only downside on the day was that with less than a 20% droppoff – pizza was a little short at lunch.

They are actually thinking about going to every 6 months instead of every 12 months. I think this would be fantastic!

I kicked off the day with a session on User Experience technologies at Microsoft. I borrowed from some of the materials that we are putting together for the upcoming ArcReady (Check the site for dates and times across the entire central region – Detroit on 5/25 in two weeks for all those that attended Day of .Net). We dipped into WPF, AJAX and Silverlight. My favorite demo is the Silverlight Airlines Demo. It shows a truly out of the box user experience that’s not all glitz and glammor but a truly solid UI for a true business application. Many of the demos, while showing off the platform really well, are marketing apps that show lots of 3D and animation. My customers often look at the glitzy demos and say that they are not doing 3D so they don’t look at the technologies. What they are missing is that there are real benifits here with enabling truly rich interfaces that go well beyond text and pictures.

I had two more 30 minute sessions. In both of those sessions the overwhelming requests were to have more Silverlight content. I had nothing prepared for these sessions but they went really well. In the first session, I pulled Don Burnett, who started Michigan Interactive Designers, out of the crowd and asked him to do a tour around Expression Blend and Silverlight. He got up, completely unscripted, and did a fantastic job! I will definitely be bringing him in to do more demos and presentations – especially when we have a designer based crowd. It turns out that he used to work with Bill Wagner (my former business partner when I was at SRT Solutions) on the Lion King Animated Storybook.

In the second session, I was on my own but I showed Top Banana, the DLRConsole (python and javascript version – IronRuby will be released as a CTP from CodePlex later this year) and talked about the .NET support in Silverlight 1.1 Alpha. Yes – I actually wrote some Python and did a simple overview for people at the conference. It was a fun day!

Here are some of the resources that we talked about during the three talks:

•Windows Forms @ .NET FX Developer Center
http://windowsclient.net

•WPF @ MSDN Developer Center
http://msdn.microsoft.com/winfx/reference/presentation/default.aspx

•.NET 3.0 (WPF, WCF, WF) Community Site
http://windowsclient.net/

•Silverlight
http://www.silverlight.net

•ASP.NET AJAX @ ASP.NET Developer Center
http://msdn.microsoft.com/winfx/reference/presentation/default.aspx

•ASP.NET AJAX Community Site
http://ajax.asp.net/

•DirectX @ DirectX Development Center
http://msdn.microsoft.com/directx/

•Microsoft Visual Studio @ Visual Studio Developer Center
http://msdn.microsoft.com/vstudio/

•Microsoft Expression
www.microsoft.com/expression

 

Day of .NET site

Link to Day of .Net in Ann Arbor 2007 – Home

Don Burnett’s write-up of the event.

Link to Don.NET’s WPF Designers Blog: Eastern Michigan Day of Dot Net