Skip past navigation, straight to the content

Video and Screenshots from the Mix Panel

Microsoft has posted videos from the Mix sessions, which means you can view the video of our panel online. There’s also a WMV version you can download directly (roughly 80 MB).

Unfortunately, the production quality of the video isn’t very good. The video shows only the projection feed, which was fairly static except for about 25 minutes worth of demos by myself and Tom Bodkin. Also, the projector in the room was running at 1280 by 720 pixels, which was then (stupidly) stretched to a different aspect ratio for the video. I’ve included a few non-stretched screenshots from my demo below:

Indigo Demo - Front Page

Indigo Demo - Geico Ad

Indigo Demo - Most Popular

If you don’t feel like watching the video, Tim Anderson has written a good summary of the panel.

During the session, I showed a demo that myself and Roger Black (amongst others) have been working on in the past couple of weeks. It’s a rendition of the English-language version of Reporte Indigo, a Mexican online weekly magazine currently done in Flash. Our goal was to show some of the directions we see online reading experiences moving toward: richer, branded layouts that look good across a variety of screen dimensions, integrated media, richer advertisements, and continued increases in community-driven features. My big fat mouth has more to say about this area, but that will have to wait until another post.

Come See Me at Mix

Those attending Mix 07 next week in Las Vegas might be interested in going to Beyond the Reader: Improving the Online Media Experience, a panel discussion featuring yours truly (along with Roger Black of The Font Bureau/Danilo Black and Tom Bodkin of the New York Times). It’s currently scheduled during the first timeslot on Wednesday morning.

Here’s the abstract:

Is it really possible to make online narrative content glamorous? Smart designers are complementing their traditional strengths in branding and narrative with technologies such as WPF to create highly flexible, readable and vibrant online media products. See how designer-delivered digital media can work on-and-off-line, in-and-outside the browser. Envision next year’s portal digital world and how can you become part of it. For producers of newspapers, magazines, and TV content, this is the next Web.

Commuting, Happiness, and Seattle

This week’s New Yorker has an interesting article by Nick Paumgarten, There and Back Again, which really resonated with me. Here’s a relevant quote:

Three years ago, two economists at the University of Zurich, Bruno Frey and Alois Stutzer, released a study called “Stress That Doesn’t Pay: The Commuting Paradox.” They found that, if your trip is an hour each way, you’d have to make forty per cent more in salary to be as “satisfied” with life as a noncommuter is … The commuting paradox reflects the notion that many people, who are supposedly rational (according to classical economic theory, at least), commute even though it makes them miserable. They are not, in the final accounting, adequately compensated.

“People with long journeys to and from work are systematically worse off and report significantly lower subjective well-being,” Stutzer told me. According to the economic concept of equilibrium, people will move or change jobs to make up for imbalances in compensation. Commute time should be offset by higher pay or lower living costs, or a better standard of living. It is this last category that people apparently have trouble measuring. They tend to overvalue the material fruits of their commute—money, house, prestige—and to undervalue what they’re giving up: sleep, exercise, fun.

I was spoiled by growing up in a small town — I found my daily commute from downtown Seattle to Redmond to be dreadful. It’s a little under 15 miles, but a one-way journey can take anywhere from 30 minutes to an hour and a half at peak hours (the median is about 45 minutes, but travel times are unpredictable). Honestly, this was a big reason I ended up leaving Microsoft.

The article brings up an interesting way to decide where to live:

Putnam likes to imagine that there is a triangle, its points comprising where you sleep, where you work, and where you shop. In a canonical English village, or in a university town, the sides of that triangle are very short: a five-minute walk from one point to the next. In many American cities, you can spend an hour or two travelling each side. “You live in Pasadena, work in North Hollywood, shop in the Valley,” Putnam said. “Where is your community?” The smaller the triangle, the happier the human, as long as there is social interaction to be had. In that kind of life, you have a small refrigerator, because you can get to the store quickly and often. By this logic, the bigger the refrigerator, the lonelier the soul.

I would add another important location: where you see your friends.

