Zen and the art of WPF

February 23, 2008

Once upon a time, there was a WPF application that had two types of users:

zen 1

The UI had two buttons. One button allowed anyone to view an account. The other button, though, was only for certain privileged people to click, because it deleted an account.

zen 2

When the program was first released, a careless developer introduced a subtle bug in the logic which determines if an account can be deleted.

zen 3

For 99% of the non-privileged users, it never dawned on them that it was possible to delete an account when they ran the program.

zen 4

One of the users had a grudge against the world, and also some knowledge of a little tool known as Snoop. He was determined to bring down The Man one account at a time.

zen 5

When this malicious user ran the app, he snooped around until he found the hidden Delete Account button.

zen 6

He found that button’s Visibility property and set it to ‘Visible’.

zen 7

Since the careless developer did not expect that button to ever be visible when the user is not allowed to see it, the button was not disabled and could be clicked.

zen 8

Tempting fate, the jaded user clicked the button.

zen 9

After much fire and brimstone fell from Corporate Skies, the once careless developer learned a valuable lesson. He understood that WPF element trees can be viewed and modified while the application is running. He sharpened his code-sword and prepared for battle.

zen 10

In one swift movement, he defeated his foe.

zen 11

After the new version of the application was deployed, the malicious user once again attempted his devious maneuver. However, this time, he found that after unearthing the Delete Account button in Snoop, the button was disabled.

zen 12

He could not click it. The button’s IsEnabled property could not even be set to true, since the Delete command’s CanExecute handler was forcing the button to be disabled. He could not use the application to continue his rampage against The Man. It broke his heart, and he cried.

zen 13

Download the application’s source code here (rename the file extension from .DOC to .ZIP).


Deleting an image file displayed by an Image element

February 21, 2008

This blog post discusses one way to deal with the fact that, by default, a BitmapImage object holds a lock on the source image file. Along the way we will see what inspired this solution.

I have been working away on Podder, my WPF podcast player. Grant Hinkson, my favorite Visual Designer in the world, has spent some of his scarce free time creating a truly phenomenal skin for Podder. His work has revealed shortcomings and oversights in the Podder design, which I have been diligently working on and resolving.

Every podcast has an associated image, which is linked to via the podcast’s RSS feed. Grant’s Podder skin represents a podcast by showing it’s image. When I first added in support for providing the image of a podcast, I simply exposed a property on my Podcast class that returned the URL of the image. This worked OK for my skin, since it only shows one image at a time. For Grant’s skin, however, this did not cut it. His UI shows multiple podcast images at the same time. When the app first loaded with his skin applied, it would take quite a while for those images to be downloaded and displayed. Subsequent loads with his skin, during the same run of the app, would be fast because WPF caches images by default.

I decided to address this issue by saving each podcast’s image to disk, and then always load the image from disk (instead of downloading it every time you run the app). Getting the image saved to disk was easy:

Image File (download)

The tricky part was a little more subtle. When the user removes a podcast from Podder’s list of podcasts, I feel morally obligated to delete that podcast’s image file from their disk. I suppose it isn’t truly necessary, but I’m not a fan of apps that lazily leave garbage floating around on my disk, eating up space.

This moral quandary resulted in a call to File.Delete(theImageFile). Unfortunately, this did not work. It turns out that the BitmapImage, which is used by an Image element, holds a lock on the image file that you pass as it’s source. If you try to delete the file, an exception is thrown letting you know that you’re being a very naughty developer.

Naturally, the first thing I did was search the Web for more info about this problem. I came across an excellent solution for the problem here. Ralph’s solution involves a custom value converter that adjusts the BitmapImage’s caching behavior, so that it does not put a lock on the image file after the image has been loaded. That’s a very clean and simple solution, but I didn’t want to use it. One of my goals in designing Podder is that it should be as simple as possible to skin it. I’m actually toying with the idea of hosting a competition where people make their own Podder skin(s), and then submit them as entries to be judged and possibly awarded prizes. So I need to keep the skinning process as simple as possible. Having to use some obscure value converter on Image sources does not jive with that objective.

