Skip past navigation, straight to the content

Monthly Archives: March 2007

Running

I never liked running. Although I could play hours of basketball or soccer, if I set out to go running, I would stop before even reaching a mile. I got bored quickly, kept on noticing how tired I was, and eventually gave up and found some other way to exercise like soccer — or a hamburger.

Even though I didn’t like running, I wanted to. There was something romantic about the sport. I was drawn to the simplicity, the minimal equipment necessary, and the lack of dependency on others (no need to wait around for a game of pickup). A lot of runners would tell me how great it was to run while traveling — seeing large parts of the city on foot, especially in the morning, provided context and a different view of the area.

Also, running was a sport that people were to do across their lifetimes. Perhaps its the lack of dependence on others, or the ability to go at your own pace, but I never met sixty year-old soccer or basketball players. The active people that age all seemed to be runners.

During my last weeks in China, feeling unhealthy from the pollution and my emaciated state, I decided it was time to suck it up and become a runner. I emailed some of my runner friends and asked for advice, realized I didn’t have running shoes, and made plans to start running as soon as I came back to the US.

I had a lot of downtime while traveling during those last few weeks in China — so I made up some ground rules for my running: Run every day to build and reinforce the habit, run before doing anything else (like checking email) to make sure it doesn’t get procrastinated away, and run for around a half-hour so it doesn’t take too much time (which could put the habit at risk).

My first runs were terrible, of course. The very first run lasted about twenty minutes, and I probably walked at least eight of those minutes. Luckily, most of my early runs were in Florida, which is drier and warmer than Seattle.

I’ve kept at it, although I’ve revised the rules — I quickly moved to six days a week (taking Sunday off), and now I run whenever I feel like it and the conditions are decent (three to four times a week). I rarely run in the mornings, because it’s usually better to wait until the afternoon when it’s 45, not 35, degrees out.

I’ll typically run between four and five miles, which takes a comfortable thirty to forty minutes, depending on terrain. The longest I’ve run was seven miles, with a mile-long walking break in the middle.

Finding good routes has been a bit of a pain, since Seattle has lots of steep hills — on the upside, I feel much faster when I run in Florida (where the highest point is mostly in Alabama and a hundred feet shorter than Capitol Hill).

My biggest piece of advice to those starting off: Track your progress. Take a note of how far you’re running, and how long it takes. It’ll be depressing at first, but it’s great to see how much you’ve improved since you started. If you’re into gadgets, a GPS tracker is nice to have (got mine for Christmas — thanks!). I’ve found the distance measurement to be accurate and consistent. My only complaint is that altitude readings are pretty much useless — when I ran around Green Lake (which is quite flat) it told me I ascended 500 feet on the first lap, and 360 feet on the second.

The forecast said rain, but it’s currently sunny outside. I’m off…

First albums of 2007

Aesop Rock - All Day+

Aesop Rock - All Day+

This is the latest in a series of running-specific mixes commissioned by Nike. When I started running, I often listened to LCD Soundsystem’s 45:33, which was my first exposure to the series. Although I like LCD Soundsytem, I’m not in love with this mix — it’s a bit too repetitive. In the liner notes for his mix, Aesop Rock writes about the requirements Nike gave:

There had to be a new element every 30 seconds or so (a new riff, a new layer, a new drum pattern) as other elements faded into the distance. Basically, I had to keep the scenery shifting while maintaining the “push.”

It turned out well. I like having a consistent mix to listen to, because it gives me a good idea of how long I’ve been running (without actually looking at the time). Plus, it’s nice to have Aesop Rock telling you “No Surrender” when you’re getting tired.

You can hear a sample of the mix on Aesop Rock’s MySpace.

Amon Tobin - Foley Room

Amon Tobin - Foley Room

I’ve always been a big fan of Amon Tobin’s dense instrumental music, and his latest doesn’t disappoint. It may be a bit dark for some, but somehow I find it to be a great soundtrack while working. The album’s nothing new or groundbreaking for Tobin, but it’s still quite good.