I sold my car just before leaving for China last year, and I’ve stayed car-free since. Seattle isn’t an English village, but the points of my triangle/rectangle are all within walking distance of where I live — and I love it that way.

Block Elements

Unlike Inline elements, Block elements take up the entire width of the text column and have line breaks before and after their content. By far, the most common block element is Paragraph.

Here are the elements that shipped with WPF that derive from Block:

  • Paragraph: With a straightforward name, this element (along with TextBlock) is the only container for Inline elements.
  • Section: A container for other Block elements — analogous to Span, which contains Inline elements.
  • BlockUIContainer: A container for UIElement-derived classes to be displayed as a block. Analogous to InlineUIElement.
  • List: Creates an ordered or unordered list. Contains ListItem elements.
  • Table: Contains TableRowGroup
  • elements.

Additionally, there are a few helper classes that are a bit block-ish:

  • ListItem: Block container for use within a List.
  • TableRowGroup: Container for TableRow objects.
  • TableRow: Container for TableCell objects.
  • TableCell: Block container for use within a TableRow.

Just like the inline elements, all of these elements do not derive from UIElement or Visual — this is because they do not have a one-to-one mapping between their content and visuals on screen. The reasons for this, and their ramifications, will have to wait for the next post.

Differences from HTML

  • No nested paragraphs: It’s worth re-iterating, because you’ll probably run into it some time.
  • Strict structure for Lists and Tables: WPF is strict about the structure of Lists and, in particular, Tables. This leads to verbose markup.
  • Only one List: Unlike HTML, there are no specialized elements for ordered and unordered list. You use the MarkerStyle property.

Interesting Facts about Cheese

  • Cheese, Seattle, Washington

    Round One, before the wine

I took a wine and cheese pairing class last night, and learned a few things I’ll pass on to my millions of readers:

  • All Cheese Rind is Edible: Even the wax and foil (!) ones. Cheese makers spend time crafting the rinds to add to the flavor. Not all of the rinds taste great, but they’re edible.
  • Brie, and other soft cheeses, have less fat than hard cheeses: This is obvious in hindsight, but it’s because hard cheeses have less moisture, and therefore a higher percentage of fat.
  • The mold in blue cheeses is a penicillium: This was interesting for me because I’m allergic to the antibiotic version of Penicillin — but I have no symptoms when eating blue cheese (or my current favorite, soft Italian gorgonzola).
  • Non-pasteurized cheeses are legal in the US as long as they’re more than 60 days old: The libertarian in me tries not to imagine how much federal legislation exists around cheese.
  • Lactose intolerance is typically cow-milk intolerance: Most people are just fine with goat or sheep’s milk, as the intolerance stands from some cow-specific enzymes.
  • Traditional mozzarella (mozzarella di bufala) is made from water buffalo milk: I thought it was just a name, but it’s not. Apparently, there are some big water buffalo farms in California.
  • Goats have the highest proportional milk production of any farm animal

They also handed out the following chart, which shows the composition of various milks, by percent weight (the totals don’t add to 100 because I removed the Minerals column, do the math yourself if you’re curious):

Milk Type Fat Protein Lactose Water
Human 4.0 1.1 6.8 88
Cow 3.7 3.4 4.8 87
Cow: Holstein/Friesian 3.6 3.4 4.9 87
Cow: Brown Swiss 4.0 3.6 4.7 87
Cow: Jersey 5.2 3.9 4.9 85
Cow: Zebu 4.7 3.3 4.9 86
Water Buffalo 6.9 3.8 5.1 83
Yak 6.5 5.8 4.6 82
Goat 4.0 3.4 4.5 88
Sheep 7.5 6.0 4.8 80
Camel 2.9 3.9 5.4 87
Reindeer 17 11 2.8 68
Horse 1.2 2.0 6.3 90
Fin Whale 42 12 1.3 43

I’ve had Cow, Water Buffalo, Yak, Goat, and Sheep’s milk. I’m definitely curious about Reindeer and Fin Whale (how do they milk it?).

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?

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.

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.

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.

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.

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.

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.