Silverlight to become Microsoft’s next VB6?

There was a huge uproar in the tech blogs this past week regarding some comments made by Bob Muglia (of Microsoft) as reported by Mary Joe Foley in a post entitled, “Microsoft: Our Strategy with Silverlight has shifted.”

The quotes that caused the most ruckus are:

Silverlight is our development platform for Windows Phone,” he said. Silverlight also has some “sweet spots” in media and line-of-business applications, he said.

 

But when it comes to touting Silverlight as Microsoft’s vehicle for delivering a cross-platform runtime, “our strategy has shifted,” Muglia told me.

 

Silverlight will continue to be a cross-platform solution, working on a variety of operating system/browser platforms, going forward, he said. “But HTML is the only true cross platform solution for everything, including (Apple’s) iOS platform,” Muglia said.

OK, so many who read this read a lot between the lines.

Whatever HTML5 means to you (and your definition is likely different than mine unfortunately), it can’t do everything. There’s still a place for Silverlight and Flash in this world. Many consumer facing web sites, simply don’t need Flash or Silverlight. Either of these browser plug-ins can enhance the consumer experience, but rarely are they needed for the average web site. You won’t likely see more Flash or Silverlight on traditional consumer facing web sites.

Thankfully, BobMu responded and tried to calm some fears (which was only somewhat effective).

I’d consider there are a few places where HTML (4+) is not yet rich enough to provide the type of experience demanded by users:

  • Games. JavaScript and HTML just isn’t yet up to the task of creating a good rich game. It’s not really the platform’s fault – it just wasn’t designed with it in mind.
  • Business Applications. It’s great that Twitter can run completely in the web browser or that you’re able to enter a street address to collect a consumer’s home shipping address for a package (with the ability to provide some text hinting as a bonus). But, business applications are far more complex, and require robust data and input handling that are very challenging to handle, especially cross browser. Layout of complex data (tables or not) can be maddening and extremely inefficient in browsers, when data needs to be truncated, formatted, centered, sorted, etc.

    It’s easy to build a ineffective web application in HTML that doesn’t consider the user. Too easy. That’s where the plug-ins can excel when used properly.

Many things can be hacked to work in the web browser without Silverlight. However, this comes at a great cost of development and maintenance and QA. How many times have you written a web application and not needed to fix an issue that happens only in one browser (and worse, only in a particular version)? If you haven’t, it’s likely you haven’t written a complex web application or that your needs are very simple.

This is where Silverlight (and Flash/Flex) both shine. They provide a consistent and robust user experience across supported browsers and platforms. Write it once, and it really should run nearly anywhere the plug-ins are supported without issue. Furthermore, they both provide a better debugging and development experience than JavaScript/HTML.

Even though Silverlight and Flex are best used in Enterprise development, I worry that Microsoft may still abandon the platform sooner rather than later.

Microsoft totally missed the boat on Silverlight for games. If they had gotten a better foothold in that market, I’d be much less worried. I’ve never encountered a game that was written in Silverlight that wasn’t pointed by some Silverlight blog I follow. Flash I encounter all the time. Silverlight should be a decent gaming platform, but the development and design tools for gaming in Silverlight suck in comparison to those provided by Flash. Suck. There’s no real consideration for the type of animation and character creation that the Flash tools provide that game development shops need.

Blend – phhpt. Don’t get me started on how awful that would be to use as an animator. Expression Design? Ha! That thing is a joke compared to Flash CS5. At best, an animator could painfully create illustrations in Photoshop or Illustrator and then import them as layers into Blend, and then try to manage them … yuck. Too many tools and not enough interaction between them.

This is a new game that demonstrated at Adobe Max – beautifully done. It’s using Flash. I can’t imagine it being done in any other platform today.

So, that leaves business applications as the other major distinguishing feature of these plug-ins.

But, will that be enough?

It’s absolutely enough to keep them alive for another 3-5 years without any issues. Even once HTML5 settles into place and the major 3 or 4 browsers implement most of the features, there still will be a lack of good support for typical business applications. Again, it’s just not something HTML 5 was built for. It would require enhancements. HTML 6 maybe?