As of right now, it seems like Amon Tobin’s MySpace is the best place for samples (the official website has an annoying flash interface) — although two of his songs will start playing at the same time (scroll down, there’s a video that autoplays).

The Besnard Lakes - The Besnard Lakes Are the Dark Horse

The Besnard Lakes - The Besnard Lakes are the Dark Horse

The Besnard Lakes play long rock songs with country tinges — their style reminds me of 2005’s excellent Z by My Morning Jacket. Although the songs are longer, there are only eight tracks so the album is only about 45 minutes long. As with My Morning Jacket, the lack of filler works to the band’s advantage.

Somehow, the MySpace page wins the usability contest for audio samples again. These artist websites are terrible.

Other Releases

A lot of artists I really like are releasing new albums. Sadly, I’ve been mostly disappointed.

Have I missed anything good?

A Dash of Color

  • <br />
Ceiling Fan, Seattle, Washington

This page was looking mighty drab, so I thought I’d add some color. I’ll also add a few random updates:

I’ve now been back from China longer than I was there. This means that I may no longer bring it up in conversation, under penalty of law.

The snow season is almost over — I’m trying to squeeze in some trips before the snow all melts. I went twice this week.

This guy went much, much further with his self-imposed restriction (and for similar reasons) — hopefully he won’t quit after two days like weaker people. I’m still tinkering with the balance, but I’ll do it in private for a while, so I don’t bug anyone (you?).

I’ll be in Salt Lake City next week (and two weeks after that, and two weeks after that). I’ve got some friends from High School in Park City — but what should I do in Salt Lake itself? The guides I’ve looked at all seem to say that going to the mall is one of the top three attractions. I hope the Sbarro’s and Cinnabon there are as good as they are here!

When you’re unemployed, people demand you tell them what you did with your day. In detail. Before, no one ever cared — can you blame them?

Is this thing on?

For reasons both known and unknown, I’ve decided to start writing here again. I’ll cover WPF, along with other nerdy things like PHP, Ruby, and exciting role-playing games.

Hidden <Run />

Text content in WPF adheres to a strict content model, with elements (hopefully) fulfilling a specific role. In practice, this is fairly familiar for developers familiar with HTML. However, there are a few things that are useful to know — one of those things is the Run element.

Here’s a simple piece of markup:

<Paragraph><Italic>Neon Bible</Italic> is the new album by the Arcade Fire.</Paragraph>

This XAML parses and displays as you would expect. Underneath the covers, the element tree created is equivalent to the following markup:

<Paragraph>
  <Italic><Run Text="Neon Bible" /></Italic><Run Text=" is the new album by the Arcade Fire." />
</Paragraph>

In the land of WPF text layout, the Run element is the only element that holds actual strings of text. All other elements (Bold, Italic, etc) are ultimately formatting containers for Run elements that hold the actual text being displayed.

Knowing about these Run elements is important when you’re working programmatically with text. If you’re only doing markup, you’re (almost always) fine being blissfully unaware.

Exception to the rule

Of course, there are always exceptions to the rule — there is another element that can contain text in some cases: TextBlock. You can use TextBlock.Text, which is a DependencyProperty, to bind dynamic text. Here’s the thing to watch out for: TextBlock.Text will return the contents of TextBlock only if the content is a simple string. If you have any markup inside (such as a Bold element), TextBlock.Text returns an empty string.

Collapsed Spaces Around <Run />

In response to my previous post, Nick asks:

Why are my spacings dropped when I have: <Run>NYC </Run> <Run> Hickster</Run>? This comes out NYCHickster

The space collapsing around Run can be a little tricky. The easiest thing to do if you’re running into this issue is to use Run.Text, like so:

<Run Text="NYC " /><Run Text="Hickster" />

This technique works for inserting multiple spaces as well.

Update 3/18: Sheva points out a different method I had completely forgotten about — using xml:space="preserve":

<Span xml:space="preserve"><Run>NYC</Run> <Run>Hickster</Run></Span>

TextEffects

TextEffects is a poorly-documented property that allows you to apply an effect to a portion of text. It’s not the best of name for the property (at least in this first version of WPF), because the only “effects” supported in the current version are Clip, Foreground, and Transform.

