Welcome to MSDN Blogs Sign in | Join | Help

Updated Silverlight Control Tutorial for Silverlight 2 Beta 2

I've finally gotten the Silverlight Control tutorial sample updated for Silverlight 2 Beta 2.

There have been some non-trivial changes to how controls are written between Beta 1 and Beta 2.  My goals were to do more than a straight port.  I wanted to take advantage of some of these changes as an example of how to use the new functionality, and I wanted to address some feedback I've gotten from the original post.  Some of the ways I chose to do things in the original post were overly complicated, and I took this opportunity to streamline things a bit.  The result is the same functionality with a lot less code.

Default template

The major change centers around the Visual State Manager.  When my team and I first started working with Silverlight, we found the existing templating model to be difficult and confusing.  The model of defining all of your animations as key-framed timelines was work intensive and difficult to get right.  In addition, the model of having parts and states defined in the same way led to what we called "state explosion".  This occurred with controls like the CheckBox when you get into permutations of states - "Checked Focused MouseOver", "Checked Unfocused MouseOver"..."Unchecked Unfocused MouseOver"..."Checked Disabled"....you get the idea.  Each time you added another axis, you added another state to define and it quickly got out of control.  I think CheckBox had 18 states at one point.  Not good.

We brought this up with the Blend team and they came up with a great solution to the problem: Visual State Manager.  Not only did this simplify things by allowing the system to compute may of the transitions, but it also allowed Blend to implement a MUCH nicer tooling experience (Tim has a great overview here).   Doing this conversion was the first time I'd used this in action and the difference is dramatic.  I'm so glad we were able to do this.   We got together with the Blend and Silverlight teams and workout out a way to get it into the platform.  It's a huge win.