I was stumped. I needed to be able to delete image files for podcasts that were removed from Podder, but attempting to delete an image file resulted in an exception being thrown. What to do? I stepped away from the computer, sat down at the piano, and improvised. The solution dawned on me after playing this lovely little tune:

Josh Smith Piano Improv [2-21-2008]

In an inspired moment, I ran back to my laptop and modified my PodcastImageCache class a bit, so that instead of attempting to immediately delete an image file when told to, it stored the image file path in a list.

Image File (pre-delete)

I added the PodcastImageCache object to the application’s object graph that gets serialized by the BinaryFormatter as it shuts down. When the PodcastImageCache object is serialized that list of image file paths gets saved, too. I then used the magical OnDeserialized attribute to specify a callback to be invoked when Podder starts up again, and the PodcastImageCache object is deserialized.

Image File (delete)
Since the object graph is deserialized before the UI has a chance to come back to life, I am certain that none of the image files will be locked by the UI at the time this code runs. Perhaps this solution is overkill for most apps, but if you need to maintain absolute simplicity in the UI layer then this approach has value.


Buying themes for WPF applications

February 19, 2008

The Web is full of comments where people generally voice the same issue with WPF. It seems that everyone and their grandmother thinks WPF is only useful for companies building apps with “differentiated user interfaces.” Ya know, Times Reader, Yahoo Messenger for Vista, etc. A common thread is that if you are building line-of-business (LOB) applications, WPF is not going to give you much over WinForms. While understandable, this opinion is simply wrong. Need proof? Check out the Lawson Smart Client app.

With that said, there is a point to take away from the general consensus. I totally agree that you are missing out on a lot of WPF’s potential if you do not have Visual Designers around to Blend up some fantastic user interfaces for you. Even if you have the budget to hire Visual Designers, it’s not exactly a simple task to find someone who has strong VD skills, as well as a firm background in software development. Those people are in high demand, and are in low supply (‘low’ compared to, say, competent WPF developers…oh wait…nevermind). ;)

What I expect to see, in abundance, is third-party and open-source visual themes that can simply be plugged into any application. Development teams will use pre-canned visual designs. There’s gold in them hills. Once a development team can purchase/download a set of styles/templates/resources to turn their drab LOB apps into something like Lawson Smart Client, WPF will be the de facto choice for LOB projects. Of course, I assume by that time design-time support for WPF will be much better and supportive of RAD. Without that, all bets are off.

These types of pre-canned themes are already available to a certain extent. The Reuxables product seems interesting. I have not used it yet, but it seems on the right track and worth trying out. Infragistics offers Theme Packs, which you can use to restyle Infragistics controls. Products like these are the future of WPF and Silverlight development, considering that most dev teams neither have access to or can find Visual Designers.


The importance of learning Expression Blend

February 18, 2008

A few days ago I was visiting the Infragistics headquarters.  I set aside half an hour to stop by Grant Hinkson‘s office.  Grant is the Visual Designer working on a new skin for Podder.  I wanted to check in with him, and work through any issues or questions that might have cropped up during his work on his new Podder skin.  I had a WPF revelation within those thirty minutes.

For this project, Grant is acting solely in the capacity of Visual Designer.  He is a good Developer, but I don’t want him to need those skills for this project.  My objective is to design Podder in such a way that he, the Visual Designer, never has to write a line of code.  Naturally, this means that he is living in Expression Blend to get his work done.  As we worked through little issues and gotchas, I was amazed at how fluent Grant is in Blend.  I must admit, I never use Blend.  He was flying through the menus, dropdowns, panels, etc. so quickly that I could not follow along!

What amazed me even more was the thought processes he went through to get his work done.  As he expertly navigated through Blend, he was saying things like “We’ll need to Storyboard that…I’ll just record a Timeline for this…Now I’ll just trigger the transition off that event…We’ll group those elements together…”  I never, ever say or think things like that when working with WPF.