Eventually, browsers will support the typical enterprise web application needs. It’s at that point that the Flash and Silverlight’s we know of today will be retired. But, neither Microsoft or Adobe is going to sit idly by and watch their platforms die a slow miserable death. Both sell tools. That’s how they make money. The plug-ins generate no real money. It’s the tools. Once the tools stop being profitable, the technologies will be retired or open sourced. For the sake of enterprise development shops, one could hope for the latter (but my guess is that intellectual property issues surrounding much of the plug-in will make this impractical, especially video/audio codecs.).

The best chance for both Adobe and Microsoft seems to be in the application market. Not a pure web application delivered via the browser, but an out-of-the-browser application. Adobe AIR and Silverlight both provide a reasonably robust (and continuously improving) out of the browser experience that in some ways exceeds the native platform capabilities in terms of developer and designer productivity. Both allow developers to be far more productive than the equivalent HTML/JavaScript solution of reasonable complexity.

Furthermore, both are cross platform (Mac OS X and Windows). That’s a huge win for both companies. Although some predict that the rise of “tablets/pads” prove that the end is near for personal computers, Apple’s recent Macbook Air (2010) debut shows the opposite. It’s a slick lightweight laptop. (There are some Win7 notebooks that have similar characteristics). The keyboard is not dead. Giant 8 pound laptops are hopefully dead (except for those who want a “desktop replacement.” The traditional PC tower may be going away for many consumers, but typing and mouse driven interaction isn’t going away any time soon (and laptops aren’t generally very cheap or effective in an enterprise, especially where mobility isn’t important). You may be able to casually browse the web for a couple of hours (?!) on a touch screen tablet (like the iPad), but could you do data entry? Not for very long before you wanted to toss it out the window, or, attach a keyboard.

There’s still a place for many different form factors. As long as there are sufficient business enterprises in need of rich interactive applications, delivered over the web, using web services, there will be a place for Silverlight and Adobe’s Flash. When the time comes and they aren’t necessary anymore, it will be time to port and convert. Microsoft and Adobe won’t want to abandon you in that case either as they’ll want to provide new tools to help you move to the next “web platform.”

Eventually, Microsoft will announce, “Silverlight is being retired. We will support it for the next 3 years.” At that point, you may start the panic. For now though, continue on as usual. Always pick a solution based on the product. Don’t use Silverlight just because you think it’s more fun than HTML. Pick the right tool for the job.

As I said, it will happen. HTML 5 and its friends have accelerated its end, but it’s not happening so soon you should be considering throwing out all of your Silverlight books. Keep them. In fact, this is a good one.

(I would predict today though that Adobe’s products will outlast Microsoft’s)

How to bind ListBoxItem.IsSelected to a bound item in Silverlight 4.0

This technique requires the Blend 4.0 SDK (which is included in Blend 4.0 and is also available as a free download.

Someone on StackOverflow asked how to bind a collection of items to a ListBox in Silverlight where the IsSelected property of the ListBoxItem is bound to an IsSelected property of the data item.

WPF has the native ability within a style to set the a style’s setter property IsSelected to a value of the two way binding to an IsSelected Property. Slick.

Silverlight, has no such thing unfortunately.

But, there’s a work around that isn’t too awful. Seriously.

image

What I’ve done is mapped the look and feel of the ListBoxItem selection to the DataTemplate for the item and removed it from the standard ListBoxItemContainer style:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TestSilverlightTodoListItem" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="TestSilverlightTodoListItem.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>        

        <local:PeopleList x:Key="PeopleListDataSource" d:IsDataSource="True"/>        

        <Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
            <Setter Property="Padding" Value="3"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Top"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="TabNavigation" Value="Local"/>            
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid Background="{TemplateBinding Background}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="SelectionStates">
                                    <VisualState x:Name="Unselected"/>
                                    <VisualState x:Name="Selected">
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
                            <Rectangle x:Name="FocusVisualElement" RadiusY="1" RadiusX="1" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <DataTemplate x:Key="PersonTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <i:Interaction.Behaviors>
                    <ei:DataStateBehavior Binding="{Binding IsSelected, Mode=TwoWay}" Value="True" TrueState="Selected" FalseState="Unselected"/>                    
                </i:Interaction.Behaviors>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="Selection">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0:0:0.25"/>
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Selected">
                            <Storyboard>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="fillColor" d:IsOptimized="True"/>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Unselected"/>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <VisualStateManager.CustomVisualStateManager>
                    <ei:ExtendedVisualStateManager/>
                </VisualStateManager.CustomVisualStateManager>
                <Rectangle x:Name="fillColor" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1" Grid.ColumnSpan="2"/>
                <Rectangle x:Name="fillColor2" Fill="#FFBADDE9" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1" Grid.ColumnSpan="2"/>
                <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Grid.ColumnSpan="1"/>
                <TextBlock x:Name="textBlock" Text="{Binding Name}" Grid.Column="1"/>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource PeopleListDataSource}}" >
        <ListBox x:Name="myList" ItemsSource="{Binding}" 
            ItemContainerStyle="{StaticResource ListBoxItemStyle1}" 
            ItemTemplate="{StaticResource PersonTemplate}" 
            SelectionMode="Multiple" />
    </Grid>