The other changes are simplifications and updates due to changes in the Silverlight platform (there weren't many of these).

Basically, in my original sample, I wasn't taking advantage of binding properly.  So I had some properties and parts I didn't need.  Moreover, I committed some "no-nos" like including code in my CLR property wrapper for accessing a Dependency Property.  Fixing these issues up really smoothed things along.

And, finally, in the app.xaml, I included to very basic templates to show what a simple template would look like.  One collapses horizontally, the other vertically:

Horizontal Collapse vertical collapse

To give you an idea how much things are simplified using VSM. here are some before and after code samples:

Beta1:

        protected override void OnApplyTemplate()

 

        {

 

            base.OnApplyTemplate();

            // Fish out all of the template children and wire them up.            //

 

            _rootElement = GetTemplateChild(ExpandoHeaderControl.RootElement) as FrameworkElement;

            if (_rootElement != null)

 

            {

 

                bool opened = IsOpened;

                _buttonElement = GetTemplateChild(ExpandoHeaderControl.ButtonElement) as ToggleButton;

 

                if (_buttonElement != null)                {

 

                    // setup the buttons initial state.

 

                    //

 

                    _buttonElement.IsChecked = opened;

 

                    _buttonElement.Click += new RoutedEventHandler(ToggleButtonElement_Click);

 

                }

 

                _openAnimation = _rootElement.Resources[ExpandoHeaderControl.OpenAnimation] as Storyboard;

 

                _closeAnimation = _rootElement.Resources[ExpandoHeaderControl.CloseAnimation] as Storyboard;

 

            }

 

            ChangeVisualState();

 

            _templateLoaded = true;

 

        }

 

        private void ChangeVisualState()        {

 

            // manage the animations base on the current state.

 

            //                       

 

            Storyboard toState = IsOpened ? _openAnimation : _closeAnimation;

 

            Storyboard fromState = !IsOpened ? _openAnimation : _closeAnimation;

 

            if (toState != null)            {

                if (!_templateLoaded)                {

 

                    toState.SkipToFill();

 

                }

 

                else                {

 

                    toState.Begin();

 

                }

 

            }

            if (fromState != null)            {

 

                fromState.Stop();

 

            }

 

        }

Beta 2:

        public override void OnApplyTemplate()        {          

            base.OnApplyTemplate();

 

            // fetch the button and hook up to it's click event.

 

            //

 

            _buttonElement = GetTemplateChild(ExpandoHeaderControl.ButtonElement) as ToggleButton;

 

            if (_buttonElement != null)            {

 

                _buttonElement.Click += new RoutedEventHandler(ToggleButtonElement_Click);

 

            }           

 

            // set up our initial state

 

            //

 

            ChangeVisualState(false);           

 

        }

 

        private void ChangeVisualState(bool useTransitions)        {

 

            // Tell VSM to manage the animations based on the current state.

 

            //                                   

 

            VisualStateManager.GoToState(this, IsOpened ? NormalState : ClosedState, useTransitions);

 

        }

Much simpler!  Note the call to VSM in the ChangeVisualState method.

The other changes to call out.  To get generic.xaml to work, you need to specify a DefaultStyleKey in your constructor:

        public ExpandoHeaderControl()        {       

            DefaultStyleKey = typeof(ExpandoHeaderControl);

 

        }

Also note OnApplyTemplate is now public.

Other than that the process is basically the same as documented in the prior tutorial.  Inside of the generic.xaml file, you'll see how I templated the ToggleButton.  The animation on ToggleButton took me a long time on Beta 1, and I never got it quite right.  With the Blend June Preview that supports VSM, this was a snap.

Posted by sburke | 3 Comments
Filed under:

Attachment(s): HeaderB2.zip

Building a Storefront using ASP.NET MVC

If you're interested in what's going on with the new ASP.NET MVC project, Rob Conery has just launched a new series of webcasts that document the process of him building out an MVC Storefront.  He's been iterating on this idea for a few weeks and it's coming together very nicely - I think you'll find it a nice change of pace from standard webcast fare.

Rob's ASP.NET MVC Storefront Series

Posted by sburke | 0 Comments

Tutorial: Writing a Templated Silverlight 2 Control

[UPDATE: For a Beta 2 version of this control, click here

We're going to create this control:

image

It's called the ExpandoHeaderControl, and it does two basic things.  First, it has an area for a header, and a collapsible content area, with a ToggleButton to manage when the content is visible or not (e.g. collapsed).

For this tutorial, I'm trying to simplify concepts as much as possible. For more sophisticated, industrial-strength concepts, check out the full control source available for the Source Code for Silverlight 2 Beta 1 Controls.

I'm continually amazed by how much power Silveright 2 provides.  This control will require about 100 lines of code to write.  Really!  Let's get started.

Step 1: Defining your control's template parts. 

What are the parts of your control that the logic has to interact with?  These should be the the defined "parts" of your control.  There are two types of objects that your control cares about.  First, it's the elements that are going to drive the UI or layout.  And, second, are the transition Storyboard animations that will cause your control's UI to move from one state to the next.  Let's focus on the UI parts right now.

We want to make sure that we give designers the most flexibility possible.  So our code should be as general as possible.  If you look at the code in the Silverlight 2 Beta 1 Controls package, you'll see great examples of this.  The code running the control is very agnostic about what the UI is actually doing.

So for our control, we'll define a few parts:

  1. The RootElement, which is the container for all of the UI.  This is important because it's also where we'll stick the resources that have our Transitions.
  2. The HeaderElement, which is the element that contains the header content.
  3. The ContentElement, which is the element that will parent the main content in the collapsible area.
  4. The ButtonElement, which is the ToggleButton that will control the collapsed state.

Usually, when we start writing our control, the first step is to add these attributes to our control class:

   [TemplatePart(Name=ExpandoHeaderControl.RootElement, Type=typeof(FrameworkElement))]
   [TemplatePart(Name=ExpandoHeaderControl.HeaderElement, Type=typeof(ContentControl))]
   [TemplatePart(Name=ExpandoHeaderControl.ContentElement, Type=typeof(ContentControl))]
   [TemplatePart(Name=ExpandoHeaderControl.ButtonElement, Type=typeof(ToggleButton))]    
   public class ExpandoHeaderControl : ContentControl
   {        
       private const string RootElement = "RootElement";
       private const string HeaderElement = "HeaderElement";
       private const string ContentElement = "ContentElement";
       private const string ButtonElement = "ButtonElement";  

Note that we do two small, but important, things here.  First, we use static strings for the element names.  This is good practice because we'll use them again later.  Second, we specify what type of element the Template Part needs to be.  This should be the most general type that you need for a given element.  If you use specific types here (for example Grid instead of FrameworkElement for the root), it will be much more difficult to template your control.  In the case of the ButtonElement, we chose ToggleButton rather than Button so we can ensure that it has a specific state.  If we used just Button (or ButtonBase), we'd need to track this ourselves. 

Step 2: Define your control's transition animations

What are the animations that your control will need to transition from one state to the next?  Defining transitions is just the same as defining the parts - use the TemplatePart attribute.  The main difference here is that the type will always be Storyboard.

Let's add in the animation declarations:

[TemplatePart(Name=ExpandoHeaderControl.RootElement, Type=typeof(FrameworkElement))]
    [TemplatePart(Name=ExpandoHeaderControl.HeaderElement, Type=typeof(ContentControl))]
    [TemplatePart(Name=ExpandoHeaderControl.ContentElement, Type=typeof(ContentControl))]
    [TemplatePart(Name=ExpandoHeaderControl.ButtonElement, Type=typeof(ToggleButton))]    
    [TemplatePart(Name = ExpandoHeaderControl.OpenAnimation, Type = typeof(Storyboard))]
    [TemplatePart(Name = ExpandoHeaderControl.CloseAnimation, Type = typeof(Storyboard))]
    public class ExpandoHeaderControl : ContentControl
    {        
        private const string RootElement = "RootElement";
        private const string HeaderElement = "HeaderElement";
        private const string ContentElement = "ContentElement";
        private const string ButtonElement = "ButtonElement";        
        private const string OpenAnimation = "OpenAnimation";
        private const string CloseAnimation = "CloseAnimation";

Step 3:  Write your OnApplyTemplate logic

After a control is loaded, its UI is populated from it's template.  To do this, the override of OnApplyTemplate is called by the framework.   For the most part, this code always looks about the same. 

For each of your parts, you're likely to want to have a member variable to access the element later, if you'll need to manipulate it:

        private FrameworkElement _rootElement;
        private ToggleButton _buttonElement;
        private Storyboard _openAnimation, _closeAnimation;
        
        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // Fish out all of the template children and wire them up.
            //
            _rootElement = GetTemplateChild(ExpandoHeaderControl.RootElement) as FrameworkElement;

            if (_rootElement != null)
            {
                     
                _buttonElement = GetTemplateChild(ExpandoHeaderControl.ButtonElement) as ToggleButton;
                _openAnimation = _rootElement.Resources[ExpandoHeaderControl.OpenAnimation] as Storyboard;
                _closeAnimation = _rootElement.Resources[ExpandoHeaderControl.CloseAnimation] as Storyboard;
            }
        }

One thing to note is that we access parts and transitions differently.  Note how we access the transitions out of the root element's Resources collection. 

Step 4: Create any properties you'll want to bind to in your template

Silverlight and WPF have a feature called Template Binding.  Template Binding allows you to "pass through" settings from a control to the UI defined in the Template.  For example, imagine your control has a TextBlock in it.  You'd like to be able to set the font properties of that TextBlock in a way that doesn't force the user to understand how the template is put together.  Template Binding allows you to reference properties on the object being templated and set those values into the template, similar to data binding.

Our control has two content areas:  the header, and the content itself.   Since our control derives from ContentControl, it already has a property called "Content" that we can use for the main content area.  But we want another one called HeaderContent to specify that, so we'll create one.  For a property to be bindable, it has to be defined as a DependancyProperty.  Visual Studio 2008 has a built in snippet for defining these.  It's meant for WPF, but it's close enough.  Just type "propdp".

image

When you do this, fill in the various fields.  In this case, the property's type should be object, and it's called HeaderContent:

       // Content property for the header
       //
       public static readonly DependencyProperty HeaderContentProperty =
           DependencyProperty.Register("HeaderContent", typeof(object), typeof(ExpandoHeaderControl), null);

       public object HeaderContent
       {
           get { return (object)GetValue(HeaderContentProperty); }
           set { SetValue(HeaderContentProperty, value); }
       }

The snippet also creates the CLR property with accessors as well!

Step 5: Create a simple Template for Testing

Okay, now it's time to throw some UI in there.  We'll create a very simple template that does everything we need.

<Grid x:Name="RootElement">
        <Grid.Resources>
            <Storyboard x:Key="OpenAnimation">
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="(UIElement.Opacity)">
                    <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="1.0"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
            
            <Storyboard x:Key="CloseAnimation">
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="(UIElement.Opacity)">
                    <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="0"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
            
        </Grid.Resources>
    <Grid.RowDefinitions>                                
        <RowDefinition Height="50"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>
        <ContentControl  HorizontalAlignment="Left" Background="Red" Content="{TemplateBinding HeaderContent}"/>
        <ToggleButton Grid.Column="1" HorizontalAlignment="Right" x:Name="ButtonElement" Content="X"/>
    
    <ContentControl Grid.ColumnSpan="2" Grid.Row="1"  Grid.Column="0" x:Name="ContentElement" 
                    Content="{TemplateBinding Content}" Background="Blue"/>
    
    

</Grid>

Okay, there's our template.  When instantiated, it looks like this:

image

Told ya it was simple.  Let's take a look at what parts we have in the template and how they match up with the control.

In the template, we define the animations at the top as resources off of the RootElement.

Notice we reference them by Key, not by Name.

For this control, we've defined a 2 row, 2 column Grid for our layout.  In the top row, we have the HeaderElement and the ButtonElement.  In the second row, we have the ContentElement, with a RowSpan of 2 so it fills up the bottom.  The red area and the words "header" and "Content Area" come from the control's usage, not the control itself or the template (see below).  In the Template above, you'll see two instances of "TemplateBinding" like "{TemplateBinding HeaderContent}".  When the control is templated, it will substitute the value of the controls "HeaderContent" property in that position. 

In our main XAML page, we've declared this control like this:

<my:ExpandoHeaderControl Width="200" x:Name="Header" Style="{StaticResource SimpleTemplate}" HeaderContent="header">
                        
       <my:ExpandoHeaderControl.Content>
          <Grid>
             <Rectangle Fill="Red" Stretch="Fill"/>
             <TextBlock Text="Content Area" HorizontalAlignment="Center" VerticalAlignment="Center"/>
         </Grid>
       </my:ExpandoHeaderControl.Content>

</my:ExpandoHeaderControl>

You may be wondering where to put that template.

In most cases, the Template will either be inline with the control's declaration (as it's Template property value, example in Step 8 below) in the XAML. This is good for one-off templates but doesn't let you share a template across controls. The more common way is as a resource defined in App.XAML (as we've done here). then it's hooked us as a StaticResource into the controls style property, as you see above.

Step 6: Managing State Changes

Now we've got the UI working, but the button doesn't know what to do when we push it.   Let's go back to our code and fix that.

The way this is usually done is to create properties to represent the state of your control.  In our case, the main piece of state is whether-or-not the control is collapsed.  So we'll add a property "IsOpened" to manage that.

// Property that determines if the expando is opened.
//
public static readonly DependencyProperty IsOpenedProperty =
    DependencyProperty.Register("IsOpened", typeof(bool), typeof(ExpandoHeaderControl), new PropertyChangedCallback(NotifyIsOpenedChanged));

private static void NotifyIsOpenedChanged(DependencyObject dpObj, DependencyPropertyChangedEventArgs change)
{
    bool isOpened = (bool)change.NewValue;

    ((ExpandoHeaderControl)dpObj).IsOpened = isOpened;
}

public bool IsOpened
{
    get
    {
        if (_buttonElement != null)
        {
            return _buttonElement.IsChecked ?? false;
        }
        else
        {
            return (bool)GetValue(IsOpenedProperty);
        }
    }
    set
    {
        if (_buttonElement != null)
        {
            _buttonElement.IsChecked = value;
        }
        else
        {
            SetValue(IsOpenedProperty, value);
        }
        ChangeVisualState();
    }
}

This looks a bit complicated.  We want to be able to bind to this property, so we've declared it as a DependancyProperty.   And we want to make sure it mirrors the actual state of the button, so if we have one of those, we'll just use its checked state.   But if we don't have one from the template, we'll just fall back to our own value.

One other note - we're hooking the changed value here.  If someone changes this value, we want to know about it so that we can update our state.  When the DP changes, our static handler will be called.  From that, we figure out which control fired the change, and update the state as appropriate.

Now that we've added the property, we can add some code in OnApplyTemplate to hook up to the Button's Click event:

bool opened = IsOpened;

_buttonElement = GetTemplateChild(ExpandoHeaderControl.ButtonElement) as ToggleButton;

if (_buttonElement != null)
{
    // setup the buttons initial state.
    //
    _buttonElement.IsChecked = opened;
    _buttonElement.Click += new RoutedEventHandler(ToggleButtonElement_Click);
    
}

Finally, we want a unified place to manage the state animations.  For that we've created a method called ChangeVisualState which plays the right animations for each state change.

This code may look funny, but to make sure we handle the case of an interrupted transition, we should start the "to" state StoryBoard before stopping the "From" one.

void ToggleButtonElement_Click(object sender, RoutedEventArgs e)
{
    // just update our state.
    //
    ChangeVisualState();
}
private void ChangeVisualState()
{
    // manage the animations base on the current state.
    //                        
    Storyboard toState = IsOpened ? _openAnimation : _closeAnimation;
    Storyboard fromState = !IsOpened ? _openAnimation : _closeAnimation;

    if (toState != null)
    {
        
        if (!_templateLoaded)
        {
            toState.SkipToFill();                    
        }
        else
        {
            toState.Begin();
        }
    }

    if (fromState != null)
    {
        fromState.Stop();
    }
}

We now have a working control!

Step 7: Specifying your default template

You'll notice that all of the SL 2 Beta1 controls have a nice default look and feel to them.  How is this accomplished?  Well, it takes a small amount of trickery.

The way you do this is by defining a XAML file called "generic.xaml" in your project and specifying it as a resource:

image

The Silveright Runtime will look for this resource and hook up templates for each specified type.  Your generic.xaml should look like this:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:HeaderControl;assembly=HeaderControl">

<Style TargetType="local:ExpandoHeaderControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ExpandoHeaderControl">
                    <!-- template xml -->
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

Step 8: Making it look nice!

I've been slowly going through Blend Kindergarten over the last few weeks.  I finally managed to get the hang of making nice glassy looking UI and was able to create a template to match.  If you'd like to learn this stuff, I highly recommend the tutorials over at the Liquid Boy blog.  They're simple and quickly taught me enough to be dangerous to myself and others.

I spent quite a bit of time mocking up the UI you see at the top of this post, and I think it looks pretty good.  Notice that I also templated the ToggleButton (as a nested template inside of the ExpandoHeaderControl Template in generic.xaml.

<ToggleButton Margin="4" Grid.Column="1" x:Name="ButtonElement" IsChecked="true">
    <ToggleButton.Template>
        <ControlTemplate TargetType="ToggleButton">
            <!-- glassy round Toggle Button Template XAML -->

        </ControlTemplate>
    </ToggleButton.Template>                                
</ToggleButton>

After I got the hang of this, it became a lot of fun.  The glassy look on the toggle button, and the funny little arrow didn't take too long to put together really.  For someone who doesn't have an ounce of design sense, I'm quite proud of myself.

Finally, here's how the control is declared on the page:

<my:ExpandoHeaderControl x:Name="sample" HeaderContent="Choose Color">
            
        <my:ExpandoHeaderControl.Content>
             <ListBox x:Name="lb" Height="100">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="2" Width="180">
                            <Rectangle Stretch="Fill" Fill="{Binding}"/>
                            <ContentPresenter Content="{Binding}"/>
                        </Grid>
                    </DataTemplate>                                
                </ListBox.ItemTemplate>
             </ListBox>                       
        </my:ExpandoHeaderControl.Content>

    </my:ExpandoHeaderControl>

Note the "{Binding}" syntax in the data template. Usually you specify a property in there like {Binding Name}, but in this case we're just using the item value itself, as in this case we're binding to an array of strings.

Again, here's the final, working product (if you're on IE/FF on Windows at least, not sure about Safari on Mac - shoehorning this into the blog has issues :))

 

