Wednesday, April 28, 2004

ListItemWrapper

Here's a little trick that I use all the time. It's simple but handy.


I often find that I want to have a ListBox full of some particular item - to be completely boring, let's say it's a list of Customer objects. We only want to display the customer's name, but it's handy to store the whole Customer object in the ListBox, rather than just the customer's name, because it saves us having to go through the trouble of looking up a Customer based on their name. And of course .NET completely supports this, since you can add any object you want to the ListBox.


If you were to code up a simple implementation of Customer like this one:


public class Customer {
  private string name;
  private int age;

 
public Customer(string name, int age) {
    this.name = name;
    this.age = age;
  }

  public string Name {
    get { return name; }
    set { name = value; }
  }

  public int Age {
    get { return age; }
    set { age = value; }
  }
}


and if you were to then shove a bunch of these into a ListBox, you might be a bit surprised to find the list box displays something like MyNamespace.Customer for every object - hardly what we want.


The reason for this is simple: when confronted with an object, the ListBox displays it by calling ToString on it. And the default implementation of ToString simply returns the name of the type. Not particularly useful in most situations, but what else could they do?


Of course, this is simple to fix if we're the ones that own the Customer object. Simply adding an override of ToString that returns the name would do it. But what if someone else wrote the object and we don't have the source code? Or what if ToString returns something we don't like? I've run into this enough times that I've found the following trick worth including in my standard bag of tricks. I simply write a class that looks like this:


public class ListItemWrapper {
  private string text;
  private object item;

 
public ListItemWrapper(string text, object item) {
    this.text = text;
    this.item = item;
  }

  public string Text {
    get { return text; }
    set { text = value; }
  }

  public object Item {
    get { return item; }
    set { item = value; }
  }

  public override string ToString() {
    return text;
  }

}


Now, when I want to store a Customer in a list, what I do is this instead:


listBox1.Items.Add(new ListItemWrapper(“Craig“, new Customer(“Craig“, 32)));


Which allows me to have any arbitrary text associated with any arbitrary item. Because ToString is overridden to return the text we choose for each object, the ListBox will display what we want it to. And retrieving the item is as simple as casting to ListItemWrapper and then just accessing the Item property.

Friday, April 23, 2004

Announcing FwContrib

If you read this blog regularly, you know that I spend a reasonable amount of my spare time contributing to the FlexWiki project. You also know that although I think it's a cool project, I hate the fact that the source code is hosted at GotDotNet. Well, we're looking at doing something about that, but it's going to take a little longer than we hoped. So in the meantime, I've relocated all the pieces that I have control over to a SourceForge workspace called fwcontrib. This includes:



  1. FlexWikiPad. A tool for writing wikis that live on your hard drive and don't require any web access. Great for organizing information and taking notes - sort of like OneNote, but uses FlexWiki syntax. I use it every single day.

  2. FwSyncA tool for automatically synchronizing a FlexWiki web site with a set of wiki files on your local hard drive. The synergy between this and FlexWikiPad is obvious, but even without FlexWikiPad this is handy if you want to do a bunch of wiki work offline.

  3. FwDocGen. A tool for generating a pile of wiki pages based on the XML comment files the C# compiler emits. Because FlexWiki has the cool ability to email you when pages on the wiki change, we're using this at one of my clients to set up a build process that maintain a wiki of code documentation that will notify you when something changes. This one still needs some work, but even as-is it's still fairly customizable.

  4. FlexWikiEmacsMode. A simple emacs major mode for editing FlexWiki files. Can be used in conjunction with FwSync to work offline.

  5. WikidPad2FlexWiki. A simple tool for converting the XML export of the very nice WikidPad tool to FlexWiki syntax.

Not all of these tools have been packaged for release yet, but they will be soon, and the source code is all there. 


I'm going to be working on the project to make all this stuff better over the coming months. If you have any feedback for me, be sure to log a bug or a feature request!

Wednesday, April 21, 2004

Constructor or Factory

I had an aha moment the other day. It's nothing that lots of people haven't already figured out, but it helped me see things more clearly, so I'm posting it here.


We were doing some design on some classes for the MSDN project I'm working on, and we were debating how to model a piece of content moving through the system. In the system we're working on, a content set (our term for a page and any other associated files or metadata) flows from the content creator, through a publishing pipeline, and into a database. From there, it's rendered out to the MSDN website.