There are four important things to know about TextEffects:

  1. They’re really only interesting when you’re working with a substring of text. In other words, if you want to affect the entire content of a TextBlock, you’re better off using properties exposed directly on TextBlock: Clip, Foreground, and RenderTransform (or its cousin, LayoutTransform).
  2. The Clip and Transform effects are always relative to the beginning of the line. In other words, the default CenterX and CenterY of a RotateTransform are at the beginning of the line — not at the beginning of the text being affected (see the screenshots below).
  3. Just like RenderTransform, any size and position changes caused will not affect the layout of text. This is good for animation, since you don’t want to performance penalty caused by re-layout. It does, however, mean that you can easily end up with overlapping text.
  4. They’re a little quirky and frustrating to use (at least in this version of the platform). With the exception of a few narrow scenarios, you’re better off using Clip, Foreground, or RenderTransform.

Let’s start with a basic example and the screenshot:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    <TextBlock.TextEffects>
      <TextEffect PositionStart="5" PositionCount="10">
        <TextEffect.Transform>
          <TranslateTransform Y="-5" />
        </TextEffect.Transform>
      </TextEffect>
    </TextBlock.TextEffects>
    Clap Your Hands Say Yeah!
  </TextBlock>
</Border>

The text 'Clap Your Hands Say Yeah!' with the words 'Your Hands' elevated 10 pixels

The markup is pretty straightforward: TextEffect.PositionStart and TextEffect.PositionCount properties indicate the substring for the effect, while TextEffect.Transform is a standard Transform.

When we resize, notice how the effect applies even across a line break:

The text 'Clap Your Hands Say Yeah!' with the words 'Your Hands' elevated 10 pixels, with a line break between 'Your' and 'Hands'

That was simple enough, now let’s switch to a RotateTransform and see how that works:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    <TextBlock.TextEffects>
      <TextEffect PositionStart="5" PositionCount="4">
        <TextEffect.Transform>
          <RotateTransform Angle="-5" />
        </TextEffect.Transform>
      </TextEffect>
      <TextEffect PositionStart="16" PositionCount="3">
        <TextEffect.Transform>
          <RotateTransform Angle="-5" />
        </TextEffect.Transform>
      </TextEffect>
    </TextBlock.TextEffects>
    Clap Your Hands Say Yeah!
  </TextBlock>
</Border>

Now we have two identical RotateTransform effects being applied to two different portions of the text. Here’s the screenshot:

The text 'Clap Your Hands Say Yeah!' with the words 'Your' and 'Say' rotated 5 degrees counter-clockwise

Is that what you expected? Let’s add some lines to make it clearer:

The text 'Clap Your Hands Say Yeah!' with the words 'Your' and 'Say' rotated 5 degrees counter-clockwise, with guide lines showing the 5 degree angle

As I mentioned earlier, effects are always relative to the beginning of the line. Look what happens when the text wraps:

The text 'Clap Your Hands Say Yeah!' with the words 'Your' and 'Say' rotated 5 degrees counter-clockwise, with a line break between 'Hands' and 'Say'

Notice how “Say” is now rotated with respect to the beginning of the line it occurs on.

Unfortunately, there’s no foolproof way to make the rotation relative to the position of the text. You can manually set the rotation center through the RotateTransform.CenterX and RotateTransform.CenterY properties — but to get the desired effect you’d have to calculate the distance from the word to the beginning of the line (which will end up being incorrect if the text breaks across lines).

<Run>ning into Trouble

Honestly, I had never done much with TextEffects until I started writing this post. I discovered a few tricky issues while constructing the following markup:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    <TextBlock.TextEffects>
      <TextEffect PositionStart="5" PositionCount="4">
        <TextEffect.Transform>
          <RotateTransform Angle="-5" />
        </TextEffect.Transform>
      </TextEffect>
    </TextBlock.TextEffects>
    Clap <Bold>Your</Bold> Hands Say Yeah!
  </TextBlock>
</Border>

This is the markup used in our rotation example, with the second effect removed and a Bold tag added around the word “Your.” If you load this XAML, you’ll see the following:

The text 'Clap Your Hands Say Yeah!' with the word 'Your' in bold.

It was a little tricky to realize what’s going on here. First, it turns out that TextEffects only works with a simple string of content. Let’s try fix this by applying the TextEffect to the Bold instead of the TextBlock (note that we also change the PositionStart to 0):

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    Clap
    <Bold>
      <Bold.TextEffects>
        <TextEffect PositionStart="0" PositionCount="4">
          <TextEffect.Transform>
            <RotateTransform Angle="-5" />
          </TextEffect.Transform>
        </TextEffect>
      </Bold.TextEffects>
      Your
    </Bold>
    Hands Say Yeah!
  </TextBlock>
</Border>

Load this up and we get:

The text 'Clap Your Hands Say Yeah!' with the word 'Your' in bold.

Well, we’re missing yet another thing! As you may already know, Run elements are used behind the scenes when we’re constructing element trees with text. It seems that the effect isn’t applying to the Run inside the Bold. Let’s switch the Bold to a Run and set the FontWeight property:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    Clap
    <Run FontWeight="Bold">
      <Run.TextEffects>
        <TextEffect PositionStart="0" PositionCount="4">
          <TextEffect.Transform>
            <RotateTransform Angle="-5" />
          </TextEffect.Transform>
        </TextEffect>
      </Run.TextEffects>
      Your
    </Run>
    Hands Say Yeah!
  </TextBlock>
</Border>

Drumroll please …

The text 'Clap Your Hands Say Yeah!' with the word 'Your' in bold.

Argh! This last one took a while, but I finally figured it out by playing with PositionStart and PositionEnd. Counter-intuitively, the PositionStart property isn’t relative to the beginning of the Run, it seems to be relative to the beginning of the containing TextBlock — but not quite. Originally, we used a PositionStart of 5, but in order to work as expected, I had to use a value of 8! Removing the whitespace between “Clap” and the Run lowered this to 7, but I never figured out how to get it to 5 (which, although counter-intuitive, I could at least understand).

Bleh. My recommendation is to set PositionStart to 0 and PositionCount to something large, like 100. Doing so, we get our final markup here:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="20" SnapsToDevicePixels="True">
  <TextBlock FontFamily="Calibri" FontSize="30" TextWrapping="Wrap">
    Clap
    <Run FontWeight="Bold">
      <Run.TextEffects>
        <TextEffect PositionStart="0" PositionCount="100">
          <TextEffect.Transform>
            <RotateTransform Angle="-5" />
          </TextEffect.Transform>
        </TextEffect>
      </Run.TextEffects>
      Your
    </Run>
    Hands Say Yeah!
  </TextBlock>
</Border>

Finally, we get the expected result!

The text 'Clap Your Hands Say Yeah!' with the word 'Your' in bold and rotated 5 degrees.

In the end …

In most cases, you’re better off using RenderTransform if you can get away with it. Hopefully, future version of WPF will add some more interesting effects and fix these weird issues. Meanwhile, I hope this post helps people who are struggling with TextEffects.

Filling things

  • A strange lamp, Seattle, Washington

Three times in the past week, I’ve heard a variant of the saying “You could fill a book with what you don’t know.”

It’s a strange thing to say, because so many people already have — in fact, they’ve filled buildings with books filled with things you don’t know.

BindableRun

A useful feature that was left out of the first version of WPF is the ability to databind the value of Run.Text. I was still around when this feature was (unfortunately) cut — but don’t despair! It’s not actually that hard to write yourself.

We’ll do this by creating a subclass of Run, which I’ve creatively named BindableRun.

using System;
using System.Windows;
using System.Windows.Documents;
 
namespace BindableText
{
  /// <summary>
  /// A subclass of the Run element that exposes a DependencyProperty property 
  /// to allow data binding.
  /// </summary>
  public class BindableRun : Run
  {
    public static readonly DependencyProperty BoundTextProperty = DependencyProperty.Register("BoundText", typeof(string), typeof(BindableRun), new PropertyMetadata(new PropertyChangedCallback(BindableRun.onBoundTextChanged)));
 