Attached is the full project.  Enjoy!

Posted by sburke | 16 Comments
Filed under:

Attachment(s): HeaderControl.zip

Silverlight 2 Beta 1 Controls Available, including Source and Unit Tests

Get Silverlight 2 Beta 1

If you were watching the Keynote from MIX08, you know that Silverlight 2 Beta 1 is now available for download.

The package includes three components:

1) The Silverlight 2 Beta 1 Runtime - installs the basic Silverlight runtime components

2) The Silverlight 2 SDK - includes - installs tools for building Silverlight applications including the controls

3) Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 - installs a project system for Silverlight that works on Visual Studio 2008, including Silverlight XAML Intellisense, Expression Blend interop, and a design-time view of the Silverlight app that you're building.

Get the Source for the Controls

A few months back, we pulled together a team to build out this list of controls.  As part of this effort, we wanted to make sure we delivered something that would really help customers with using the Beta 1 bits. 

So we decided to do to things:

1) Provide source code for the components so users can use it as a sample, or to make changes to the components themselves.

2) Within that project, also ship the Unit Tests that our developers used when writing the components.

You can also download the Silverlight 2 Beta 1 Controls project package now.  The code in this package exactly matches the controls included with the Silverlight 2 Beta 1 SDK download (for example, TextBox, Image, etc. are implemented directly in the runtime).

