Tech City Bowl Follow-up and Reviews on Blogs


I wanted to write a follow-up post to say that a manager from Tech City Bowl posted a comment on my blog only a couple of days after I posted my rant about an experience there.  He has offered a solution to our predicament that I feel is quite satisfactory, and he apologized that we were not better served when we were there the first time.

Xander will be able to go to Tech City Bowl to bowl his first game afterall.  Hopefully the staff is informed of how to address these types of situations better in the future.

Something I find very interesting about this situation is that only days after posting something to my blog about a poor experience, a manager from Tech City sought me out to resolve the situation.  Since I had heard from two employees that there was no way for Xander to bowl there, I didn't seek out management myself, as I didn't expect any satisfactory response; I posted the article on my blog to blow off steam, and I never would have expected Tech City to find the post, contact me, and offer a very nice solution.

This isn't the first time I posted a review on my blog to later be contacted by the vendor.  Garmin sent me a comment in response to my review of the Nuvi 660 we got.  I think it's great that companies actively seek out reviews posted to blogs.  I am a little curious what tooks they are using to find the reviews though.  Perhaps just googling, or maybe the Newsgator feature where you can create RSS feeds that perform web searches.

author: Jeff Handley | posted @ Friday, July 18, 2008 9:21 PM | Feedback (0)

Virtual PC – Drag and Drop Feature


Sometimes you just have to try something, even though you can’t imagine that it will work.  Usually, the result is slight disappointment that the software didn’t anticipate what you wanted to do, but occasionally the process yields pure joy.  Virtual PC just gave me such joy.

I have a virtual machine running on my right-hand monitor, and I needed to get a file from my physical workstation over to it.  I haven’t yet set up any shared drives, so I wasn’t sure of the best way to get the file over—in this case a VS 2008 settings file.  First I tried to open explorer on the physical machine, select the file and copy it, then paste it into an explorer window on the virtual machine.  I actually expected this to work and it didn’t.  Then I paused and wondered if I could drag the file onto the virtual machine.  Sure enough, you can!

I dragged a file out of an explorer window on my physical machine into a window on the virtual machine, and the file was copied over for me.  Beautiful!

Technorati Tags:

author: Jeff Handley | posted @ Wednesday, July 16, 2008 4:53 PM | Feedback (0)

Rant: Bowling alley frustration


As part of getting settled into Redmond, I thought it would be good to join a bowling league.  I haven't bowled in league for a long time due to wrist and hand pain, but I figured a few games a week shouldn't bother me too much.

Each week, Xander has asked if he could come bowling with me.  We told him that this week, we'd all go together to bowl a game before my league began.  As we got there, we decided we'd actually just have Xander bowl a game by himself, so that he could bowl his first-ever game.  The bowling alley I attend for league has a sign that says you must be 4 years old to bowl, and since Xander just turned 4, we thought we'd be all set.  We'd just pay for him to bowl one game, probably in his socks.  However, the plan fell through.

As it turns out, Tech City Bowl no longer lets you just pay by the game unless you're a league bowler.  Even though I'm a league bowler, my family doesn't qualify.  We had two options: "Bowl all you want for $13/person (shoes included)" or "$15/hour + $4 shoes."  This means that for Xander to bowl one game, it would cost $13!  But there's another catch too; they don't have shoes that fit him.  He wears a 7.5 and the smallest they have is a 9.  Without shoes that fit, you're not allowed to bowl.

I really hate telling the boys we're going to do something and then not being able to make it happen.  Fortunately, Xander took it in stride, but I was pretty ticked.  I thought Tech City Bowl was supposed to be a family-friendly bowling center!

I ended up talking to a lady that works there during league tonight.  She said that they discontinued the per-game pricing because prices had gotten to $6/game and they felt they were doing their customers a disservice with that price.  Seems to me they did me (and themselves) a disservice by turning us away when they had 25 empty lanes.

author: Jeff Handley | posted @ Tuesday, July 15, 2008 1:01 AM | Feedback (4)

My first Virtual PC under Vista or x64


It’s been quite awhile since I created a virtual PC; a couple of years probably.  This is the first time I tried to create one under either Vista or x64.  Here were some interesting findings…