    private static void onBoundTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((Run) d).Text = (string) e.NewValue;
    }
 
    public String BoundText
 
      get { return (string)GetValue(BoundTextProperty); }
      set { SetValue(BoundTextProperty, value); }
    }
  }
}

The code is pretty straightforward, we create a new DependencyProperty in the usual manner. Then we add a PropertyChangedCallback that manually sets the Text property. That’s it! We rely on the base class to take care of everything else.

You can use this in DLL, by declaring an XML namespace and linking it to a CLR namespace, as in the example below:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:bt="clr-namespace:BindableText;assembly=BindableText">
  <FlowDocumentScrollViewer>
    <FlowDocument>
      <Paragraph>
        You can control the value of this text through the TextBox below: <bt:BindableRun FontWeight="Bold" BoundText="{Binding ElementName=tb, Path=Text}" />
      </Paragraph>
      <BlockUIContainer>
        <TextBox Name="tb" Text="This is text with spaces that wraps across a line … like this!"/>
      </BlockUIContainer>
    </FlowDocument>
  </FlowDocumentScrollViewer>
</Page>

If you’re running this in XamlPad, you’ll have to make sure that the BindableRun.dll file is in the same directory as XamlPad itself. You can do this by either creating a new copy of XamlPad.exe or copying the BindableRun.dll into the directory where you keep XamlPad (C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin in my case).

If you want to download this class, I’ve created a project (with the DLL) that you can download and use: BindableText.zip (13 KB).

Update 3/21: Paul Stovell mentions an alternate technique that creates an attached property instead of a subclass to achieve the same effect.

Creating WPF Text Layouts is Hard

I’ve heard many people ask for advice on creating attractive text layouts using WPF — with good reason! There are quite a few challenges, in my opinion, the top difficulties are:

  1. Differences from HTML/CSS: More than any other part of WPF, the System.Windows.Documents namespace has many similarities with HTML/CSS — but the differences are significant enough to cause real issues.
  2. Lack of good examples: The technology is still new, so there aren’t many role-models out there to learn from. The lack of view-source capability makes it tough to steal learn from others.
  3. Variable-column layout is hard: Without a doubt, designing a document that looks good when reflowed into a variable-number of columns is difficult.
  4. Lack of a designer: This is a tough one.

It’s a bit ambitious, but I’m going to do what I can to help fix these problems.

Obviously, this will take many entries — let me know if I’m missing anything, or if you have specific questions you’d like me to address.

Inline Elements

The term inline may be familiar if you know HTML and CSS — an inline element is displayed within an existing flow of text, positioned on lines of text shared with other inline elements.

Let’s make this more clear with a screenshot and a bit of code:

<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="1" BorderBrush="#ccc" Padding="10">
  <TextBlock TextAlignment="Left" TextWrapping="Wrap" Width="400" FontSize="25" FontFamily="Candara">
    <Bold>Of Montreal:</Bold>
    <Hyperlink Background="#cef">Hissing Fauna, Are You The Destroyer?</Hyperlink>
    <Italic>(2007)</Italic>
  </TextBlock>
</Border>

The text 'Of Montreal: Hissing Fauna, Are You The Destroyer? (2007)'

In our example, we are using three inline elements: Bold, Hyperlink, and Italic. Each of these shares space on a line within our TextBlock (you can think of it as a paragraph). I added a background to the Hyperlink element to emphasize the fact that the element is broken across a line.

Here are all the elements shipped with WPF that derive from Inline (you can, of course, subclass and add your own):

  • Run: A string of text.
  • Span: A container for grouping other Inline elements. Its subclasses provide default formatting, and linking:
    • Bold
    • Italic
    • Underline
    • Hyperlink
  • LineBreak: Forces a hard line break within a text flow. Provided as a markup convenience (newline characters are honored if used within code).
  • InlineUIContainer: A container for UIElement-derived classes within text.
  • AnchoredBlock: I’ll cover these in detail later, but note that these cannot be used within a TextBlock
    • Floater
    • Figure