Simply download the package and unzip it somewhere on your machine using the self-extracting zip.  Once you've done that, launch the project using the "MixControls.sln" solution in VS 2008.

When you launch the solution, you'll see six projects:

Controls - contains basic controls like Button, Checkbox, etc.

Controls.Extended - contains controls like Calendar, Slider, etc.

Controls.Data - contains the DataGrid control

Controls.Test - Unit tests for the Controls project

Controls.Extended.Test - Unit tests for the Controls.Extended project

Controls.Data.Test - Unit tests for the Controls.Data project

Controls Project Test Projects, Controls.Data, Controls.Extended

As expected, all the source code for the controls is in the project.

image

Testing Silverlight Control Code

You can then run the unit tests for any of the projects by launching it's corresponding "Test" project.  Our test harness runs inside of the browser and runs the unit tests.  There are a lot of them -- almost 1500 for the Controls assembly alone! -- and we've gotten very good code coverage.  In the case of the Controls.Test project, for example, we know we're getting over 80% code coverage from our unit tests.  This facility has allowed us to have very few regressions in our control development work, as well as quickly spot any possible issues in the underlying Silverlight runtime when we pick up daily builds. 

Silverlight Control Unit Tests

As you'd expect, the unit tests are basic but provide some functionality that you need for testing in an animated environment like Silverlight.  For example, if the template for a component defines animations, you need to wait for those to run and for the component to be added to the visual tree before checking the state.  You can't do this synchronously, and you can't access the UI thread from another thread.  So we came up with a unique easy to use system for this that handles all that for you, but still lets you write tests that are in one method and are easy to maintain.