This experience made me realize that Visual Designers think about WPF in a very different way than Developers.  So different, in fact, that there is a very real potential for a communication barrier to arise between the development staff and the visual design team.  Luckily for me, Grant is an accomplished WPF developer, so we were both pretty much on the same page.  However, it is easy to imagine working with a Visual Designer who does not have the development experience, and having trouble finding a common ground of shared concepts to discuss.  The further away from “visual design” you go, the more murky the communication can become.  For example, how do you discuss the proper way to create a declarative data binding with someone devoid of development experience?

I now believe it is imperative that WPF developers are at least comfortable using Blend.  Even if you have no intention of using Blend on a regular basis, it will prove beneficial as you interact with people who live in Blend.  The thought processes of getting work done, the terminology/lingo, and the artificial limitations imposed by Blend are all things that we, the developers, should know about.  Not only that, but it is a very interesting and powerful tool!

I’m excited to learn Blend!


Podder v2 Beta

February 10, 2008

Just over a month ago I introduced my WPF podcatcher project, Podder. Shortly after the initial release of Podder I began collaborating with Grant Hinkson, Visual Designer extraordinare. He has been working on a new skin for Podder, actually a new “structural skin,” as I call it. I designed Podder to allow for structural skinning, meaning the entire UI can be swapped out at runtime or compile time. It has been very exciting to see Grant turn Podder into a thing of true beauty, by substituting my UI with his own! :D

Part of this process has required me to change the way Podder works, as well as implement several new features. At this point, I have implemented all of the new functionality and refactored some of the previous code. I’m not sure how long it will take Grant to finish his Podder skin, so I decided to release the new build of Podder as a beta.

Here it is: Podder v2 Beta

NOTE: You will need to change the file’s extension from .DOC to .ZIP and then decompress it. This is a workaround for a limitation imposed by WordPress. Podder requires .NET 3.5

If you have already been using Podder, you must erase the files it stores in your AppData/Local/Podder directory. On my Vista machine, those files are located here:

C:\Users\joshs\AppData\Local\Podder

I am not sure where the equivalent directory would be on XP.  If you do not delete those files, Podder will not work correctly.

I added quite a few features between v1 and v2. Here are some of the big ticket items:

  1. Vastly improved podcast management dialog.
  2. The Podder process runs at a high priority so that it does not freeze under heavy CPU load (thanks to Marlon Grech for that tip).
  3. Episode tooltips now contain a summary, duration, file size, and more.
  4. The app has a system tray icon and minimizes to the system tray.
  5. No matter which podcast is selected, you can click on a link to return to the active episode.
  6. The app detects when it does and does not have internet access (hacky…).
  7. The app can load and apply skins from DLLs at runtime (this feature is disabled in the Beta).
  8. Lots of tweaky bug fixes and better error handling.

Here are some screenshots of the Podder v2 Beta, still using my plain old skin. Click on the images to view them at full size.

Podder’s main window

Podder v2 Beta (Main Window)

Podder in the system tray

Podder v2 Beta (System Tray Icon)

Adding a new podcast to your list – Processing…

Podder v2 Beta (Processing New Feed)

Adding a new podcast to your list – Finished!

Podder v2 Beta (Podcast Added)

I hope you have as much fun using Podder v2 Beta as I had making and using it. If you find any bugs, please drop a comment on this post and let me know. I appreciate all the help I can get. :)

By the way, I have seen the skin that Grant is making. OMG it looks good! Once it is ready, I will write the next article in the Podder series on CodeProject, and show you why WPF rocks so hard!


John Liao on WPF and F#

February 2, 2008

A few months ago, I explored how the new .NET functional programming language F# could be used with WPF.  After a while I decided that F# was not “there yet”, in terms of Visual Studio integration, to really be a contender in that space.  One could say that WPF is not “there yet” either, but that’s besides the point…

It turns out that John Liao has down a fantastic job of exploring and blogging this exciting intersection of cutting edge technologies.  The mastermind behind F#, Don Syme, has created a listing of Liao’s WPF/F# blog posts here.  This is great material!  Enjoy.


Follow

Get every new post delivered to your Inbox.

Join 289 other followers