The problem is that, when content is coming into the system, it starts life as a lump of XML. But when the content is being rendered, it starts life as a database record. Further, there are some properties of the content set that are only present at render time, and some that are only present when the content is being loaded into the the database. We were torn whether to have something like this:


public class ContentSetBase { }
public class DbContentSet : ContentSetBase {
  public DbContentSet() { }
}
public class XmlContentSet : ContentSetBase {
  public XmlContentSet() { }
}
public class ContentSetFactory {
  public DbContentSet CreateContentSetFromDatabase(db args) {}
  public XmlContentSet CreateContentSetFromXml(xml args) {}
}


or something like this:


public class ContentSetBase { }
public class DbContentSet : ContentSetBase {
  public DbContentSet(db args) { }
}
public class XmlContentSet : ContentSetBase {
  public XmlContentSet(xml args) { }
}


The debate was interesting. I was all for the second approach, since I didn't like mixing XML and Database goo in the same class - it just feels like bad separation of concerns. But there was that word...Factory...and it seemed like that's what it was, so it sort of made sense.


I'll admit, I'm not even remotely knowledgable about patterns, but the one I do have sort of a clue about is the factory pattern. You see it all over the place, and it's hugely useful. But here's the trick: it doesn't apply here. Why not? Because the calling code already knows what type of object it wants. Our database loading code always creates an XmlContentSet, and our web page code always creates a DbContentSet. The factory would only be really useful if we were doing something like this:


ContentSetBase cs = ContentSetFactory.Create(args);


and we didn't care whether we got back a DbContentSet or an XmlContentSet. In other words, an important part of the factory pattern is that the factory makes the decision about what type of object to create. In the factory above, the caller was making the decision by calling one or the other method.


Now, that's not to say that the code wouldn't have worked either way: it would have. But it makes more sense to me the second way, and realizing that rule is going to help me figure out in the future when a factory is appropriate, and when it isn't. And that's a useful trick to have in my pocket.


Oh, and in case you were wondering, in the end we wound up doing something else entirely, after figuring out a bunch of other constraints. :)

Process Explorer Rocks

I've long since replaced the venerable Task Manager with Process Explorer from SysInternals. It's just better in every way - from the fact that it will show you which process created which other processes to the fact that the column names actually mean something. But today I found out how truly cool it is.


My machine was thrashing on something, the CPU at nearly 100%. When I fired up Process Explorer, I could see that it was the mysterious “System” process. If I'd been using Task Manager, that would have been pretty much all I could tell. But with Process Explorer, I was able to right-click, bring up properties, and see that one particular thread was the offender. Further, I was able to see the call stack for that thread. On top of that, I was able to click a button to pull up details of the device driver that was using the CPU so heavily.


Love it.

"Creating a Vertex Buffer" Direct3D Tutorial Danish Translation Available

Micael Baerens has kindly translated another of my Direct3D tutorials into Danish. You can find “Oprettelse af et VertexBuffer objekt” (Creating a VertexBuffer) here.


Much more of this, and I will be shamed into writing another one in English. :)

Monday, April 19, 2004

Page 23 Meme

Via Ian, I saw this meme doing the rounds of various blogs. It tells you to do this:



Grab the nearest book. Open the book to page 23. Find the fifth sentence. Post the text of the sentence in your journal along with these instructions.


My nearest book was “Clanbook Nosferatu”, which, on page 23, says



That's part of where we got our sinister reputation.  


 

Sunday, April 18, 2004

Snake!

So, I was sitting at my computer in my basement office, reading my email. I became vaguely aware of something on the wall directly behind my monitor. After a few seconds, the small part of my brain that isn't devoted to what the computer is doing sent a bit of an alert: “Hey, that thing on the wall is moving.” The alert kicked up to Infrared Level 5 when I realized it was a two-and-a-half foot long snake!


My wife heard me exclaim something unprintable, and came down to find out what was up. We sort of stared at it for a while as it made its way slowly up the unfinished wall. Eventually, we figured out that the best thing was to just go ahead and grab it and let it go outside. I put on my work gloves and got ready to do the deed, but the closer I got to it, the slower I moved. A bit like Xeno's Paradox, really. Eventually, my wife got tired of waiting for me and took the gloves and grabbed it herself. She rocks.

Saturday, April 17, 2004