Here's an example:

 

image

CreateAsyncTest takes the component, adds it to the Silveright surface, waits for it's Loaded event to fire, then runs the delegate function you've provided (in this case we're using the C# 3.0 Lambda syntax).  It's very clean and simple and allows very rapid writing and execution of tests.

In the controls themselves, you'll also see lots of things to help you write your own control.  In each controls project, you'll find a file called generic.xaml.  This is where you will find the default templates for all of our controls.  You can either customize this in place, or (preferably) use it as a starting point for creating your own templates.

To use these controls in your Silverlight project instead of the default, just add the DLL to your references as you would with any other .NET project and you're set.

More Resources

We're working on getting more sample apps up to help you do usage and templating of controls, but the online docs really are great, including videos and traditional MSDN content.  For example, check out this topic on templating a Button.  Keep an eye on Silverlight.net for more example apps.

I've found the code in these controls invaluable when building Silverlight applications.  I think you will too!

Posted by sburke | 26 Comments
Filed under: ,

MIX08 in Vegas this week

I'll be headed down to Las Vegas this week to attend the MIX08 show.  This is the third year of MIX and it's by far my favorite Microsoft event, and not just because it's in Vegas.  Like the last two years, this show should provide plenty of great surprises.

I'll be participating in a Panel at 1:30 on Wedneday titled "Opportunities and Challenges in Mashing Up the Web" if you want to find me to chat about Silverlight, AJAX, or anything else.  I'm also looking to do some networking to find some leads on filling an opportunity for a senior developer on my team, so if you know someone who might be a good fit, definitely let me know.

See you in Vegas!

[Update: Fixed the job URL above]

Posted by sburke | 2 Comments
Filed under:

Updated AJAX Control Toolkit release

As you know, the team has been very busy working on controls for the upcoming Silverlight 2 Beta 1 release.  Working on a new platform, with new tools, doing things that have never been done before is more than enough to keep us busy.

But we wanted to make sure we kept some focus on our AJAX Control Toolkit users.  As such, we pulled together some top-requested bug fixes as well as all the fixes we've recently gotten from our users, and have released the 20229 version of the Toolkit.  Thanks to all of our users that have been submitting patches - keep it up!

More details available from Kirti and David about what went into this release.

Posted by sburke | 5 Comments

Getting to know Silverlight 2 Beta 1

What we've been up to in DevDiv...

Today, Scott put up a mammoth post introducing the upcoming Silverlight 2 Beta 1. His post includes an 8 (yes, 8!) part walk through building out an application using it.  I really have to hand it to Scott on this one, and I'm not just kissing up because he's my boss.  He's been talking about this post he's been working on all week, and I went over a little bit of it with him on Monday.  But when I saw it live this morning, my jaw just about hit the floor.  To say the guy is prolific is an understatement.  Just earlier this week, he put up another big roadmap post.

I've been spending this week playing with the overall Silverlight 2 Beta 1 experience, which is coming along very nicely.   The integration between Blend and the Visual Studio tools is really, really nice.   I lack any UI design skills, but I'm starting to be able to build basic apps that look okay, and that's a big step forward to me.  I'm having fun.

image

What my team has been up to...

Like many new, cool, things, my team has been involved with this as well.  As a way to set ourselves up for delivering top-notch Silverlight controls in the future, we agreed to take on the task of building out some of the basic Silverlight controls, including Button, CheckBox, and ListBox.  The controls work great, are easily templatable, and will be very familiar to any WPF users out there.  My team is working with some other teams to deliver a broad suite of controls in Beta1 including DataGrid, Calendar, ToolTip, Hyperlink, and GridSplitter, among others.  Given where we are at in the product cycle, the available control Toolbox is coming along nicely.

But that's why we've been so quiet - it's been very busy.  But the model we're using - having the Silverlight Team build the runtime and a separate team build controls has really driven a lot of great feedback across the teams and resulted in a some real design and quality wins. 

Looking forward to getting this stuff out into your hands!

Posted by sburke | 10 Comments
Filed under:

.NET Framework Source & Symbols available for Windows Server 2008 & Windows Vista SP1

The build of the .NET Framework that we recently released source for was 2.0.50727.1433, which was the VS2008/.NET 3.5 RTM build.  A small change was made to the Framework after that, and this new version, 2.0.50727.1434, was then delivered to Windows Server 2008 and Windows Vista SP1. 

Since the source and symbols have to exactly match what's running on a developer's machine, this meant that customers running these new OS releases lost the ability to access the Reference Source for the parts of the .NET Framework that we've released.  The new symbols and source have now been deployed for the following:

  • mscorlib.dll
  • system.dll
  • system.data.dll
  • system.drawing.dll
  • system.web.dll
  • system.windows.forms.dll

The rest of the released source/symbols weren't updated.

Posted by sburke | 5 Comments

You can't domisticate a server!

Someone just pointed me at this "Stay At Home Servers" website.  Y'all know I'm a big Windows Home Server fan. 

Pretty solid geek humor, check it out!

Posted by sburke | 2 Comments

How to disable optimizations when debugging Reference Source

When you debug code in the .NET Framework using the newly available Reference Source functionality in VS 2008, you may notice that many variables are not available for inspection.

image

This is because you're debugging against retail-optimized code.  In many cases, since you can still step through, this is something that's manageable.

But what if you really need to get a better idea of what's going on?  Fortunately, there is a way.

What you need to do is to tell the CLR not to load the pre-JIT (aka NGEN) images.  Here is how to do it. 

First, create a CMD file that sets an environment variable, then launches Visual Studio.  I called mine "NoOptDevEnv.cmd", and it's contents are as follows:

set COMPLUS_ZapDisable=1
cd /d "%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\ide\"
start devenv.exe
exit

I put this cmd file on my desktop.   When I want to disable optimizations, and only when I want to do this, I launch VS from this command. 

Once in my Visual Studio project, do the following steps:

1) Right click on your project file and choose "Properties"