</UserControl>

The real magic is using the DataStateBehavior (which is included in the Blend 4.0 SDK):

<i:Interaction.Behaviors>
    <ei:DataStateBehavior Binding="{Binding IsSelected, Mode=TwoWay}" Value="True" TrueState="Selected" FalseState="Unselected"/>                    
</i:Interaction.Behaviors>

This ties the IsSelected property of the Person class (see below) to two VisualStates that I defined in the DataTemplate. A “Selected” and an “Unselected” state.

I grabbed the rectangle from the standard ListBoxItem container template template.

In the code behind, I wired up the selection changed event:

public partial class MainPage : UserControl
{
    private PeopleList _items = new PeopleList();

    public MainPage()
    {
        this.DataContext = _items;
        InitializeComponent();
        myList.SelectionChanged += new SelectionChangedEventHandler(myList_SelectionChanged); 
    }

    void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // these both just need to toggle 
        foreach (object o in e.AddedItems)
        {
            Person p = o as Person;
            p.IsSelected = !p.IsSelected;
        }
        foreach (object o in e.RemovedItems)
        {
            Person p = o as Person;
            p.IsSelected = !p.IsSelected;
        }
    }

    void myList_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space  )
        {
            if (e.OriginalSource is ListBoxItem)
            {
                Person p = (e.OriginalSource as ListBoxItem).DataContext as Person;
                if (p != null)
                {
                    p.IsSelected = !p.IsSelected;
                }
            }
        }
    }
}

The selection changed toggles the state of each item. Without doing that, the selection doesn’t behave correctly. The SelectedItems list on the listbox no longer reflects the reality of the bound data items – but that shouldn’t matter in this case as the property of the item reflects the real state accurately.

For testing:

public class PeopleList : ObservableCollection<Person>
{
    public PeopleList()
    {
      this.Add( new Person { Name = "Henry", IsSelected = true });
      this.Add(new Person { Name = "Bonnie", IsSelected = true });
      this.Add( new Person { Name = "Clyde", IsSelected = false });
      this.Add( new Person { Name = "Ervin", IsSelected = false });
      this.Add( new Person { Name = "Timmy", IsSelected = true });
      this.Add( new Person { Name = "Jane", IsSelected = true });

    }
}

And:

public class Person : INotifyPropertyChanged
{
    private bool _isSelected;
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (value != _name)
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected != value)
            {
                _isSelected = value;
                RaisePropertyChanged("IsSelected");
            }
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Using Visual State Manager from a UserControl

To aid in an answer on StackOverflow that I had recently answered, I’m providing part of the response here.

The question was essentially, “what’s a way to use DataTriggers in Silverlight, without DataTriggers?”

