Interesting solution to a WPF resource location issue

Design-time is one of my hobbies, and I’ve been fooling around with the WPF designer ("Cider") lately.  I’ve been making adorners do interesting things for the most part and havent fooled around with property editors much, which makes me kind of useless for Blend.

A pattern I’ve been following involves structuring my projects with a folder for each control I’m providing support for.  Each folder has its own resource dictionary in a Resources.xaml file, and the Themes/Generic.xaml includes all of them as a merged resource dictionary.  It works great, but I recently had a problem, couldn’t find the solution, and now that I know what went wrong I want search engines to help others out.

My metadata was loaded correctly, but none of my templates were being applied to adorners.  I thought something was wrong with the merging of the resource dictionaries, so I tried moving a template into Generic.xaml; no dice.  Nothing I did seemed to be making the project pick up the template.  I set up some small proof-of-concept projects, and couldn’t find anything visibly different about what was wrong.  The end of the day arrived and I decided I’d just delete the project and try again tomorrow.

Tomorrow became today, and the project was magically working.  I called a coworker over to witness the event, and he began to point at my project.  "Why do you need that junk in Properties; it’s a class library and you won’t use application settings and resources?"  I agreed; yesterday I’d deleted them too.  In fact, early today I had deleted all of them but our source control decided they were important and resurrected them.  I’m glad it did.

It turns out that in AssemblyInfo.cs, which I clicked on for kicks, there is a ThemeInfoAttribute that tells the project where to find the non-themed and themed resources.  If it’s not there, whatever is supposed to look for Generic.xaml doesn’t look there.  Oops.  When I deleted AssemblyInfo.cs, I broke the theming!

So, if you’re depending on themed or non-themed resources in WPF, don’t delete AssemblyInfo.cs!  Or, if you do, make sure to apply an assembly-level ThemeInfoAttribute somewhere else.  Don’t waste half a day like I did!

Testing Source code posting

Supposedly there’s a markup element for posting code on WordPress blogs.  This is just a test; I’m actually planning some big posts and it will determine if I use the blog or just link to a static page.

public void DoSomething()
{
     MethodCall();
}

Welp, either I did something wrong or WordPress lied to me. I’ll try upgrading this weekend.

*Update:* Turns out I needed to manually install this syntax highlighter.

MSDN’s Community Features Really Suck

I really, really hate to complain about a very large piece of software because I understand the difficulties involved in developing such a thing.  I also don’t like offending people, as I know when people say “x sucks” and there is an author of x then that author can’t help but get their feelings hurt.  However, I feel like the community features are an afterthought at Microsoft’s MSDN site, and I’m really tired of trying to deal with it.  Maybe someone will read this and fix it, but I doubt it.

First, I don’t understand why MSDN is so slow.  I understand it’s a large site servicing thousands of connections per minute, but so is Amazon and somehow I don’t have 10-second delays when accessing that.  OK, fine, Amazon targets a different audience and perhaps their software can be optimized.  That doesn’t explain why if I simultaneously try to visit a blog hosted on Blogger and MSDN, the MSDN blog is still loading 10 seconds after the Blogger page is done loading.  This is true for all parts of the MSDN site: blogs, forums, newsgroups, technical documentation.  What’s the deal?

Next, some community features.  The forum software is pretty neat, but new categories are added at a glacial pace and they’re really dated.  The VS 2008 forums were clearly marked for “discussion of the Visual Studio Codename Orcas Beta” at least until VS 2008 SP1 was released.  I’m just glad there’s a couple of them devoted to WPF.  However, so far I’ve got about 4 active questions with 0 replies; at least in the WPF design time forum (which they still call by its codename for some reason) it looks like the only way you have a chance of getting a reply is to ask a simple question like, “I haven’t opened Visual Studio yet and I need to.  How do I do this?”  So far the most use I’ve gotten out of these forums is a good place to arrange my thoughts while I arrive at the solution myself.

The managed newsgroups are worse.  As part of the MSDN subscription my company purchased, we’ve got guaranteed response times to questions on the MSDN managed newsgroups.  Except it doesn’t look like they’ve updated their newsgroups in a while; there’s no newsgroups for WPF and not even a really good-looking place to pretend is associated with it.  That doesn’t matter though, because it’s impossible for me to configure my MSDN managed newsgroups account.