2) Choose the "Debug" tab and uncheck "Enable the Visual Studio Hosting Process"

3) Launch your application in the debugger.

Now, you'll see full local and member variable information:

image

Finally, you may be asking yourself "What is the Visual Studio Hosting Process (aka VSHost), and what happens if I turn it off?"  And this is a good question.

For the most part, disabling VSHost won't have any major impacts, but it will disable two features that you may be using.

First, you will not be able to do "Debug In Zone", which allows you to debug a process in the context of a security zone such as "Internet" or "Intranet".  That won't work without VSHost.

Second, Design Time Expression Evaluation for class libraries will also not work.  What that means, for example, is that if you are developing a Class Library, you won't be able to execute code from it in the Immediate Window while under the debugger.

In general, I recommend re-enabling VSHost (undo step 2 above) when you are finished with your debugging.

Hope that helps!

Posted by sburke | 8 Comments
Filed under:

Configuring Visual Studio to Debug .NET Framework Source Code

It's finally here - the launch of the .NET Reference Source project.  This post (hopefully!) contains everything you need to know.  Over the past few weeks, we ran a pilot of this feature and collected lots of great data that helped us work through some issues and understand where people were likely to have problems. 

First, though, if you have any problems, please make sure you've followed all of the steps exactly as described.  If you're still having problems, please check the FAQ/Troubleshooting section at the bottom.  If that doesn't work, post a comment below and I'll look into it.