I used the wizard to create the first virtual PC and its hard drive.  I booted to a Vista x64 install and walked through the first stages of the process with no problems.  After an hour to an hour and a half, it rebooted and I thought I was going to be well on my way to having my virtual PC ready to use.  I was wrong; instead I got a message that I was trying to boot to an x64-based operating system from a machine that doesn’t support 64-bit mode.  I didn’t note the actual message, but it was telling me that the virtual PC was actually a 32-bit machine, not a 64-bit one.  Time to start over.

I deleted the hard drive and recreated it manually.  I expected 10GB would be sufficient.  About 5 minutes later, I find that 10GB is not enough; it says that 13024MB (or something like that) is required.  Time to start over.

I deleted the hard drive and recreated it manually; this time at 15GB.  About 5 minutes later, I get back to the same screen for selecting the install drive.  Now it tells me that 17048MB (or something like that) is “recommended.”  Since I was previously told that what the requirement was, and I exceeded that, and this was just a recommendation, I thought I’d be able to get past this message, but I couldn’t.  Time to start over.

I deleted the hard drive and recreated it manually; this time with 64GB dynamically sized.  The installation is in the process of copying files (again).  Let’s hope that this time I’m in the clear! (yn)

Technorati Tags: ,,

author: Jeff Handley | posted @ Monday, July 14, 2008 2:23 PM | Feedback (0)

HP MediaSmart Home Server and Photo Sharing


We invested in an HP MediaSmart Server EX470.  This server will become where we store our documents, music, photos, video, and more.  One of the major draws for me was the photo/video sharing website that you get out of the box.  Our family website has been down for months because the “server” (read: old Pentium 2-450 Mhz box with a 20GB HD) has been offline.  So we are really eager to get a family website back online.  Our families are missing seeing the boys, so we want to at least show them some pictures!

Besides the hardware problems with the server we were using before, we also decided that we wanted to do something different for the website.  Previously, the site was completely public.  Anyone could jump on the site and view pictures of our family.  We’ve decided that probably isn’t the safest thing to do, so we want a password-protected site where we can invite friends and family members to log in.  Fortunately, the Webshare application that ships with the HP MediaSmart servers works in that manner, so I thought we’d be all set.

Alas, we’re not as equipped as I thought we’d be having that application.  First of all, after I installed the home server, I couldn’t log into the Webshare site.  No matter what I did, it rejected my username/password.  It rejected the account I set up for Kelly too.  No matter what I did, I couldn’t log in.  After googling around, I found that I was not the only one that couldn’t get Webshare to work.  I didn’t see anyone else that could not log in AT ALL, but I found several reports of login-related problems.

One solution I saw someone use was to do a factory-reset on their home server.  Reinstall everything, wiping the data drives.  At a loss for any other options, I went that route.  This required that I pull all of the data back off that I had already moved over there.  This was a 2-night process as I already had many gigs of data moved over.  (Note, moved, not copied).  After reinstalling everything, I was able to get logged into Webshare, but it thought my user account was a visitor, not a manager.  This is what I had previously found reports of.  And when I created Kelly’s account, it didn’t work in Webshare.  What a joke!!

I ended up finding this topic that gave a solution that involved running the postgreSQL command-line tool and manually correcting the Webshare database.  I thought, “Are you kidding me!?”  This is a brand new server, installed cleanly, with the users set up exactly as the setup guide told me to, and I have to hack at the database manually in order for it to freaking work!  GRRRR!!

Sure enough though, this did the trick: (found from here, thanks DullingWine!)

Do remote desktop to your home server
Get a cmd prompt running
cd c:\Program Files\PostgreSQL\8.2\bin
psql.exe -U postgres
\c sj
select * from users;
You should see yourself in the table - make a note of your userid
The update:
update users set manager='t' where userid=your_id;

I was able to insert Kelly’s account that way too, so she’s up and running now as well (she just doesn’t know it yet).

Once I finally got into Webshare, I started poking around.  It looks pretty standard.  Create albums, upload pictures, invite people, blah blah blah.  What I didn’t see that I had expected, was a way to just say, “Show all of the photos and videos that are sitting right here on the server.”  Instead, it wants me to upload all of the pictures – but they’re already on the same machine.  I’m not going to like that one bit.

