Skip past navigation, straight to the content

Category Archives: Work

Filipe Fortes used to work at Microsoft as a Program Manager on the Windows Presentation Foundation team — now he eats a lot of cheese.

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.

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>

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.

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.

So Long

This post is a bit overdue — but, as the saying goes, better late than never.

I left the WPF team (and Microsoft) a few months ago. Then, I went to Europe to go watch the World Cup.

As of four days ago, I’ll be working and living in Beijing for three months. If you’re interested in those adventures, you can check out the life section of this blog (yes, I know I neglected it for the past six months, but I’m here to repent).

If you’re looking to fill the WPF/Avalon void in your blog life, try:

As for this “work” blog — the blogging here will remain technical. I’m not sure which topics I’ll cover, but I’ll probably still occasionally write about WPF (I did spend four years working on it). Only time will tell.

Watch my Mix06 Talk

You can now view my Mix06 talk online, watch the thrilling Developing a Windows Presentation Foundation Application from the comfort of your own home!

You can see all the other talks at sessions.mix06.com. You should definitely watch Robby‘s talk: A Designer’s Overview of Windows Presentation Foundation.

Mike Swanson has tips for viewing the talks — I definitely recommend viewing them on high-speed (it makes everyone sound smarter too).

Thailand Screencast on Channel9

Screenshot of the Thailand WPF application

Channel9 has posted the full screencast in high resolution so you might actually be able to read what I’m typing (imagine that!).

Mix06 Thailand Demo Screencasts

I’ve recorded and posted screencasts for the demo-building portion of my Mix06 talk. It’s broken up into four parts:

  1. XamlPad: A quick, live introduction to XAML where I display some photos in a thumbnail view
  2. Visual Studio & Expression: I use Visual Studio and Expression to create the initial UI for the application
  3. Richer Typography: Adding a custom font to our application as well as page layout for the text
  4. Simple Video: Add video into the project and demonstrate code behind

I know everyone’s very excited to hear me stutter and sound silly over a PC microphone. Believe it or not, doing a screencast is harder than coding live on stage.

The total viewing time is just over 22 minutes (I’ll post a link to the combined video shortly). The application isn’t super-complex, but my goal during the talk was to give an overview and taste for the platform.

If there’s interest, I can expand upon the sample in order to make it more sophisticated.

If you have the Feb CTP installed, you can run the application via the browser:

A WPF XBAP application showing pictures from Thailand along with flowing, multi-column text

You can download the source files, but note that I haven’t included the font (Lindsey) in the source as the licensing terms do not permit it. Lindsey will be available with the WPF SDK when we release.

Update: Here’s a link to the combined video — which is still a little too blurry look good. I’m trying to find a better hosting solution for the video.

Update: Get a higher-res, full length version of the video on Channel9

Mix06 Demos Update

Sorry for the delay posting the materials from my Mix06 talk — I need to track down some licensing information for the fonts I used in one of my demos.

For those not at the talk, I had two main demos:

  • Feature Montage: I created a set of interactive slides that showed off various portions of WPF feature areas. This is the part that I need to change slightly before posting.
  • Thailand Browser Application: I built this demo live on stage. I’ve created some screencasts so you can watch this live (the first is posted, I’ll add links to the others in the next post).

In case you haven’t seen Mike Swanson’s announcement, the full Mix06 talks will be posted in the next couple of weeks.

Mix06 Talk

My talk was yesterday — thanks for all who attended.

I’ll be posting the applications I showed in the next post (my laptop is about to die).

If you took pictures during my session, I’d love to get a link / copy.

Mix06 and Powerpoint

I’ll be speaking at Mix06 in Las Vegas this Monday — I’m giving a developer-focused overview of WPF (4:30 on Monday, if you’re interested).

One of the original goals (gimmicks?) for my talk was to not use Powerpoint — I didn’t want my talk to turn into a boring, slide-focused hour. I hoped that not having Powerpoint would force me to come up with a gripping, unique talk that would win many awards, honors, an Oscar, presidential medal of honor, and possibly a pony.

Well, after working on the talk for a few weeks, I’m removing this goal for a couple of reasons:

  1. Just like the PDC talks, the sessions at Mix will be recorded and archived on video. However, the chaptering is integrated with Powerpoint. Without slides, there will be no chaptering in my talk, making it very hard to scan later on.
  2. It’s silly. Plenty of great talks have been given with Powerpoint — and plenty of horrible talks have been given without it. Content, flow, and the speaker are what make or break a talk, not the file format.

Alternatively:

Why I'm Using Powerpoint, as a Powerpoint Slide

Don’t worry — I don’t think that slide will make the cut.

Five Steps to Font Freedom

Adrian has a post titled Five Steps to Font Freedom on the Be A Design Group blog. I’ve quoted some of it below:

There is something absurd about typography on the web. Think about these scenarios: You don’t need to own a font to read a book set in Goudy. You don’t need to own Futura to watch a Wes Anderson film. You don’t need to own Times to read the Times. You don’t need to own any fonts to watch television. Why not? Because that would be insane. And yet this same logic doesn’t apply on the internet. Online, a person needs to own a fully licensed version of a font in order to view it in a web browser. You are reading Arial right now. That’s right, Arial. Why? Because everybody on Earth has a licensed version of Arial on their computer. The great democracy of the internet has failed to produce typography any better than the least common denominator of system fonts. As a designer, I hope you are outraged and offended. So what can you do about it?

Those who know me (or have seen me speak) know that I feel pretty strongly about the lack of variety in widely distributed fonts. Almost every page uses one of the same five fonts (Verdana, Georgia, Arial, Lucida Sans, or Times). The lack of variety can make it tough to create strong branding and beautiful designs on the web.

Designers tend to work around this issue by creating text in Photoshop or Illustrator and exporting to an image. Flash also provides the ability to use fonts that aren’t locally installed (this is the key to the popular Sifr technique). Unfortunately neither technique works well for reading long documents.

The release of Vista will help (but not solve the issue) for two reasons:

  1. New high-quality fonts: Poynter was the first to show the new Microsoft fonts being distribute with Vista (some will be distributed with Office as well). All six of the new fonts are OpenType, and will provide much needed variety from the current popular Windows fonts.
  2. Font embedding in WPF: I haven’t had a chance to write a blog entry about this, but you can embed fonts into your WPF/Avalon application (even ones hosted in the browser). Many fonts provide licensing terms that allow you to freely embed and redistribute a font in an application (the WPF SDK will provide several free fonts from Ascender for this purpose).

Adrian proposes some solutions — but one thing he’s missing is reliable technology for font embedding in web browsers. IE has this feature but you don’t see it used much. Probably due to a combination of the following issues:

  • Download size for quality fonts: Embedding a high-quality font can easily balloon a page size
  • Lack of embeddable fonts: Not all fonts are licensed for embedding
  • No cross-browser support: I’m not sure how much this was the issue, since many other IE-only features were adopted before they had cross-browser support