Direct3D Tutorial - French Translation

The most popular thing on this site continues to be my Direct3D tutorials. And yes, I do intend to write more at some point.


At any rate, the first few of these are now available in French, thanks to translation by Kershin. Keep 'em coming, dude!

Friday, April 16, 2004

Wanna See Where I Work?

I finally got over to Channel9 to check out the video tour of MSDN that Chris Sells did. It turns out the tour was of the particular part of building 5 where the work I'm doing for MSDN is based. Since I know you're dying to know, I'll reveal that when I'm there, I share an office with the Kim that you hear him mention in passing, right across the hall from Tim Ewald's office.


Chris does the tour with his usual charm, and you can briefly meet the people like Priya and Rangan that I'm working with to build the next generation of - to paraphrase Chris - the biggest developer-oriented website in the world.

Wednesday, April 14, 2004

Best Auction Ever

My sister sent this to me. Hilarious. The link, that is. Although my sister is hilarious too.

Monday, April 12, 2004

Beware GoogleBot

I get notifications via email whenever anything changes on the FlexWiki wiki. It's one of the coolest features of FlexWiki, IMO, because I like for notifications to arrive via email/RSS (they're the same to me because of NewsGator). Anyway, it's often my habit to review the changes that have been made to the wiki while going through my morning mail.


Today, I saw something annoying. Somone had gone through and changed a massive number of pages on the wiki, including some of the pages that I'm responsible for maintaining. I went to the wiki and found that my pages had been rolled back to previous versions. It was the work of only a few seconds to restore them to their correct condition, but I was bothered that someone had changed it out of malice or out of ignorance. The more so since it looked like they'd done the same to dozens of other pages.


While I was there, I noticed that David Ornstein, the spiritual leader of the FlexWiki effort, had made some changes to the site layout using his new and ultra-cool WikiTalk engine. Hoping that error and not vandalism was at the root of the problem, I threw a question out on the FlexWiki mailing list to see if perhaps that was the issue.


Not too much later, Tommy Williams, another FlexWiki contributor and a really bright guy, came up with a theory. If he's right it's a doozy!


Tommy noticed that the IP address of the offender is owned by Google. So he figures that the GoogleBot came in and visited the “restore this page to a previous version” link that's on every page in the new layout (it used to be in a dropdown). And of course, we don't have any “hey Google, don't follow this link” magic on those pages. Although obviously we need some, even if that's not what happened in this particular case.


Take this as a warning. If you have any unprotected links to “delete” or “order” or “trigger webmaster's ejection seat” functionality on your webpages, and you're assuming that no human would mistakenly click on them, remember that not all visitors to your website are human.

Friday, April 9, 2004

Hacknot

If you're not subscribed to Hacknot, you should be. Pieces like this are pleasantly rational. Via Sam.

Good Article Series

I generally don't regret my lack of a formal CS degree. My EE background generally seems to have adequately prepared me to write software, as most of what you need to know, you don't learn in CS classes. Still, I do occasionally think about how it would be interesting to go back and take some classes, to learn some of the more formal stuff, like algorithms and data structures. Usually that's when I just go pick up a book on the topic and read it, to much the same effect.


Sometimes you don't have to buy a book, though. Today I was reading this series (particularly, the latest entry), and I really liked it. Choosing an appropriate data structure is an extremely common task in programming, and it's not always simple. For example, in just the last six months, I've had to deal particularly with how to represent directed graphs efficiently, and having read this beforehand would have been helpful.

Wednesday, April 7, 2004

New Lows in Home Improvement

One of the things I do when I'm not programming is work on the house. For the last year and a half, that has included gutting the basement, in preparation for rebuilding it newer...better...stronger.


As part of this process, I've busted a hole - about a meter square - in the concrete of the floor, to allow me to rip out and rearrange some of the lame-brained plumbing that's in place now. It's taken me weeks to make that hole (I don't exactly spend all my time on it), but I periodically show off my “progress” to friends when they come by.


Well, apparently one of them got the idea that I'm quite a bit more ambitious than my achievements to date would indicate. He sent me this.

Monday, April 5, 2004

Holy Crapoli

First Microsoft and Sun kiss and make up. Now this. They chose the IBM license, which - while not quite as easy to understand as my favorite, the MIT license - is pretty straightforward. Can't say I understand all the language about patents in it, but other than that it looks pretty simple.