So here’s my dilemma… do I force myself to use this Webshare thing, even though it doesn’t work the way I want it to (and it seems to barely work anyway)?  Maybe I’ll learn it better and grow to like it.  Or do I create my own website and drop it on the box?  Here are some features of our old website that I’d certainly want to use again:

  1. No need to create albums.  It just showed a tree of pictures in the library, organized by year, month, day.  You could view slide shows of months or days.  The photos were discovered by looking at disk to see what files were there.
  2. I built a console application (and some batch files) that allowed us to just plug the memory card from the camera into a USB port, double-click an icon, and it would do the following:
    1. Move all files off the memory card an onto local disk
    2. Tell you when this was completed so that you could take the card back and be on your way – it was typically under 5 minutes for a full 1GB card dump
    3. The videos were all copied over to a videos share (but not published online)
    4. The photos were parsed for camera orientation, time and date.  Then the photos were rotated to put them in the correct orientation for screen viewing, and the files were renamed giving them a date/time stamp filename.  Thumbnails were also created.
    5. Thumbnails and rotated/renamed photos were copied over to a photos share as well as to the web server

This process had a very high WAF (Wife Acceptance Factor) – just plug it in, click an icon, and it tells you when it’s done.  Maintaining the high WAF is a must.  But there are some changes that I would want from the new website too.

  1. Ability to browse photos without having to go through a slide show, but provide the slide show to users too
  2. Ability to either browse all photos or browse by album
  3. Automatically create albums when photos are added; for instance a “Photos added on 7/10/2008” album.
  4. Allow custom albums to be creating using the existing files, with no need to copy/upload files
  5. Allow tag-based albums (might also serve as #4), where photos can be tagged with a list of keywords
  6. Allow a note/description to be entered for a photo
  7. Password protected access
  8. Inclusion of videos, encoded to something other than AVI (which is how the camera records them)
  9. Invitations, notifications, and all of that goodness

Additionally, I would want the website to run over HTTP (as our old one did) instead of HTTPS (as Webshare does).  I don’t want to mess with SSL certificate warning messages or anything, and I don’t see the point in encrypting the photos and videos as they move over the wire.

If I were to create a new site for us, I’d (of course) build it in Silverlight.  There will be a little bit of friction for our visitors as they’ll have to install Silverlight, but the user experience would be worth it.  Silverlight could allow for a clean inclusion of videos with the photos, so long as I can encode them properly.

I will probably end up creating the site.  I’m thinking about starting an open source project for this, unless someone can point me to an existing one that gets me close.

author: Jeff Handley | posted @ Thursday, July 10, 2008 6:40 PM | Feedback (2)

Binding to Nullable Values in XAML


I stumbled upon some behavior awhile back that struck me as odd.  I had a nullable property in my ViewModel that I was binding to in Silverlight, but I found that whenever the value was cleared out by the user, the property setter was not called.

I narrowed it down to a simple application that has properties for Name and Age, as follows:

   1: public string Name
   2: {
   3:     get { return _name; }
   4:     set
   5:     {
   6:         if (value != _name)
   7:         {
   8:             _name = value;
   9:             this.RaisePropertyChanged("Name");
  10:         }
  11:     }
  12: }
  13:  
  14: public int? Age
  15: {
  16:     get { return _age; }
  17:     set
  18:     {
  19:         if (value != _age)
  20:         {
  21:             if (value.HasValue && (value != 30))
  22:             {
  23:                 value = 30;
  24:             }
  25:  
  26:             _age = value;
  27:             this.RaisePropertyChanged("Age");
  28:         }
  29:     }
  30: }


I then have XAML binding to these properties like this:

   1: <TextBox Grid.Column="0" Grid.Row="1" Text="{Binding Name, Mode=TwoWay}" />
   2: <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Age, Mode=TwoWay}" />

Then, I followed these steps, getting the stated results:

  1. Type in a Name, hit [Tab] – Get a PropertyChanged event for “Name” with the name I typed in
  2. Type in an Age, hit [Tab] – Get a PropertyChanged event for “Age” with the age I typed in
  3. Clear out the Name, hit [Tab] – Get a PropertyChanged event for “Name” with an empty string
  4. Clear out the Age, hit [Tab] – Nothing!