BASIC SETUP

Note this functionality is not available on the Express versions of the Visual Studio 2008 products.

1) Install the Visual Studio 2008 QFE.  This Hotfix just updates a DLL that's part of the Visual Studio debugger that fetches the source files, more details on the download page.

 UPDATE:  If you get an error installing the Hotfix , try inserting your VS 2008 DVD and then running the Hotfix EXE again.  We're looking into the root cause - it's related to having a prior version of VS 2008 (e.g. Beta 2) installed on the machine.  But this workaround should allow the Hotfix to install properly.

 UPDATE (1/18): There were some problems with the QFE link above that have been addressed, sorry for the inconvenience, it's fixed now.

2) Start Visual Studio 2008 and bring up Tools > Options > Debugging > General.  If you are running under the Visual Basic Profile, you will need to check the box on the lower left of the Options Dialog marked "Show All Settings" before continuing (other profiles won't have this option).

Set the following two settings:

  • Turn OFF the "Enable Just My Code" setting
  • Turn ON the "Enable Source Server Support" setting

Your settings should be as below:

image

3) Next, bring up the "Symbols" Page and set the symbols download URL and a cache location.  Specifically, set the three settings below:

    • Set the symbol file location to be: http://referencesource.microsoft.com/symbols
    • Set a cache location.  Make sure this is a location that your account has read/write access to.  A good option for this is to place this path somewhere under your user hive (e.g. c:\users\sburke\symbols)
    • Enable the "Search the above locations only when symbols are loaded manually" option.