If you want to get the guaranteed response you paid for, there’s a process you go through to associate an alias with your MSDN account.  I presume this is so some automated tool they have can ping an appropriate person to find someone that can respond to the question.  Since June 2007, when I tried to access this page, I’d get an error message after a 2-3 minute delay; the message basically said “something unexpected happen; try again in 10 minutes”.  A couple of weeks ago, I got tired of it and used the concierge chat to see if maybe I was doing something wrong; it turns out the “Configure” link was broken for everybody and it had to be fixed.  Go figure; a crucial link on a feature they charge money for was completely broken and it went nearly 2 years unnoticed.  It got fixed in a couple of days, I configured a posting alias, then realized that I had found the answer to the question I wanted to ask through trial and error anyway.  Today, I needed to ask a question, so I double-checked that my alias was configured.  “No alias configured.’”  Huh.  Weird.  So I tried to configure it again.  “We’re sorry, this alias is already in use.”  Huh.  Real weird.  So I tried another alias: the old one with a 1 on the end.  5 minutes of waiting later, “There was a problem connecting to the registration service.  Try again in 10 minutes.”  Hey, this sounds familiar!  10 minutes later, I try again with the new 1-suffixed ID.  “We’re sorry, this alias is already in use.”  CURSES! So it seems that if I try to register an alias, it fails for an unspecified reason.  However, it does get so far as to registering the alias because after I get that unspecified error the next error tells me that my posting alias is already in use.  Shouldn’t this be a transaction that’s rolled back on failure?

I tried the concierge chat again, and the person confirmed this is a “known issue with volume license subscribers” and is “intermittent”.  Funny, I’ve been barred from this feature for more than a year and it’s described as an “intermittent” issue.  I wonder if there’s a word for the practice of selling a service but making it so difficult to obtain the service that it’s not used?  Surely someone’s been in trouble for it.

I’m genuinely frustrated here.  The best resource for information about programming is other programmers, and MS has the framework in place to create a really great community of developers.  However, they’ve chosen to needlessly obfuscate the communication process to the extent that I’m getting better answers from programming accidents than the MS “community”.

Also protip if any MS employees decide to reply (occasionally it happens!): if you want me to contact you by email it is dreadfully important that you leave an email.  Someone responded to some WPF comments I had one time and expressed an interest in an email discussion, but didn’t leave an email.  No email on his blog either.  If you don’t leave contact information I can’t contact you.

An open letter to NBC

Austin’s NBC affiliate KXAN is having a fun time playing victim because Time Warner isn’t paying some fee for the honor of carrying an NBC affiliate.  While KXAN was whining about how unfair it is they neglected to mention what other networks are being paid by Time Warner, leading me to suspect the sum is somewhere around zero.  I have plenty of choice words to say about this, but that is not what has agitated me.

Since I can’t watch NBC on TV, I use your website to watch the shows I want to watch (take THAT, local advertisers!)  In return for this service, I have to watch online commercials as part of the viewing process.  This is generally well-done, though occasionally it seems like the ads cut in a little earlier than they should and lines of dialog are missed.  This is still just background.

What CHUCK! agitates me CHUCK! is a CHUCK! commercial for CHUCK! some lame show CHUCK! that I don’t CHUCK! even CHUCK! want to CHUCK! watch.  The CHUCK! commercial in CHUCK! question is for CHUCK! the CHUCK! CHUCK! show Chuck CHUCK!.  It involves some kind of CHUCK! music with CHUCK! occasional CHUCK! interjections CHUCK! CHUCK! of characters CHUCK! screaming the CHUCK! titular CHUCK! name CHUCK!.  I see this CHUCK! commercial CHUCK! at least 5 times CHUCK! per viewing, CHUCK! and it’s CHUCK! really aggravating that CHUCK! it CHUCK! both has an CHUCK! annoying sound and CHUCK! CHUCK! plays with a volume CHUCK! significantly louder CHUCK! than the show I’m CHUCK! watching. 

The commercial covers a few really lame jokes, and after seeing it multiple times in a row I’m pretty certain that Chuck isn’t the show for me.  I’m sure the ad’s creator is confident that it’s "attention getting", but in this case the ad only draws attention to the fact that I’ve already seen it dozens of times, the jokes were stale the first time I saw them, and I don’t like the commercial.  On the TV, I just mute during commercials and the problem’s solved, but I’m a bit more captive at my computer and it’s easier to just wait out a commercial.  It has driven me to the point where even if I accidentally started watching Chuck, the first time someone said his name I’d think of the commercial and change the channel.  Perhaps you could do some work to ensure your viewers don’t have to watch the same commercial too many times in one viewing session, and also pass along to your advertisers that some viewers are less inclined to ignore ads in the online viewer because it’s inconvenient.