As it turned out, the property setter for Nullable<int> Age doesn’t get called when the value in the textbox is empty.  Nothing converts empty string into a null.  The interesting part of this is that if I had a button on the form, invoking a method on my ViewModel, when that method is invoked, the ViewModel would still have the original age value that was supplied, not knowing that the textbox had been cleared out.

I found this to be quite disturbing and I mentioned it to a couple of people, and they too were surprised by this behavior.  But when I talked to Mitsu Furuta about it, he set me straight.  He explained that Binding takes a very safe approach to calling property setters.  Unless it knows the property setter will succeed*, it won’t call it.  Therefore, Binding won’t call the property setter for blank values when it thinks the value is supposed to be something that it cannot supply a blank to.  I realized that Binding cannot supply null to the property setter because the value isn’t really null, but rather an empty string.

Mitsu then showed me how to get the behavior that I wanted: create a NullableValueConverter, like this:

   1: public class NullableValueConverter : IValueConverter
   2: {
   3:  
   4:     #region IValueConverter Members
   5:  
   6:     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   7:     {
   8:         return value;
   9:     }
  10:  
  11:     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  12:     {
  13:         if (string.IsNullOrEmpty(value.ToString()))
  14:             return null;
  15:  
  16:         return value;
  17:     }
  18:  
  19:     #endregion
  20: }


Very Simple!  Now, I just change my markup to use the converter.  This is a 2-step process where I first have to define the converter in my resources (can be done once, application-wide) and then specify that converter in my binding.

   1: <UserControl.Resources>
   2:     <local:NullableValueConverter x:Key="NullableValueConverter" />
   3: </UserControl.Resources>
   4:  
   5: ...
   6:  
   7: <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Age, Mode=TwoWay, Converter={StaticResource NullableValueConverter}}" />


Note that when you bind to a property that is a string, and you clear the value out, the property setter is called with an empty string, not with a null.  So you could use this converter for string bindings too, allowing you to get null in your property setter if desired for consistency.

This behavior and solution work the same in both WPF and Silverlight 2.  If you’d like to tinker with this, I have uploaded a demonstration solution here (VS 2008).  It has both a Silverlight (Ag) project and a WPF project.  Both of them are using the NullableValueConverter, but if you take that converter off of the binding, you’ll experience the behavior that could easily lead to bugs in applications.

Of course, now that I understand this behavior better and know that value converters are the key, I found a plethora of resources that discuss this.

* Saying that Binding “never” fails is hyperbole.  I’m sure you can make it fail if you try to.

author: Jeff Handley | posted @ Wednesday, July 09, 2008 2:07 PM | Feedback (0)

Custom Controls Everywhere – In XAML


You’ve heard me preach it before.  Custom Controls Everywhere, damn it!  It’s my mantra, my MO, one of my core beliefs for application development.

As I started getting used to XAML, I kept thinking about how I’d implement custom controls everywhere and utilize the pattern in the same way I have before.  Since the concept applies equally well to ASP.NET and WinForms, I of course assumed that I would want to apply it to XAML (either Silverlight or WPF) too.  However, while actually doing my work in XAML, I restrained from creating custom controls right off the bat, instead waiting for the indication that I’d actually need them.  I knew the time would come, but I wanted to wait until the last responsible moment to implement them, making sure that I was implementing them A) for the right reasons; and B) in the best manner.

Well, I’m about 2 months into working with XAML now, and I am yet to find a need for using custom controls everywhere.  The stock controls are working quite nicely, and when they lack some sort of presentation or behavior that I want, styles, attached properties, and attached behaviors come to the rescue.  With the combination of these 3 techniques, you can pull off some amazing things with stock controls.  Attached properties and behaviors are just really, really cool.  They are what ASP.NET and WinForms have been missing, and what I think is the key to being able to discontinue custom controls everywhere.

So I’ve now ridded myself of the instinct that a Silverlight developer would want to create custom controls everywhere when creating a Silverlight-based application.  Just use the controls you have, apply styles, and attach properties and behaviors.  And if you find a case where this falls short, let me know!

author: Jeff Handley | posted @ Monday, July 07, 2008 5:05 PM | Feedback (0)

Starting to get LINQ