When you're finished, the settings should look like the image below:

image

Setup is done!  That's it, really!

DEBUGGING INTO FRAMEWORK SOURCE

For this simple example, we'll start with a blank C# Windows Application project, but it will work the same with a VB, Web, or WPF project.  To walk through this, go ahead and create that project.

Set a breakpoint in Form_Load:

image 

Now run your project to hit that breakpoint and go to your Call Stack window (CTRL+ALT+C).  In the Call Stack, right click a frame that starts with System.Windows.Forms.dll, and choose "Load Symbols".  This will load the symbols for the System.Windows.Forms assembly, which are about 10 megabytes, so the speed of the download will vary according to your connection speed.  Note that Visual Studio may be unresponsive during this time.   However, this download is a one-time cost for each assembly.  The symbols (PDB) file will be cached on your machine, in the directory specified in the steps above. 

Loading Symbols Manually

This will load the symbols for the DLL from the server, and you'll see some information in the status bar to reflect this.  Note that when this completes, the call frames will turn black and line numbers will be available.  Note you'll need to do the Right Click -> Load Symbols step each time you launch a debugging session (but, again, the symbols will now be cached locally so they won't have to download).  For more information on this, see the ADVANCED USERS section below.

image

You have now loaded the symbols for the Windows Forms DLL and can begin viewing the code.  You can view code in any way that you normally would in a debugging session.  In this case you can either Step In to the line of code above, or you can double-click one of the frames in the Call Stack Window.   For this case, we'll step in (F11).

The first time you step into code, we'll be presented with the EULA for accessing the source code.  Please take the time to read this EULA.  If you agree to the terms of the EULA, hit ACCEPT, and the source will then be downloaded.

That's it! You're now debugging .NET Framework Source!

Debugging Form.cs in Windows Forms

Now, for each assembly that you'd like to debug into just repeat the steps above (note you'll only see the EULA once, not for each file).

There are times when the Assembly you'd like to debug into isn't on the call stack, for example in the code below:

image

Before you step in to Graphics.DrawRectangle, you need to get the symbols for System.Drawing.Dll loaded.  To do this, we use the Modules Window (CTRL+ALT+U).  This lists all of the modules (DLLs) loaded by the debuggee.  Just find System.Drawing.DLL in this list, right click, and choose Load Symbols.

Load via Modules Window

Note that once a symbol file is loaded, the path to the symbol file shows up in the "Symbol File" column.

You can now step into the Graphics.DrawRectangle code above using F11!  In this case, note, you'll have to step through the PaintEventArgs.Graphics property code first.

ADVANCED USERS

Normally, each time you launch a debugging session, Visual Studio attempt to download symbols for each DLL that loads into the debuggee process.  As part of this process, it asks each path specified in the Debugging Symbols dialog for the corresponding PDB.  Some projects load a LOT of DLLs which won't have symbols available, so this process can significantly impact debugger startup time as this probing occurs.  It is mainly for this reason we've recommended manual symbol loading in the steps above; we don't want using this feature to degrade the debugging experience across-the-board.

There is, however, a way to allow automatic symbol loading (which avoids the "Load Symbols" step) in a way that minimizes performance impact.   This is for more advanced users because it requires regular trips back to this Debugging Symbols Dialog.  Note you can quickly get to this dialog by choosing the "Symbol Settings..." item on the right click menus pictured in steps above form the Call Stack or Modules windows.

The key is to get all of the symbols for a given project type downloaded and cached locally, then turn off the automatic symbol downloads.  This will prevent the pings at debugger startup as well.

To do this, configure your setup as above with the following difference: Uncheck the "Search from the above locations..." item on the dialog.

Now, launch your project in the debugger.  This will cause all of the symbols available for the DLLs in your process to be downloaded at on-demand as the DLLs are loaded into the process.  Depending on your connection speed, this could take a while (it's generally about 50MB of symbols), so it's a good idea to hit F5 then go do something else for a while.  Again, these symbols are cached so this is a one-time cost.  Visual Studio will likely be unresponsive during this download process.

image

Once that process has completed, stop the debugger, and UNCHECK the the Reference Source Server symbol location, and hit OK:

image

Now when you launch the debugger, symbols will load automatically and you'll be be able to step in and through call stacks normally.  Note if you switch to a different project type (that has different assemblies), or have assemblies that are loaded later by your project, you can just repeat these steps to get any assemblies you don't have cached locally). 

FAQ/TROUBLESHOOTING

1) Which assemblies are currently available for symbol/source loading:
  • Mscorlib.DLL
  • System.DLL