I had suggested one idea would just to use VisualStates and a code behind file.

That’s what I’ve done here. I created an enum of type AnimateState, which has three possible values, Top, Left, and Right. By clicking on one of three buttons on the simple UI, it changes the value of the property, which in turn calls one of the VisualStates defined in the XAML.

In the example, it animates the position of the orange ellipse to various positions on the canvas.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace DemoShowVisualStateManager
{    
    public partial class MainPage : UserControl
    {
        private AnimateState _animateState;

        public MainPage()
        {
            InitializeComponent();
        }

        public AnimateState State
        {
            get { return _animateState; }

            set
            {
                if (_animateState != value && Enum.IsDefined(typeof(AnimateState), value))
                {
                    _animateState = value;

                    VisualStateManager.GoToState(this, value.ToString(), true);
                }
            }

        }

        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            AnimateState state;
            if (AnimateState.TryParse((sender as Button).Content.ToString(), out state)) 
            {
                State = state;
            }
            
        }
    }

    public enum AnimateState
    {
        Top,
        Left,
        Right
    }
}

 

<UserControl x:Class="DemoShowVisualStateManager.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Width="500" Height="500">

    <UserControl.Resources>
    </UserControl.Resources>
    <Canvas x:Name="LayoutRoot" Background="White">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="Positions">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:3"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Right">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="389" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="ball" d:IsOptimized="True"/>
                        <DoubleAnimation Duration="0" To="198" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ball" d:IsOptimized="True"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Left">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="-199" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ball" d:IsOptimized="True"/>
                        <DoubleAnimation Duration="0" To="390" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="ball" d:IsOptimized="True"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Top"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <Ellipse x:Name="ball" Stroke="#FFFFD9B8" RenderTransformOrigin="0.5,0.5" Height="100" VerticalAlignment="Top" Canvas.Top="10" Width="100" Canvas.Left="200">
            <Ellipse.RenderTransform>
                <CompositeTransform/>
            </Ellipse.RenderTransform>
            <Ellipse.Fill>
                <RadialGradientBrush Center="0.388,0.328" GradientOrigin="0.388,0.328" RadiusX="0.63">
                    <GradientStop Color="#FFF97200" Offset="1"/>
                    <GradientStop Color="#FFFFD9B8"/>
                </RadialGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <Button Content="Left" Height="33" Canvas.Left="200" Canvas.Top="229" Width="100" Click="Button_Click"/>
        <Button Content="Top" Height="33" Canvas.Left="200" Canvas.Top="266" Width="100" Click="Button_Click"/>
        <Button Content="Right" Height="33" Canvas.Left="200" Canvas.Top="303" Width="100" Click="Button_Click"/>

    </Canvas>
</UserControl>

image

Silverlight Analog/Retro Flip Numbers

I’m not sure what to call these exactly. I’ve created a relatively simple Silverlight 4 control that emulates the old mechanical flip style numbers (or letters) displays found at airports and in old clock-radios.

image

I call it the RetroFlipper.

It’s easy to use (at least for my needs). Declare an instance of the control in XAML:

xmlns:wpcontrols="clr-namespace:WiredPrairie.Controls;assembly=WiredPrairie.RetroFlipperControl"             

 

        <wpcontrols:RetroFlipper Margin="5,20" 
                                 x:Name="numberFlip100" Grid.RowSpan="1" Grid.Column="1"/>

And then respond to the “Flipped” event and set the “Text” property as needed.

            numberFlip0.Flipped += new EventHandler(numberFlip1_Flipped);
            numberFlip0.Text = "0"; //(0, 0);

The default animation speed can be adjusted:

numberFlip0.AnimationSpeed = 1;

It’s a percentage – 1.0 is the default. If you want the animation of the flip to be half speed for example, just set it to .5.

The class that drives the demo is really simple:

public partial class MainPage : UserControl
{
    private DispatcherTimer _timer;
    private int _inc = 0;