I’m finding that I’m using LINQ more and more for simple problems that would otherwise have longwinded solutions.  The brevity that LINQ offers is pretty powerful, and I appreciate that LINQ allows me to express what I want clearly and get the desired result.

One example today was when working with a custom calendar control that has a list of selected Days.  A Day is also a custom control, and it has a Date property.  I wanted to convert the list of selected Day controls into a list of selected dates.

The selection is a single range of dates, so my instinct was to find the minimum date from the list of selected days, find the maximum date from the list of selected days, then loop, adding each day’s date into a new list.  Here’s what I came up with in about a minute:

Please note that DateTimeList is an alias to ObservableCollection<DateTime>

   1: DateTimeList selectedDates = new DateTimeList();
   2: DateTime start = new DateTime(_selectedDays.Min(day => day.Date.Ticks));
   3: DateTime end = new DateTime(_selectedDays.Max(day => day.Date.Ticks));
   4:  
   5:  
   6: while (start <= end)
   7: {
   8:     selectedDates.Add(start);
   9:     start = start.AddDays(1);
  10: }

That felt pretty good.  I was able to just use Min and Max to find the bounds, and then loop over the range.  But I had a feeling that LINQ could do me one better, and sure enough, it did:

   1: DateTimeList selectedDates = new DateTimeList();
   2: _selectedDays.ForEach(day => selectedDates.Add(day.Date));


I have a feeling there’s an even more succinct way to accomplish this task.  Any suggestions?

Technorati Tags:

author: Jeff Handley | posted @ Wednesday, July 02, 2008 5:01 PM | Feedback (0)

This alias is either really cool or just plain wrong


I was working in a custom control today that exposes a dependency property of type System.Collections.ObjectModel.ObservableCollection<System.DateTime>.  After typing that type name a few times I decided it was time for a using statement at the top of the file to shorten things up.  But even ObservableCollection<DateTime> is pretty long.

I recalled reading about how applying the using statement to create aliases.  I wasn’t sure if it would, but sure enough, the following worked like a charm:

   1: using DateTimeList = System.Collections.ObjectModel.ObservableCollection<System.DateTime>;

That lets me declare my property as a DateTimeList, shortening up the syntax significantly.  Here’s a comparison.

With a typical “using System.Collections.ObjectModel”:

   1: public static ObservableCollection<DateTime> GetSelectedDates(Calendar calendar)
   2: {
   3:     return (ObservableCollection<DateTime>)calendar.GetValue(SelectedDatesProperty);
   4: }

With the DateTimeList alias:

   1: public static DateTimeList GetSelectedDates(Calendar calendar)
   2: {
   3:     return (DateTimeList)calendar.GetValue(SelectedDatesProperty);
   4: }


The usage feels really nice, but I wondered what others think.  Is this alias really cool or just plain wrong?

author: Jeff Handley | posted @ Wednesday, July 02, 2008 4:44 PM | Feedback (1)

Stoked about the NIN concert


I had always enjoyed Nine Inch Nails’ music.  But it wasn’t until Kelly explained to me that NIN is really just one guy, Trent Reznor, that I really became a fan.  Frankly, when Kelly told me about this, at first I didn’t quite believe it.  But then I went and read up on Trent and NIN, and was blown away.  What Trent does and how he composes his music is very unique and impressive.  I’ve now become addicted to his music.

Kelly saw a NIN concert several years ago and has said it was simply amazing.  When the 2006 tour dates were announced, we talked about going.  In fact, we considered going up to Atlantic City for the show at the House of Blues, but ultimately we didn’t go.  Just about the time we moved out to Redmond, NIN announced some 2008 tour dates, and Seattle is the 2nd stop on the tour.  We talked about how cool it would be to go, but of course we don’t have any sitters out here to stay with the boys.  So we emailed Kelly’s mom and said that if she wanted to make a trip out to see us, it would be great if she could do so over the week of the concert.  We didn’t expect her to say, “OK,” but she did!  And we bought tickets right away!

I’m totally pumped about the concert.  Recently, NIN started releasing videos of rehearsals for the tour, and they are awesome.  I simply cannot wait to go.

author: Jeff Handley | posted @ Wednesday, June 25, 2008 11:08 AM | Feedback (0)