Thanks.

Annoying Dialogs

Every now and then, Visual Studio’s busy doing something it feels is really important, and I end up seeing this dialog:

VS Delay Notification dialog

The dialog is trying to be helpful.  It’s telling me that VS is busy, and it gives me three choices: switch to the application that’s holding things up, wait a little longer, or cancel the operation that caused the delay.  I have never seen the “Cancel Operation” button be a valid choice.  “Switch To…” is worthless because 9 times out of 10 VS is the application that is causing the delay.  So, this dialog is little more than VS making fun of me and telling me that I’ll just have to wait for it’s oh-so-important mystery operation to complete.

What I hate about the web these days

Let’s assume that I’m looking for information on some fringe programming topic that doesn’t have a lot of pages with content.  It might be something like the new D3DImage class in WPF that allows you to render DirectX content on a WPF surface, and whether there’s a way to make it work with the XNA framework and thereby avoid having to write managed code (not all shops have people proficient in writing managed code.)

So I ask Google to tell me what it knows about this; looks like a few results, right?  The first two I see are a The Code Project article and the MSDN documentation, which seems like a pretty good first two results.  Buried in the results is a forum post with a user asking about using SlipDx with the D3DImage.  The rest of the results are nothing but blog posts, forum posts, and news posts with nothing but "Dr. WPF wrote an article about this, here’s the link:"

Isn’t Google supposed to be smart?  Why can’t it filter out blog entries with non-ad content of less than 20 words?  I have to wade through a sea of these blog posts which are nothing more than internet trash to find any articles about what I’m interested in.

Weird Terminating Error Behavior

I’m writing a dirty hack PowerShell provider so that I can have a reasonable base of knowledge before approaching something more work-oriented.  One component of the path the provider accepts must be an integer, so I decided to throw a terminating error if the path does not follow this rule. I also decided I’d do this so I could examine how terminating errors are handled. Something that mystifies me is the terminating error isn’t behaving as I understand it.  Here’s the code I use to throw the error:

var record = new ErrorRecord(new ArgumentException("path"), "InvalidItemIndex",
                           ErrorCategory.InvalidArgument, null);
var details = new ErrorDetails("The second element of a text file path must be an integer.");
record.ErrorDetails = details;
ThrowTerminatingError(record);

I expect that I’d see the information in the ErrorDetails property in some way, based on how the documentation is written; instead it seems like this information gets lost somewhere:

PS C:\Documents and Settings\myUsername\My Documents> get-item text:\Section1\item1
Get-Item : The second component of the path must be an integer.
At line:1 char:9
+ get-item  <<<< text:\Section1\item1
PS C:\Documents and Settings\myUsername\My Documents> $error[0].ErrorDetails -eq $null
True
PS C:\Documents and Settings\myUsername\My Documents>

Maybe it’s fixed in PowerShell v.2.0, or maybe I’m doing something wrong, but this is definitely not what I expected.

Writing Objects from PowerShell Scripts

I’m going to continue writing about PowerShell because it’s fun to talk about and fun to use.

Today I decided to try and analyze some data in text files using a PowerShell script. The files were simulations of a betting strategy in a coin-toss scenario. The first line represented the final balance and every line thereafter represented the balance after a bet was completed. I was interested in the average balance over time and the average minimum balance for all files. The script itself was pretty uninteresting until I got to the output:

$files = get-childitem *.txt
$sum = 0
$count = 0
$minSum = 0

foreach ($file in $files)
{
    Write-Verbose "Processing file: $file"
    $sum += [long](get-content $file -totalCount 1)
    $count += 1
    
    $values = get-content $file
    $minimum = 0
    
    foreach ($line in $values)
    {
        $value = [int]$line
        $minimum = [Math]::Min($value, $minimum)
    }
    
    $minSum += $minimum
}

$average = $sum / $count
$averageMinimum = $minSum / $count

Now is when it gets fun. I originally just wrote the output using write-output:

write-output "Average: $average"
write-output "MinAverage: $minAverage"

This didn’t seem very PowerShell-like. I wanted to output an object that could be used by other scripts (for the heck of it at least.) I knew how to do this from a cmdlet, but had to search to find how to do it from a script. There seems to be two ways to make objects or object-like things to write.

Associative Arrays