    public MainPage()
    {
        InitializeComponent();
        numberFlip0.Text = "0"; //(0, 0);
        numberFlip0.AnimationSpeed = 1;
        numberFlip10.Text = "0"; //(0, 0);
        numberFlip10.AnimationSpeed = .7;
        numberFlip100.Text = "0"; //(0, 0);
        numberFlip100.AnimationSpeed = .4;
        _timer = new DispatcherTimer();
        _timer.Interval = TimeSpan.FromSeconds(.5);
        _timer.Tick += new EventHandler(_timer_Tick); 
        
    }

    void _timer_Tick(object sender, EventArgs e)
    {
        int current = _inc;
        int next = ++_inc;
        if (next % 10 == 0)
        {
            numberFlip10.Text = Math.Floor(next / 10 % 10).ToString(); 
        }
        if (next % 100 == 0)
        {
            numberFlip100.Text = Math.Floor(next / 100 % 100).ToString(); 
        }

        numberFlip0.Text = (next % 10).ToString();            
    }

    private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        _timer.Start();
    }
}

(And no, it doesn’t handle numbers > 1000).

Building the control required a few tricks.

The most interesting was that I decided to use 4 layers to actually represent and animate the flip cards:

image

Using a few OpacityMasks

<Border.OpacityMask>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="Transparent" Offset="0.5"/>
        <GradientStop Color="Black" Offset="1"/>
        <GradientStop Color="Black" Offset="0.5"/>
        <GradientStop Color="Transparent"/>
    </LinearGradientBrush>
</Border.OpacityMask>

and some creative PlaneProjection and animations,

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="backBottom">
    <EasingDoubleKeyFrame KeyTime="0:0:0.17" Value="270"/>
    <EasingDoubleKeyFrame KeyTime="0:0:0.27" Value="180"/>
    <EasingDoubleKeyFrame KeyTime="0:0:0.30" Value="220"/>
    <EasingDoubleKeyFrame KeyTime="0:0:0.32" Value="180"/>
</DoubleAnimationUsingKeyFrames>

it’s possible to create the illusion of the mechanical parts moving.

Any text may be set into the Text property – it’s automatically sized to fill. So, it could be words, double digits, anything you’d like, as long as it’s text.

In any case, the demo is here.

The source code, licensed under BSD, is here.

Enjoy.

How to embed and use the Google Web Fonts in Silverlight

There are a few steps necessary to using one of the Google Web Fonts in Silverlight.

Step 1

Go to the directory of web fonts here.

  image

Step 2

Pick your favorite font and click the embed link:

SNAGHTML5af9c8a9

Step 3

Verify the license is acceptable to your needs.

SNAGHTML5afad2c6

Step 4

Click the “Get the code” tab:

image

Copy the location of the CSS and open it in your favorite editor. I just paste it into a new tab in Chrome. But you could open it in Visual Studio if you’d like for example (just File > Open).

Step 5

Grab the font URL from the CSS (copy the link to the clipboard).

image

Step 6

From the same tab in Chrome, I paste in that value which prompts me to download the file:

Give the font a file name and save it locally.

image

Step 7

In Windows 7, installing Fonts is easy (as easy as it should have been for years). For other operating systems, consult your OS docs.

SNAGHTML5aff9164

In Windows 7, simply click the image button.

Step 8-Blend 4 (RC)

In Blend 4, to use the font, you’ll need to select it once as a Font choice:

 image

Click the “Embed” checkbox to include it in your XAP file.

image

Step 8-Visual Studio 2010

In Visual Studio 2010, copy the font file to a new folder (suggest something like Fonts). Set the build action to Resource:

image

Step 9

Then, to use the font, set the FontFamily to be the Path/FileName.ext#FontName as shown here:

image

<Button Content="Login" Height="54" Margin="21,156,16,0" 
                x:Name="button1" 
                VerticalAlignment="Top" Click="button1_Click" Grid.Row="1" Grid.Column="1" 
                FontFamily="FONTS/INCONSOLATA.TTF#Inconsolata" />

 

Step 10

Sit back and enjoy the new font.