As I’ve mentioned before, it’s rarely necessary to explicitly use Run when writing markup (although it’s important when writing code). The same mechanism is used with InlineUIContainer for convenience.

Span and its subclasses are straightforward for those with experience with HTML, as is LineBreak.

Figure and Floater don’t have direct analogues in HTML, but the functionality is similar to the CSS property float. More on these later.

Differences from HTML

If you’re already familiar with HTML/CSS, then the concepts in this entry are old news to you. For easy skim-reading, here are the major differences between WPF XAML markup and HTML markup for inline elements:

  • No semantic classes: This is a subtle, but important, point — the markup classes exposed in WPF have no semantics, they are presentational only.
  • Once an Inline, always an Inline: This is partially a consequence of the previous point, but unlike CSS, you cannot change the display-type of an element — i.e. you can’t change an element from inline to block, or vice-versa. If you want to do that, you must change the elements used and the tree structure.
  • Can’t nest paragraphs: The content model is strict, so you can’t directly put a block element within a Paragraph (we’ll learn how to do this via InlineUIContainer or an AnchoredBlock in later posts).
  • Invisible container elements: Run and InlineUIContainer may not be in the markup, but they’re there if you walk the tree.

Next, we’ll look at the properties you can apply to inline elements.

Inline Properties

Now that we’re roughly familiar with the inline elements, let’s look at the formatting properties each of them expose.

Properties from TextElement

TextElement is the superclass for all classes used for text (with the exception of TextBlock). TextElement defines formatting properties that can be applied universally to text.

FontFamily

Controls what is commonly known as the “font” of the text. Like CSS, you can give a comma-separated list of alternatives such as FontFamily="Calibri, Verdana, Helvetica, Arial". Note that, unlike CSS, you cannot use generic names such as Serif, Sans-Serif, and Monospace. Like CSS, there are a few generic names you can use: Global Monospace, Global Serif, Global Sans Serif, and Global User Interface.

FontSize

The size of the font in “WPF pixels” (1/96 of an inch). Note that this is not equal to the traditional font size measure of points (1/72 or 1/72.27 of an inch depending on how precise you want to be). As with other measures, you can use shorthand in markup to get sizes in points, inches, etc (e.g. FontSize="12pt" or FontSize="2cm").

Foreground

The color of the text. This property is actually a Brush, which means you can do cool things like draw text with a gradient.

FontWeight

Controls the darkness of the font face — typically used to make text bold. This is a value between 1 and 999, or one of the following value shortcuts: Thin, ExtraLight, Light, Normal, Medium, SemiBold, Bold, ExtraBold, Black, ExtraBlack. Most fonts only have two weights (Normal and Bold) — but the nice ones that designers like have many more. If the font doesn’t have the weight you request, WPF will choose the weight closest to the value you specified.

FontStyle

Used to italicize text. There are three values: Normal, Italic, and Oblique. Almost every font defines special characters for the Italic style, while Oblique draws the same characters as Normal, but on a slant (inevitably looking worse, and being less readable, than the italic face). The difference is illustrated below:

Examples of Italic, Oblique, and Normal-styled text

FontStretch

If a font has multiple faces with different widths, this allows you to choose between them. Valid values are between 1 and 9, but like FontWeight, there are named shortcuts: UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, Normal, SemiExpanded, Expanded, ExtraExpanded, UltraExpanded. Unfortunately, only high-end fonts come with these faces (WPF will not algorithmically stretch a font).

TextEffects

Used to apply an effect to a piece of text. See my previous post on TextEffects for a thorough description.

Typography

This property is very large, and merits (several) posts of it’s own. Basically, this property exposes the many of the advanced features available from OpenType fonts (aka, expensive fonts you probably don’t have but wish you did).

