Saturday, December 17, 2011

Convert Mac Pages to HTML in Powershell


# A very crude Mac Pages to HTML converter in Powershell
# Preserves no formatting save for line breaks.
# Useful to extract the text so you can paste into Word

# A .pages file is a Zip; extract it to get the index.xml file 
# and parse out the paragraphs. 
# Note there's also a preview.pdf in the zip if all you need is to print.

# Pass the .pages file on the command line
# .\Pages-ToHtml.ps1 '.\Path\To\File.pages' > Converted.html
#
# Requires PSCX
Import-Module PSCX
$file = (Read-Archive $args[0] -format Zip ) | Where-Object { $_.Path -ieq "index.xml" } | Expand-Archive -PassThru
$xml = [xml](Get-Content $file)
$layout = $xml.document."text-storage"."text-body".section.layout
# Stripped of all formatting
#$layout.InnerText
# Write paragraphs only
$layout.p | ForEach-Object {
    echo "<p>"

    $_."#text"
    echo 
"</p>"
}

Saturday, July 02, 2011

How to require SSL in IIS7 and Azure with Rewrite

imageThis is a tidy solution. Instead of requiring SSL (and giving 500s if they come over HTTP), use IIS URL Rewrite to check for HTTPS being off—and if so, redirect them (permanent 301) to the same path over SSL. The converse could also be done.

Good news is URL rewrite comes installed out of the box at Azure (looks like v1.2 and above).

Here's an example web.config showing the configuration to ensure that the secure directory requires SSL.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Enforce SSL" enabled="false" stopProcessing="true">
          <match url="/?(secure.*)" ignoreCase="true" />
          <conditions>
            <add input="{HTTPS}" pattern="off" />
          </conditions>
          <action type="Redirect" url="https://{SERVER_NAME}/{R:1}" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Sunday, June 19, 2011

Fisheye Lens Webcam

I video conference often for work, and fret that I can only see one person on the other side of the call. Wouldn't this be easier and more natural if I could see everyone? Time to get creative and mount a fisheye lens to my webcam.

I started with a door viewer a.k.a. peephole. Fail.
side by side3

Then I upgraded to a Vivitar 0.21X 37mm fisheye lens made for a video camera. Win. I estimate the "before" viewing angle at 75º and the after at 115º. More than 90 is what I was after (stick it in the corner, see the whole room), so this is very good.
4dfe7aece6eb1

Next I needed a housing; preferably one that was non-destructive to both the lens and the laptop. Below is a 1 1/2" EMT insulated bushing (the blue ring) super glued to a plastic faceplate. You can see I drilled holes through the ring so that nuts and bolts can hold the lens in place – the lens barrel has a concave shape, so friction in the lowest point keeps it stable.
WP_000308

1" C-clamps hold the rig in place on the rim of my laptop's display. The clamps should work on pretty much any laptop screen thickness.
WP_000309

Sure it interferes with the display – but that wasn't a design goal since I have a second display.

And of course since I'm an engineer, the housing started with a sketch. Total project cost was under $50.
WP_000304

Here are some other like-minded projects on the Internet that inspired me:

Thursday, June 09, 2011

Enabling IPv6 on Comcast with Buffalo WZR-HP-G300NH

I'm running Buffalo's latest (as of this writing) DD-WRT firmware, V24-SP2 build 16783.

The DD-WRT IPv6 tutorial is in the ballpark, but didn't work for my setup. See the section on 6rd for Comcast-specific scripts; for me, the script never succeeded on startup (I presume because the WAN wasn't up before the script was executed). Here's what actually worked:

  • In the web interface, Administration / Management.
    • IPv6: Enable
    • Radvd: Disable
    • JFFS2: Enable
    • Clean JFF2: Enable (this will format a writable partition where you can store user scripts)
  • Apply, and then reboot the router.
  • For some reason, nslookup 6rd.comcast.net throws a segmentation fault on my router… so the script below shows a hard-coded value IP address. The original script linked above intended to parse the result of nslookup.
  • Use SSH/SCP/SFTP to copy this script onto the router to /jffs/etc/config/ipv6comcast.wanup:

#!/bin/sh
insmod /lib/modules/`uname -r`/kernel/net/ipv6/sit.ko
HOST6RD=69.252.80.66
#nslookup 6rd.comcast.net segfaults
WANIP=$(ip -4 addr show dev eth1 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
if [ -n "$WANIP" ]
then
V6PREFIX=$(printf ' 2001:55c:%02x%02x:%02x%02x' $(echo $WANIP | tr . ' '))
ip tunnel add tun6rd mode sit ttl 255 remote any local $WANIP
ip link set tun6rd mtu 1280
ip link set tun6rd up
ip addr add $V6PREFIX:0::1/32 dev tun6rd
ip addr add $V6PREFIX:1::1/64 dev br0
ip -6 route add 2000::/3 via ::$HOST6RD dev tun6rd
kill -HUP $(cat /var/run/radvd.pid)
fi
echo "interface br0 { \
MinRtrAdvInterval 3; MaxRtrAdvInterval 10; AdvLinkMTU 1280; AdvSendAdvert on; \
prefix $V6PREFIX::/64 { AdvOnLink on; AdvAutonomous on; AdvValidLifetime 86400; \
AdvPreferredLifetime 86400; }; };" \
> /tmp/radvd.conf
radvd -C /tmp/radvd.conf start

Friday, May 20, 2011

DIY Hauraches - Luna Sandals

Just a few teaser photos.

DSCN0489

DSCN0493

Tuesday, May 17, 2011

Triggering Multiple Commands on a Single Button Click in Silverlight XAML

If you're using RIA services and have ever drag-and-dropped a datasource onto a user control, you've likely seem the generated Load button that fires a command to load data:

<Button Content="Load" Margin="3" Name="myDomainDataSourceLoadButton" Command="{Binding Path=LoadCommand, ElementName=myDomainDataSource}" />

If your control has multiple DomainDataSources and you'd like to trigger them all by a single button click, you can change your markup:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

<Button Content="Load" Margin="3" Name="myDomainDataSourceLoadButton">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:InvokeCommandAction Command="{Binding Path=LoadCommand, ElementName=myDomainDataSource}"/>
            <i:InvokeCommandAction Command="{Binding Path=LoadCommand, ElementName=myOtherDomainDataSource}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

I left out the markup for the DomainDataSource and its query parameters, etc, but this should get the point across.

Wednesday, May 11, 2011

Performance Testing in Azure Dev Fabric

I'm running an application at Azure that runs in Full IIS Mode with Dev Fabric version 1.4 on x64 Windows 7. I set out to run some performance tests, since Memory\Page Faults/sec is high during a few scenarios in production.

Unfortunately, the Visual Studio tooling has not caught up to Azure, so it takes a bit of hacking and Powershell goodness to get the data you need. On the positive side, the Visual Studio tooling is just a UI for the same command line tools we're about to use. Plus, analysis happens exactly the same way that you're used to in Visual Studio.

This tutorial assumes you want Memory and Performance metrics using instrumented assemblies. If you don't want/need Memory, skip the relevant bullet.

NB: Be sure you're using the 64-bit versions of these commands if that is your platform. Also run Powershell as an Administrator if you use UAC. Also, oddly, vsperfcmd doesn't seem to return from the ISE, so you have to use good ol' powershell.exe.

  • Install x64 Performance Tools for Visual Studio 2010 SP1
  • (Optional) Enable CLR memory profiling (allocations, or allocations and lifetimes (shown))
    • & "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Performance Tools\x64\VSPerfCLREnv.cmd" /globaltracegclife
    • (You may have to reboot for the command to take effect)
    • Important: When you're done, be sure to run the same command with /Off and /GlobalOff switches, otherwise EVERY .NET app on your system will be publishing these metrics and run like dog crap.
  • Build your application
  • Instrument your assemblies in-place
    • $vsinstr = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Performance Tools\x64\vsinstr.exe"
      dir ".\MyCloudApp\bin\Debug\MyCloudApp.csx\roles\MyWebRole\approot\bin\MyNamespace*.dll" | foreach-object {
          & $vsinstr $_.FullName;
      }
  • Start the performance profiler; it seems this must start before your application (Note I'm naming the .vsp output with a timestamp for easier scripting and history tracking)
    • $vsperfcmd = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Performance Tools\x64\vsperfcmd.exe"
      $date = get-date -F yyyyMMddHHmmss
      &$vsperfcmd /START:TRACE /OUTPUT:perf_$date.vsp /user:Everyone
  • Start your application via the Azure cloud tool csrun.exe
    • $csrun = "C:\Program Files\Windows Azure SDK\v1.4\bin\csrun.exe"
      &$csrun /devstore:start
      &$csrun .\MyCloudApp\bin\Debug\MyCloudApp.csx .\MyCloudApp\bin\Debug\ServiceConfiguration.cscfg
  • Wait for the appropriate process to start and grab its PID. In my case, since I'm using Full IIS Mode and interested in capturing metrics from RoleEntryPoint and deeper, that process is WaIISHost.exe. If you are running a worker role, that process is WaWorkerHost.exe; "old" web roles use WaWebHost; web sites running under Full IIS Mode use the regular w3wp.exe (though getting the right app pool may be more difficult).
    • while(-not $process) {
          $process = Get-Process | where { $_.ProcessName -ieq "waiishost" };
          start-sleep 0.1;
      }
  • When ready, start capturing instrumented data
    • & $vsperfcmd /processOn:$($process.Id)
  • When done, disconnect and shut down
    • & $vsperfcmd /processOff:$($process.Id)
    • & $vsperfcmd /shutdown

Now open the .vsp and—there you have it—a performance report generated from code running in Azure dev fabric!

image

Wednesday, April 27, 2011

Converting RunAmocs to Huaraches

RunAmoc - LITE<br/>Black
Last summer I bought a pair of RunAmocs, a barefoot running moccasin. They're neat—but I didn't like the fit. They're too loose for running (contrary to other reviews online), and after the initial excitement wore off, I decided that I didn't like the style. Great vision, but it needed to be secured better on the foot.

I finally decided to tear them to bits and turn them into running sandals. I had a few other spare parts lying around, namely, a pair of elastic shoe laces from my "big fat running shoes" days. So I got to cutting.

WP_000236 WP_000238

And then learned about tying. And in the end, ended up with a beautiful little sandal. The elastic closure is incredibly secure while being very easy to get on and off. They way they move with your feet is incredible—I can't believe how many pairs of minimalist shoes I've gone through to find this.

WP_000239

WP_000240The way these things move with your feet is very impressive. Not with your feet—as a part of your feet. I've never felt less resistance to move with me in footwear. This is a 2mm road sole with another 2mm or so of lightly-padded faux (?) leather. I trimmed the toes to fit a little better…but got too aggressive on the right foot. Live and learn. I ordered some pieces from Barefoot Ted's Luna Sandals and will try another iteration shortly. I also picked up some longer 42" elastic laces in plain black (not the reflective black, above) and a proper leather punch (instead of a drill). I am excited.

Friday, April 15, 2011

Using a Vodafone AU Prepaid Data SIM in a Phone

The APN for a prepaid data SIM (at least the one I got bundled with a hardware modem):

APN: vfprepaymbb
Username: web
Password: web

They don't make that obvious, but it works. Cool. Seems to receive phone calls, too… not sure how that counts against the quota.

Saturday, March 26, 2011

A Brief History of Modern Running

In the beginning, there were bare feet. Homo sapiens sapiens (anatomically modern humans) first appeared as a species about 200,000 years ago. Having come down from trees, we stood upright and grew big brains. Like all animals, we evolved feet well-suited for our tasks: big horn sheep have hooves that enable them to deftly scale cliffs. Monkeys can grip branches and navigate trees with ease. But homo sapiens, no longer hanging onto branches, evolved feet for a rather different purpose: running across plains in persistence hunts, chasing down gazelle until they would die of heat exhaustion.
Two females, possible a mother daughter team, jog barefoot on the Morro Strand Beach
Photo credit.

In the 1970s, there came a revolution in footwear: Nike. Oh big thick padded footwear! Save us from ourselves! Our feet are defective, we need to enshroud them in padding. The laws were changed to require footwear in school PE classes (the result of footwear company lobbying).
378243098_72f998eea6_o
Photo credit.

Big, padded heels have an interesting consequence: they change your gait. Most joggers jam their foot way out in front of them and strike heel-first, letting that big pad absorb some of the shock. Some of it. The rest is absorbed by knees and hips, at angles and in ways that we did not evolve to withstand. And, most detrimentally, impact is absorbed in places where there aren't too many nerve endings, meaning pain is noticed well after the damage is done.
Slice 2
Photo credit.

Sports injuries increased: plantar fasciitis, ITBS, etc… What to blame? Not that footwear in and of itself is fundamentally flawed—no. We just had to evolve the footwear. And so arch support was born, so that our feet would no longer (defectively?) flex. Add motion control with varying stiffness of foams to prevent over-pronation. More, more, more.

Americans, being the consumers (and consumerists) that we are, needed more products to put on our feet. People began questioning the footwear (perhaps there was always a questioning subculture). Thus, in 2006, a trojan horse was born: Vibram FiveFingers. Not content to just take off our shoes and run, Americans needed to buy a product in order for the most natural thing possible to become acceptable. For shame, America! For shame!
3513130386_ce8c6f3486_o

Photo credit.

I admit that I bought into it and became an early adopter. These peculiar shoes used to fetch odd looks before coming to be so commonplace these days.

A subculture sprung up of people demanding less in their footwear. Less support, less padding, more like a sock than a shoe. These days the tide is swelling, and more and more minimal footwear products are filling the shelves. There are now entire stores dedicated to selling minimal footwear.

Have you ever wondered why your feet are so sensitive? When your shoes come off and you run, your gait becomes softer. Yes, you read that right: the less padding on your feet, the softer you land. When your feet can feel the ground, you instinctively run differently and in a way that minimizes impact and pain. No longer do you land heel first (ouch!)—your strike moves forward to the forefoot or midfoot. If it hurts, those sensitive feet immediately sound alarm bells that you're doing something wrong, so your gait necessarily adapts. The outside edges of your feet land first, you pronate (roll inward) and your arch flexes, all to absorb impact shock before it reverberates up to your knees and hips. When you slow down, no longer can you lean back and slam your padded heels into the ground—you have to take a few strides and slow down, uh, slower.

In short: if you run shod, you run incorrectly. If you run barefoot, you run correctly. Yes, you can learn barefoot form and then run correctly whilst shod. But going barefoot is the surest and quickest way to learn.

If this piques your interest, go read Born to Run by Christopher McDougall. Or watch this hour-long video for free of Barefoot Ted. It will inspire you. And if you've been running with padded shoes your whole life, START SLOW. A quarter or a half mile without shoes will be about all you can handle—you are working a lot of atrophied muscles. It will take time before you can run marathons barefoot like this guy.
Los Angeles Marathon
Photo credit.

Up next: a brief history of my experiences with minimalist footwear.

Saturday, March 12, 2011

Notepad++ HTML Tidy doesn't work

If Tidy HTML fails silently and you have UAC enabled, try this trick.

Tidy needs to write to C:\Program Files (x86)\Notepad++\plugins\Config\tidy\HTMLTIDY.CFG. Create the file, and then grant everyone full control.

Now you can do things like auto-indent XML in Notepad++.

Sunday, March 06, 2011

Using Screen on Linux - Quick Start

I'm performing a long-running import (multiple days) and need to be able to check in on it every so often. Normally, disconnecting your SSH session will kill all of its processes, but screen sits a layer above that, creating a session that you may attach to and detach from at any time, from any SSH/terminal session. Screen is intimidatingly powerful—but here is the minimal info you need to be able to start a screen session and come back to it later.

screen -S <name>   Starts a named session. Once inside the session, start the import/whatever you will want to come back to.

^a d (CTRL+a d)    Detaches the current Screen session.

screen -list    List all sessions

screen -r <name>    Resume a detached session

Hope that helps!

Wednesday, January 19, 2011

Silverlight DataGrid with Dynamic Columns

I had to build a grid of images. Business requirements called for an image with a caption, arranged in rows and columns by certain user criteria. (In other words, I couldn't just use a StackPanel and flow them horizontally and wrap row to row). Additionally, the number of rows and columns is impossible to know at compile time.

I started with a class

public class Thumb
{
    public Thumb(string imageUri, string title)
    {
        Thumbnail = new BitmapImage(new Uri(imageUri, UriKind.Relative));
        Title = title;
    }
    public ImageSource Thumbnail { get; set; }

    public string Title { get; set; }
}

I wanted to arrange them into a 2D array of Thumb[][], or IEnumerable<Thumb[]>. I'll stick with the latter because it's clearer to explain: Enumerate over the rows, and index into the array for columns. Also, there is other code to guarantee that the data is the same in columns and that the 2D array is always a rectangular, never jagged.

As an aside, if this had been ASP.NET, I could have put these objects into a DataTable/DataSet, and its DataGrid would have dynamically generated the columns. But binding an IEnumerable<Thumb[]> to a Silverlight DataGrid with AutoGenerateColumns=True ends up with a grid where each row is an array…the columns are Length, SyncRoot, IsReadOnly, etc—the properties on the array, not indexing into it.

Now to wire it up in XAML. To start, let's do it by hand, for just the first column.

<sdk:DataGrid ItemsSource="{Binding MyThumbnailCollection}">
  <sdk:DataGrid.Columns>
    <sdk:DataGridTemplateColumn Header="Column Title">
      <sdk:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <StackPanel>
            <TextBlock Text="{Binding [0].Title}" />
            <Image Source="{Binding [0].Thumbnail}" />
          </StackPanel>
        </DataTemplate>
      </sdk:DataGridTemplateColumn.CellTemplate>
    </sdk:DataGridTemplateColumn>
  </sdk:DataGrid.Columns>
</sdk:DataGrid>

When the DataGrid renders with TemplateColumns, it enumerates its ItemsSource (which it expects to be IEnumerable), and then sets the DataContext of the child FrameworkElement of the DataTemplate to the given row in the collection—in our case, each row is an array, Thumb[]. You can see that the template above is bound to an indexer and a property of the indexed object. Pretty cool and powerful runtime binding.

But how do we wire that up dynamically? At compile time, we don't know how many columns will be in the grid, so hard-coded XAML columns are out. I need to modify that binding dynamically, after the ItemsSource is set.

Roadblocks

This is not, as it turns out, a simple task in Silverlight.

As far as I can see, there's no simple way to create columns dynamically with a data context! If I'm missing something here, please leave a comment!

XAML in C#

The first solution I found was to create the indexed binding XAML in C# and load it into the cell template – a crafty workaround to both problems. It looks something like this:

private void CreateGridColumns()
{
    grid.Columns.Clear();
    if (Thumbs.Count == 0) return;

    for (int i = 0; i < Thumbs[0].Length; i++)
    {
        var template = new StringBuilder();
        template.Append(@"<sdk:DataGridTemplateColumn 
            xmlns:sdk=""http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"" 
            xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
            xmlns:my=""clr-namespace:Client.App.Views;assembly=Client.App"" ");
        template.AppendFormat(@"Header=""{0}""> ", Thumbs[0][i].Title);
        template.Append(@"<sdk:DataGridTemplateColumn.CellTemplate>
              <DataTemplate>
                <StackPanel>
                  <TextBlock Text=""{");
        template.AppendFormat("Binding [{0}].Title", i);
        template.Append(@"}"" />
                  <Image Source=""{");
        template.AppendFormat("Binding [{0}].Thumbnail", i);
        template.Append(@"}"" />
                  </StackPanel>
                </DataTemplate>
            </sdk:DataGridTemplateColumn.CellTemplate>
        </sdk:DataGridTemplateColumn>");
        grid.Columns.Add((DataGridTemplateColumn)XamlReader.Load(template.ToString()));
    }
}

This code generates identical XAML as to what we wrote by hand, except one for each column.

As a matter of style though, I don't particularly like the way this code smells. C# isn't for writing XAML, and any UI that has do be done in code should be done using the object model.

Creating a Bindable Column

Edit: This solution fails to work in Silverlight 4 because of the DataGrid's virtualization aka container recycling. See below for a updated version.

The DataGrid recycles rows when they scroll in & out of view. That is to say, rather than create all of the UI elements for potentially millions of rows in a DataGrid, they only create enough to display those that fit on the screen. When a row scrolls out of view, it's put on a "recycled" Stack; when a row scrolls into view, it checks the Stack for a row to reuse before creating a new one. If it finds one, it sets the row's DataContext appropriately and then displays it.

Our solution below fails to work because we set the DataContext of the row UI elements directly—that means when a row gets recycled, it will display whatever data it had been assigned when it was first instantiated. My apologies; I tested it with a small set of data initially. Keep reading for a solution.

This solution is a bit cleaner – it's certainly more object oriented, and feels more at home in C#, despite the increase in lines of code. Create a column that is aware of its binding context so that it can "pass it down" to its cells.

DataGridTemplateColumn has a method GenerateElement that is used to build out the FrameworkElement that is the UI of the datagrid cell. We need to override it so that is can be aware of its "column context."

First, create this "bindable" template column, inspired via:

public class DataGridBindableTemplateColumn : DataGridTemplateColumn
{
    public string BindingPath { get; set; }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        //dataItem is the row.
        var elem = base.GenerateElement(cell, dataItem);
        elem.SetBinding(FrameworkElement.DataContextProperty, new Binding(BindingPath) { Source = dataItem });
        return elem;
    }

}

Two things to note: first, we call base.GenerateElement() to let the DataGrid do its thing and build the UI. Second, when we modify the binding, we only modify the path. This will be a string like "[0].Title" or "[0].Thumbnail" in our case, and it is bound to the dataItem, which is a row in our grid (remember, enumerate over the rows, index into the columns). The framework handles the rest of the binding.

Note this same code "should" work with an IEnumerable<Dictionary<,>> and a BindingPath that keys into the dictionary. I haven't tested that, however.

Then, when your grid's ItemsSource changes, determine the columns and update dynamically:

private void CreateGridColumns(ObservableCollection<Thumb[]> thumbs)
{
    grid.Columns.Clear();

    if (thumbs.Count == 0) return;

    for (int i = 0; i < thumbs[0].Length; i++)
    {
        var dt = (DataTemplate)Resources["ThumbViewTemplate"];
        var col = new DataGridBindableTemplateColumn();
        col.CellTemplate = dt;
        col.BindingPath = String.Format("[{0}]", i);

        grid.Columns.Add(col);
    }
}

This code is a little different because, instead of creating the StackPanel, TextBlock and Image in source code, I moved it into a named resource in the XAML (below). You can see that I'm creating the new custom DataGridBindableTemplateColumn and setting its BindingPath to an index into the array, which the above GenerateElement override knows how to use.

<UserControl.Resources>
    <DataTemplate x:Key="ThumbViewTemplate">
        <StackPanel>
            <TextBlock HorizontalAlignment="Center" Text="{Binding Title}" />
            <Image HorizontalAlignment="Center" Stretch="Uniform" Width="200" Height="200" Source="{Binding Thumbnail}" />
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>

As the grid renders, the <StackPanel> of each cell gets its DataContext bound to dataItem[i] – where dataItem is the row. Thus, its children are now bound to a single Thumb instance in our case.

DataGrid LoadingRow Event

While the above solution fails abysmally, there is fortunately an even more elegant option. First, you create the columns dynamically just as before. Second, you handle the DataGrid's LoadingRow event, which is fired every time a row is either created or scrolled into view. We can use this event to index into our columns and bind each cell individually.

Note we're using a regular DataGridTemplateColumn.

private void CreateGridColumns(ObservableCollection<Thumb[]> thumbs)
{
    grid.Columns.Clear();    
    if (thumbs.Count == 0) return;

    for (int i = 0; i < thumbs[0].Length; i++)
    {
        var dt = (DataTemplate)Resources["ThumbViewTemplate"];
        var col = new DataGridTemplateColumn();
        col.CellTemplate = dt;
        grid.Columns.Add(col);
    }
}

private void grid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    var dataRow = (Thumb[])e.Row.DataContext;
    for (int i = 0; i < grid.Columns.Count; i++)
    {
        var col = grid.Columns[i];
        var elem = col.GetCellContent(e.Row);//FrameworkElement inside of DataGridCell
        elem.DataContext = ((Thumb[])e.Row.DataContext)[i];
    }
}

Another important point to note is that DataGridRow.Cells is an internal property. Use DataGridColumn.GetCellContent(DataGridRow) instead, it will return the FrameworkElement of the cell at the intersection of the row and column.

There you have it – dynamic columns in a Silverlight datagrid.

Hope this helps! Which solution do you prefer?