Perl hackers love their hashes, and with good reason: this little data structure is very powerful. In the .NET world, we call them "dictionaries" for some reason. PowerShell associative arrays are declared with this syntax:

$array = @{name = value; name2 = value2}

If I wrote one of these using write-object, I got a nice list format with headers and could access the individual values via property syntax. Joy! Still, this isn’t really what I was looking for because I was really fishing for a way to output a PSObject.

PSObjects

You can create a PSObject using New-Object, but at first I couldn’t figure out how to let this object know it should have the properties I wanted. This is something you can use Add-Member for. You have to specify the type of member you are adding, and I believe the valid member types are listed in the PSMemberTypes enumeration. In this case, I needed NoteProperty since there’s no base object:

$output = New-Object PSObject   
$output | add-member NoteProperty -name Count -value $count
$output | add-member NoteProperty -name Average -value $average
$output | add-member NoteProperty -name AverageMinimum -value $averageMinimum
write-output $output

Expanding Wildcards in PowerShell

Yesterday I thought I’d jump into the deep end of PowerShell and try to make a provider; this lets you treat some data store as a drive in PowerShell.  It didn’t work out very well, mainly because I had no plan and just kind of hacked my way around it.  I didn’t want to do an AccessDB provider like the MS one and came up with the idea of a provider that treated each line of a text file like an item.  I kind of got overwhelmed with new information and decided to put it off for a bit.

So I switched to cmdlets today, since there’s a lot less planning involved in making some kind of cmdlet that does something.  The one I’m making takes Path and LineNumber parameters, then tries to retrieve the line of text corresponding to LineNumber from the indicated files.  I wanted to be fancy and accept wildcards in the Path parameter, and found that most people talking about wildcards are using a different approach to them than what I needed.

What You’ll Find

It seems like most people who talk about wildcards on the internet are excited about the WildcardPattern class.  I can see why.  Suppose I have a list of things I want to process and the user has given me a wildcard pattern to specify what items are important; if you don’t mind LINQ this is all it takes to prune your list:

var options = WildcardOptions.Compiled | WildcardOptions.IgnoreCase;
var pattern = new WildcardPattern(userPattern, options);

var matchedItems = from item in itemList
                   where pattern.IsMatch(item)
                   select item;

That’s awesome; I don’t have to bother processing wildcards.  However, it’s only useful if you have the list of items in the first place.  In my cmdlet, the user can pass me any arbitrary path with wildcards and I need to fill in the blanks.  The internet led me to believe this was the only wildcard processing in place, so I was looking at having to traverse the file system to make the list, then apply filtering.  Yuck.

What I Needed

One of the things I like about PowerShell is I can tell MS really stands behind it and wants it to become the new command-line.  The Cmdlet Development Guidelines are already up; compare this to other exciting technologies like WPF which get guidelines way after they’re released (I haven’t found any WPF ones, sadly).  Anyway, I was looking over these guidelines and found what I needed under the section "Support Windows PowerShell Paths".  The SessionState.Path property is a PathIntrinsics instance that has several useful methods that do the wildcard expansion for me.  For example, assuming I just happen to know the path is a PowerShell path, I can write this code:

ProviderInfo pInfo;
var resolvedPaths = SessionState.Path.GetResolvedProviderPathFromPSPath(FilePath, out pInfo);

Now, resolvedPaths is a Collection<string> of every path name that matches the wildcards in the parameter.

One thing I’m curious about is what to do with this.  My Path parameter is an array, as recommended by the design guidelines.  My plan was to loop over all of the parameters, get the expanded paths, then get the indicated line numbers from each item.  But I’m curious: is it wrong to do this expansion in BeginProcessing and replace my Path property with an array of fully-expanded items, then loop over that in ProcessRecord?  It seems wrong to change the value of the user-provided parameters, but for some reason I don’t like the nested for loops that doing it all in ProcessRecord would require.  I wonder if there’s a better way?

Working with Enumerations in PowerShell

Two posts in one day should show you I’m excited about PowerShell.

I wanted to update the script from my last post to find my My Documents folder so if I hop to Vista I won’t get an error, and I found it slightly difficult to figure out how to use Environment.GetFolderPath because I got a lot of errors trying to use the Environment.SpecialFolder enumeration.  It turns out if you pass the string value for the enumeration value you want, you get basically what you want:

$myDocs = $myDocs = [System.Environment]::GetFolderPath("MyDocuments")
Set-Location $myDocs
Set-Variable -name home -value $myDocs -force

Apparently, you can also use flags enumerations.