Here’s a list of the various options available through the property (I’ve already posted examples for some of these properties, I’ll add links as I write more samples — Warning: the XAML in those older posts is probably no longer valid due to namespace changes and property renames):

  • AnnotationAlternates
  • Capitals: Small caps, etc
  • CapitalSpacing
  • CaseSensitiveForms
  • ContextualAlternates
  • ContextualLigatures
  • ContextualSwashes
  • DiscretionaryLigatures
  • EastAsianExpertForms
  • EastAsianLanguage
  • EastAsianWidths
  • Fraction
  • HistoricalForms
  • HistoricalLigatures
  • Kerning
  • MathematicalGreek
  • NumeralAlignment
  • NumeralStyle
  • SlashedZero
  • StandardLigatures
  • StandardSwashes
  • StylisticAlternates
  • StylisticSet1 through StylisticSet20: Yes, there are really twenty of them.
  • Variants: Used for Subscript, Superscript, etc

Phew, that was a long list! Lucky for you, there won’t be a test any time soon. Moving on …

Properties from Inline

The Inline superclass defines three new properties that can be applied on inline text.

TextDecorations

This property lets you draw a horizontal line around the text — it’s mostly used to underline a word. There are four possible line positions: Underline, Overline, Strikethrough, and Baseline. Underline draws a bit below the baseline so the line doesn’t touch the (most of) the actual letters, while Baseline is drawn directly on the text baseline.

You may have noticed that the name of this property is plural, that’s because you can set more than one decoration for the text. Unfortunately, the syntax for this isn’t as clean as TextDecorations="Underline Overline", you have to use much more verbose syntax:

<Run>
  <Run.TextDecorations>
    <TextDecoration Location="Underline" />
    <TextDecoration Location="Overline" />
  </Run.TextDecorations>
  Help! I'm surrounded by lines
</Run>

Also, an individual TextDecoration has a Pen property, meaning you can choose the Brush used to draw the line, change the Thickness, or each use the DashStyle property to change how your underlines work (it will surely look awesome on your MySpace).

BaselineAlignment

This property allows you to vertically position an inline element within the line. The legal values are: Bottom, Baseline, Center, Top, Subscript, Superscript, TextBottom, and TextTop. The image shows the values in action:

Illustration of the values of the BaselineAlignment property

There are some fine typographic distinctions between TextTop, Top, and Superscript (as well as their mirror values for the bottom) — but I’m guessing you don’t really care about those (they’re pretty much the same as CSS, if you really must know).

You probably won’t use this property very much, but it comes in handy when you’re dealing with non-text objects (i.e. things within an InlineUIContainer), or if you’re trying to create a fake subscript or superscript effect because your font doesn’t support the real thing.

FlowDirection

This property is useful if you’re including text from languages that use a right-to-left reading order (such as Arabic or Hebrew). It’s also exposed on many other elements, such as FlowDocument and all the Block-derived classes.

“Content” properties of inlines

Except for LineBreak, each Inline exposes a property that allows you to set it’s content. Unlike Control.Content, which is of type object, each of these properties is strongly-typed to the kind of content it can contain:

  • Run.Text of type string
  • Span.Inlines of type InlineCollection
  • InlineUIContainer.Child of type UIElement

Additionally, Hyperlink exposes a few properties (such as NavigateUri) so you can actually make a link functional.

Once again, we’ll skip over Figure and Floater for now — we don’t have enough background for them yet.

Differences from HTML

With the exception of TextEffects and Typography, these properties are quite similar to their CSS counterparts. You’ll run into slight spelling annoyances (CSS uses dashes in their names and values, while WPF does not, href is much easier to type than NavigateUri) — but you should feel pretty comfortable.

The exceptions would be the properties that don’t have CSS analogues: TextEffects and Typography. However, these properties aren’t used very frequently, so you rarely need to mess with the defaults.

Phone Recommendations

  • Road and Sky, Antelope Island, Utah

    Antelope Island, Utah

Apparently, my phone does not like coming to Utah — it’s been on the fritz all week, and I caught it saying goodbye to old friends (wallet, keys) and giving away its stereo.

I’ve had the phone for almost three years, and I’ve been quite happy with it. It’s small, has good battery life, and a reasonable menu system. It’s also unlocked, so I was able to use it in Europe and China.

A (used) replacement is pretty cheap on eBay — but perhaps I should move into the 21st century and get a more sophisticated phone. Any suggestions?