November 2009 - Posts

In preparing for an upcoming talk I'll be giving on the Managed Extensibility Framework (MEF), I wanted to demonstrate how fast and easy it is to use in a sample, reference application. This application creates a dynamic plugin. I first link a plugin and show it active, then I create a second plugin and show how it is dynamically added to the program during runtime. It all takes under 10 minutes and would be faster if I didn't want to pace the demo to show the steps involved.

Here is a direct link to the video

Here it is embedded:

Jeremy Likness

Your boss suddenly decides that Silverlight is the "next big thing" and asks you to begin converting your line of business application to use the new features. Being a solid architect, of course, you have already built a nice application that is structured in layers. You have a data access layer that abstracts persistence behind interfaces, a domain layer that describes business models, a business logic layer for heavy lifting, a services layer for interconnectivity, and a presentation layer that is ASP.NET or something similar.

RIA services looks promising, but there is one problem. You see that you can create a LINQ to SQL based service, or an Entity Framework service, but you're not comfortable going to production with either of those because then it would introduce an entirely new way of accessing data. You want to keep your data access layer (maybe it's built using Enterprise Library or NHibernate or something similar).

What do you do?

Fortunately, RIA services is not limited to LINQ or EF. You can build a domain service that handles your POCO (plain-ole' CLR objects) domain models. If you are willing to extend your classes a bit and haven't already begun decorating your POCO objects with data annotations, you can handle that, too! Here's how.

Let's assume I've got a decent entity model based on entities that have an integer for their identifier. I do like INotifyPropertyChanged but had reservations about decorating my model with data annotations or validation attributes. Just didn't seem right. So what I have is a base entity that looks like this:


public abstract class BaseEntity : INotifyPropertyChanged
{
    private bool _isDirty = false;

    private bool _isNew = true;

    private int _id = -1;
  
    public virtual int ID
    {
        get { return _id; }
        set
        {
            if (!value.Equals(_id))
            {
                _id = value;
                OnPropertyChanged("ID", true);

                if (_isNew && value > 0)
                {
                    _isNew = false;
                    OnPropertyChanged("IsNew", true);
                }
            }
        }
    }

    public virtual bool IsNew
    {
        get { return _isNew; }
    }

    public virtual bool IsDirty
    {
        get { return _isDirty; }
    }

    public void Reset()
    {
        if (_isDirty)
        {
            _isDirty = false;
            OnPropertyChanged("IsDirty", false);
        }            
    }

    protected void OnPropertyChanged(string property)
    {
        OnPropertyChanged(property, true); 
    }


    private void OnPropertyChanged(string property, bool setDirtyFlag)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }

        if (setDirtyFlag)
        {
            if (!_isDirty)
            {
                _isDirty = true;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs("IsDirty"));
                }
            }
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    protected abstract bool _Equals(object obj);

    public override bool Equals(object obj)
    {
        return _Equals(obj);
    }

    public override int GetHashCode()
    {
        return _id.GetHashCode();
    }
}

I have a user entity defined as well. This contains properties for a username, a first and last name, and an email address. Only the username is required. The entity looks like this:


public class UserEntity : BaseEntity 
{
    private string _userName, _firstName, _lastName, _email;

    public virtual string UserName
    {
        get { return _userName; }
        set
        {
            if (value == null || !value.Equals(_userName))
            {
                _userName = value;
                OnPropertyChanged("UserName"); 
            }
        }
    }

    public virtual string FirstName
    {
        get { return _firstName; }
        set
        {
            if (value == null || !value.Equals(_firstName))
            {
                _firstName = value;
                OnPropertyChanged("FirstName"); 
            }
        }
    }

    public virtual string LastName
    {
        get { return _lastName; }
        set
        {
            if (value == null || !value.Equals(_lastName))
            {
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }
    }

    public virtual string Email
    {
        get { return _email; }
        set
        {
            if (value == null || !value.Equals(_email))
            {
                _email = value;
                OnPropertyChanged("Email");
            }
        }
    }

    protected override bool _Equals(object obj)
    {
        return obj is UserEntity && ((UserEntity)obj).Equals(ID);
    }
}

Note: it's quite possible that you didn't declare your properties as virtual. While I won't make you rewrite your domain model layer, it would be helpful if you're willing to make that one change ... I'll explain why later. Virtual gives us some flexibility to extend later on.

Now for my data access class, I have an interface that defines my basic data handling needs. How I implement these could be anything from NHibernate to Enterprise Library to my own SQL provider that directly accesses the database and parses readers and a data sets into my POCO objects. The point is, I can do this all through a clean interface, like this:


public interface IDataHandler<TEntity> where TEntity : BaseEntity 
{
    TEntity Load(int id);

    void Delete(int id);

    int Save(TEntity entity);

    IEnumerable<TEntity> List();
}

Great. So now I can implement and extend as needed. For example, I might create a concrete UserDataHandler that is based on the IDataHandler<UserEntity> interface. Sound good?

Now we want to build our domain service in RIA but maintain backwards compatibility with our existing system. After all, a large line of business application wasn't written overnight. It could take months to convert all of those screens to Silverlight and we might not even touch them all. It's important to maintain a consistent data access layer so I can fix things in one place and still reuse the existing connectors in my legacy code.

The first thing I'll do is fire up a new Silverlight Business Project. This puts in some plumbing that I might use, or I might throw out, but more importantly it integrates the structure for my Silverlight project to be able to seamlessly communicate with my RIA services.

It makes sense for those of you new to RIA to take a step back and mention two things.

First, RIA is "magic" and exposes a neat class that I can work with, without having to deal with the nuances of WCF services. In the end, however, RIA generates WCF endpoints. These are 100% bona-fide WCF service points that anything can plug into ... I'm just going to do it with my Silverlight application for now.

Second, RIA is "magic" and performs some code generation. I don't see these in a special designer.cs file, but it's there. Code generation isn't a popular term because of some bad projects in the past, so I think the cool word for it now is "projection." We say RIA projects code to my Silverlight application. This means I'll have access to the host web namespace from my Silverlight application.

Let's dig in. What I want to do is create a Domain Service that allows me to reuse my existing data access layer and POCO classes. What I'll do is add a new item to my web application (the one that's hosting the Silverlight, not the Silverlight application itself) and I'll call it LOBDomainService (line of business domain service). The shell that is provided for me looks like this:


[EnableClientAccess()]
public class LOBDomainService : DomainService
{
}

This is the start of a workable service. Because I called my class LOBDomainService, RIA will project for me a LOBDomainContext in the Silverlight client. We'll get to that in a moment.

First, we need to get our data access layer into the domain service. There are several ways to do this:

Factory


IDataHandler<UserEntity> dataHandler = MyDataFactory.GetDataAccess<UserEntity>();

Constructor Injection using something like StructureMap or Unity


private IDataHandler<UserEntity> _dataHandler;

public LOBDomainService(IDataHandler<UserEntity> dataHandler)
{
    _dataHandler = dataHandler;
}


Managed Extensibility Framework (MEF)


[Import]
IDataHandler<UserEntity> DataHandler { get; set; }

... or maybe you just want to new it up. It's up to you.

At this point, however, we have a problem. While I'm able to import my data handler and my objects, the RIA framework doesn't know much about my entities. This is because it depends on data annotations to get hints. With data annotations, I can specify which field is the key field for the entity. I can provide user friendly column names, hints, and descriptions, flag which fields are required and even provide validation.

Some shops may already use these annotations, as they are encapsulated in System.ComponentModel.DataAnnotations and are database and data-strategy independent. However, if you either haven't used these, or simply don't want to "dirty" your base domain models, there is a way to "cheat" a bit and get this to work.

Remember how I mentioned using virtual on your properties would come into play? Let's create a new class called UserEntityExtension. I'll go ahead and base it on my POCO class, but add some annotations.


public class UserEntityExtension : UserEntity
{
    public UserEntityExtension()
    {
    }

    public UserEntityExtension(UserEntity baseEntity)
    {
        if (baseEntity.ID > 0)
        {
            ID = baseEntity.ID;
        }
        UserName = baseEntity.UserName; 
        FirstName = baseEntity.FirstName;
        LastName = baseEntity.LastName;
        Email = baseEntity.Email;
        Reset();
    }

    [Key]
    [ReadOnly(true)]
    [Display(AutoGenerateField=false)]
    public override int ID
    {
        get
        {
            return base.ID;
        }
        set
        {
            base.ID = value;
        }
    }

    [Display(Name="Username")]
    [Required]
    [RegularExpression("^[A-Za-z0-9]+$", ErrorMessage="Please enter a valid user name using only alphanumeric characters without spaces.")]
    public override string UserName
    {
        get
        {
            return base.UserName;
        }
        set
        {
            base.UserName = value;
        }
    }

    [Display(Name="First Name")]
    public override string FirstName
    {
        get
        {
            return base.FirstName;
        }
        set
        {
            base.FirstName = value;
        }
    }

    [Display(Name="Last Name")]
    public override string LastName
    {
        get
        {
            return base.LastName;
        }
        set
        {
            base.LastName = value;
        }
    }

    [Display(Name="Email Address")]
    [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage="Please enter a valid email address.")]
    public override string Email
    {
        get
        {
            return base.Email;
        }
        set
        {
            base.Email = value;
        }
    }

    [Display(AutoGenerateField=false)]
    public override bool IsNew
    {
        get
        {
            return base.IsNew;
        }
    }

    [Display(AutoGenerateField=false)]
    public override bool IsDirty
    {
        get
        {
            return base.IsDirty;
        }
    }
}

As you can see, I'm simply passing through to the base properties, but annotating these with various tags. The constructor takes the base class and populates itself, making it easy to convert from the base type to the extended type. Now I'm ready to complete my domain service model:


[EnableClientAccess()]
public class LOBDomainService : DomainService
{
    public LOBDomainService()
    {
        // MEF set up goes here
    }

    [Import(AllowRecomposition=true)]
    IDataHandler<UserEntity> UserContext { get; set; }

    public IQueryable<UserEntityExtension> GetUsers()
    {
        return UserContext.List().ToList().ConvertAll(u => new UserEntityExtension(u)).AsQueryable(); 
    }

    public void InsertUser(UserEntityExtension entity)
    {
        UserContext.Save(entity);
    }

    public void UpdateUser(UserEntityExtension entity)
    {
        UserContext.Save(entity);
    }

    public void DeleteUser(UserEntityExtension entity)
    {
        UserContext.Delete(entity.ID);
    }
}

The Liskov Substitution Principle (LSP) states that "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program." In this case, we can safely pass the extended class to our data handler that only knows about the base class without worry.

On the Silverlight side, I can now wire up a fast grid and form to see the results of my hard work. I'll sneak into the Views/Home.xaml template and add the following references:


xmlns:ria="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Ria"
  xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Controls.Ria"
  xmlns:local="clr-namespace:LOBApp.Web.Services"
  xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
  xmlns:dataGrid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

Then, I'll wire in the data source, a grid, and a data form, like this:

 <ria:DomainDataSource AutoLoad="True" Name="userSource" QueryName="GetUsers">
                    <ria:DomainDataSource.DomainContext>
                        <local:LOBDomainContext/>
                    </ria:DomainDataSource.DomainContext>
                </ria:DomainDataSource>
          
                <dataGrid:DataGrid RowDetailsVisibilityMode="VisibleWhenSelected" SelectionMode="Single" AutoGenerateColumns="True" 
                                   ItemsSource="{Binding Path=Data, ElementName=userSource}">
                    <dataGrid:DataGrid.RowDetailsTemplate>
                        <DataTemplate>
                            <dataForm:DataForm x:Name="dataForm" AutoGenerateFields="True" CurrentItem="{Binding Path=DataContext, ElementName=dataForm}"/>
                        </DataTemplate>
                    </dataGrid:DataGrid.RowDetailsTemplate>
                </dataGrid:DataGrid>
 

With just that little bit of code, I can compile and generate and get something like this (notice it takes on the field names as well as validations, etc):

RIA Services using POCO

Obviously there's much more to do (we haven't touched security or made a submit button or added delete functionality, for example) but this should give you an idea of not only how powerful RIA services truly are, but also how there is plenty in place to enable you to leverage your existing architecture with the new model.

Jeremy Likness

One of the advantages of using RIA services is that you can build your domain entity tier independently from the rest of the application tiers and then wire it in as needed, whether as LINQ or simple POCO classes.

If you decide to annotate your entities with resources, it can get a little dicey. Most examples online focus on resource files within Silverlight or entities defined within Silverlight. However, it is quite common to have existing POCO objects that point to a resource file. For example, I might declare a user entity like this:


public class User
    {
        [Key]
        [ReadOnly(true)]
        public int ID { get; set; }

        [Display(Name="UserName", Description="UserNameDescription", ResourceType=typeof(EntityResource))]
        [Required]
        [RegularExpression("^([A-Za-z0-9])+$", ErrorMessageResourceName="BadUserName", ErrorMessageResourceType=typeof(EntityResource))]
        public string UserName { get; set; }
    }

In this example, my resources are defined in the same project as the user entity, in a EntityResource.resx file.

When I build my DomainService to use this object, the first thing I get is an error related to accessing the resource file. I'm told it needs to be flagged as public. This is simple enough: I go into the designer and switch the access the modifier.

RIA Services with Resource File

Now we can compile again, but again, we get an error. This time it's in one of those auto-generated files that ends with .g and it says that my LOB.Entity.EntityResource type doesn't exist! What happened? I marked my domain service with EnableClientAccess, but the resource type doesn't make it to the Silverlight client.

It turns out the magic of RIA (for Silverlight 3) only goes so far ... we need to go ahead and manually bring the resource file over. Fortunately, we can do it in a way that prevents us from having to duplicate code.

In the silverlight project, figure out where you want the resource files to reside. I chose a folder called Links to keep all of my cross-linked resources in one place. On the folder, I right-click and choose "Add Existing Item." I then navigate to the resource file in my server side project, and add it ... as a link.

RIA Services with Resource File

Be sure to add the Designer.cs file as well, and you should be good.

Jeremy Likness

As I continue to work on a reference project (basically building my portfolio site out in Silverlight) I keep going back to what it takes to put a Silverlight application "out there." When is it really "code complete?" There are tons of blog posts and articles about unit testing, frameworks, line of business, etc, but often I believe people miss some of the smaller points and nuances that go into making the application "application-ready." Here's a few tips and pointers that may help out.

Is SEO Important?

If it's an internal application, or even one hosted on the cloud that performs a business function and doesn't generate revenue via search engine discovery and click throughs, then search engine optimization is, of course, not much of a concern. What about if I'm presenting a portfolio or some other type of application that I want the search engines to uncover? Then we have to worry about it.

The introduction of deep-linking navigation certainly helps, but as someone pointed out in an earlier post of mine, search engines won't necessarily take the time to load XAP files, run them in a virtual environment, and see what they spit out. So we have to host the application creatively. Some shops will build two different versions. I'm working on an engine I think is a compromise, and am currently testing how the search engines like it. If it works, I'll blog about it ... if not? Back to the lab.

Essentially, you can host the website to parse out the current URL and present a set of default title, description, and other meta tags based on the URL. In other words, if I navigate to page.aspx#/Home I'll send out different tags and data than page.aspx#/Bio. The question is whether I need to generate this server side, or if I can parse it via javascript, update the tags, and the search engines will recognize the update. If I put a "site map" or legend on my pages that link to these "relative" nodes, the theory is that the engines will crawl those nodes and index at least the title and description for the content.

Most applications in Silverlight, however, function "inside the box." They don't rely on SEO. The only reason you use the deep linking and HTML DOM integration is to give the user consistent browser feedback and the ability to bookmark and return to pages.

Splash Page

It seems like a trivial step, but it is very important to promote your brand and create a seamless experience for the user. Mike Taulty has a nice video and rant in this post about the default progress animation. Take the time (about 2 minutes) to build a nice, branded experience for the user.

Here's a tip: I've seen lots of exotic ways people use to "test" their splash screen. Here's something I think will help, and will also give you good feedback for your application as a whole.

  1. Download Fiddler, a web-debugging proxy.
  2. Publish your website locally
  3. Run Fiddler. Go into Rules -> Performance and check "Simulate modem speeds" and "Disable caching"
  4. Run your application. Instead of localhost use your machine name. My laptop is called jeremyliknesspc so I navigate to http://jeremyliknesspc/testapp to test

That's it. Fiddler will slow down your connection enough that you can see the screen. What's better, if you are using dynamic module loading, you can also see how the application behaves when those modules take a long time to load. It might prompt you to add some nice progress indicators or other user feedback to manage the case when their connection is slow. We always test our applications locally (either on our machine or the local intranet) so it's very important to throttle the speed down and check out how it behaves in the worse case scenarios.

As an added bonus, you can start to see the internals of how the engine works: when it requests the XAP files, the additional modules, resources, etc. This will help you tune your application.

The Dead Plugin

It's going to happen. Believe it or not, as enthusiastic as we are about the way Silverlight has been growing, there will be end users who do not have the plugin. This is another branding choice in line with the splash screen. You can either give them a nice, boring, default logo provided by Microsoft, or you can spruce it up a bit. Connect with the consumer, explain why you are using Silverlight. Delight them with the benefits they'll receive after installing it and assure them it won't take long.

You can manipulate what's inside the object tag to your heart's desire. For the portfolio that I'm building, I welcomed the user, thanked them for visiting, then mentioned that as a Silverlight developer, I chose to build my portfolio in Silverlight. I indicated it is a safe plugin and that they simply need to click on the link to install it. I included the standard Microsoft icon and then put a little set of breadcrumbs linking to my relative pages beneath it.

Testing this is simple and easy, too. In Internet Explorer, you simply go into Tools -> Manage Add-ons. Navigate to Silverlight and set it to disabled. Refresh the page and see what the users will see when they don't have the plugin installed. (Re-enable it later, of course, or your Silverlight development career may end abruptly).

That's it: nothing earth-shattering or ground-breaking, but a little common sense to sprinkle along the way as we all forge ahead with our applications and anticipate how Silverlight 4 will change the landscape.

Jeremy Likness

Silverlight 4 provides some very powerful data form capabilities out of the box. You will no longer have to throw an exception just to send a validation error or even worry about hard-coding labels. With support for data annotations, IDataErrorInfo and more, you now have plenty "out of the box" to work with.

Let's explore the surface of some of these powerful new features!

IDataErrorInfo

With support for IDataErrorInfo as well as INotifyDataErrorInfo, you no longer have to raise exceptions just to validate your classes. Fire up VS 2010 and create a new Silverlight 4 application. First, we'll create a "helper" class to derive our entities from in order to perform validation and notify property changes. The class looks like this:


public abstract class BaseEntity : INotifyPropertyChanged, IDataErrorInfo
{
    private Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();

    protected void RemoveErrors(string prop)
    {
        if (_errors.ContainsKey(prop))
        {
            _errors.Remove(prop);
        }
    }

    protected void AddError(string prop, string error)
    {
        if (_errors.ContainsKey(prop))
        {
            _errors[prop].Add(error);
        }
        else
        {
            _errors.Add(prop, new List<string> { error });
        }
    }

    protected void OnPropertyChanged(string prop)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(prop));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual string Error
    {
        get { return string.Empty; }
    }

    public virtual string this[string columnName]
    {
        get 
        {
            System.Text.StringBuilder retVal = new System.Text.StringBuilder();

            if (_errors.ContainsKey(columnName))
            {
                bool first = true;
                foreach (string error in _errors[columnName])
                {
                    retVal.Append(error);
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        retVal.Append(Environment.NewLine);
                    }
                }
            }

            return retVal.ToString();
        }
    }
}

There are a few things going on here. First, we implement INotifyPropertyChanged in to facilitate binding. The protected OnPropertyChanged method allows derived classes to hook into this event.

Next, we implement IDataErrorInfo. This forces us to provide a single error property as well as an extension method that references errors for a given property. John Papa has an excellent article about building a handler for this at Enabling Validation in Silverlight 4 with IDataErrorInfo. In my case, I keep a dictionary referenced by the property name that holds a list in case there are multiple errors I want to show. When the errors are requested, I fold them into a single string using Environment.NewLine (OK, so the beta just came out the other day ... can't say I've fully tested that part).

Data Annotations

Now you can build a PersonInfo class based on this base class. To keep things simple for a contrived example, I chose just a first name, last name, and age. Here we'll need to add a reference to System.ComponentModel.DataAnnotations. You must install the latest Silverlight Toolkit for this. If you need to browse to it manually, it's located under the toolkit installation directory (usually c:\Program Files\Microsoft SDKs\Silverlight) under v4.0\Libraries\Client. Now we can derive the class and annotate it, like this:


public class PersonInfo : BaseEntity 
{
    private string _firstName, _lastName;

    private int _age;

    [Display(Name="First Name")]
    [Required]
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (string.IsNullOrEmpty(value.Trim()))
            {
                AddError("FirstName", "First name is required.");
            }
            else
            {
                RemoveErrors("FirstName");
                if (!value.Equals(_firstName))
                {
                    _firstName = value;
                    OnPropertyChanged("FirstName");
                }
            }
        }
    }

    [Display(Name="Last Name")]
    [Required]
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (string.IsNullOrEmpty(value.Trim()))
            {
                AddError("LastName", "Last name is required.");
            }
            else
            {
                RemoveErrors("LastName");
                if (!value.Equals(_lastName))
                {
                    _lastName = value;
                    OnPropertyChanged("LastName");
                }
            }
        }
    }

    [Display(Name="Age (Years)")]
    [Required]
    public int Age
    {
        get { return _age; }
        set
        {
            if (value  130)
            {
                AddError("Age", "Age must be a valid integer between 18 and 130.");
            }
            else
            {
                RemoveErrors("Age");
                if (!value.Equals(_age))
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
        }
    }
}

You'll probably pull out validations into a handler / rule set but basically what I'm doing is validating the value, setting an error or clearing all errors if it passes, then calling the property changed event if the value truly changes. Note the use of annotations to specify required properties as well as "friendly names" for the properties.

Now that our class is prepped, we can get to work on the XAML.

Implicit Styles

With support for implicit styles, we can set a style based on a target type and style it that way - allowing for themes to be set externally. We'll take advantage of that to set the width for our TextBox controls. I also add a reference to the PersonInfo class to use in data binding, so I won't need to touch the code-behind for MainPage.xaml:


<UserControl.Resources>
   <local:PersonInfo x:Key="Person"/>
   <Style TargetType="TextBox">
      <Setter Property="Width" Value="200"/>
   </Style>
</UserControl.Resources>

Data Input Helpers

Next, add a reference to System.Windows.Controls.Data.Input (found in the toolkit as well, same folder as the data annotations). We'll reference it at the top of our XAML (along with the local reference we need for the PersonInfo class:


xmlns:local="clr-namespace:DataForm"
    xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"

Great, now let's get to work! I'm going to show you the full snippet of XAML and then explain the pieces:


    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource Person}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>           
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <dataInput:Label Target="{Binding ElementName=tbFirstName}"
                         Grid.Row="0" Grid.Column="0"/>
        <StackPanel Orientation="Horizontal" 
                    Grid.Row="0" Grid.Column="1">
            <TextBox x:Name="tbFirstName" 
                 Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, FallbackValue=''}"/>
            <dataInput:DescriptionViewer Description="Please enter your first name."
                                         Target="{Binding ElementName=tbFirstName}"/>
        </StackPanel>
        <dataInput:Label Target="{Binding ElementName=tbLastName}"
                         Grid.Row="1" Grid.Column="0"/>
        <StackPanel Orientation="Horizontal" 
                    Grid.Row="1" Grid.Column="1">
            <TextBox x:Name="tbLastName" 
                 Text="{Binding Path=LastName, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, FallbackValue=''}" />
            <dataInput:DescriptionViewer Description="Please enter your last name."
                                         Target="{Binding ElementName=tbLastName}"/>
        </StackPanel>
        <dataInput:Label Target="{Binding ElementName=tbAge}"
                         Grid.Row="2" Grid.Column="0"/>
        <StackPanel Orientation="Horizontal" 
                    Grid.Row="2" Grid.Column="1">
            <TextBox x:Name="tbAge" 
                     Text="{Binding Path=Age, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, FallbackValue='0'}"/>
            <dataInput:DescriptionViewer Description="Please enter a valid age between 18 and 130."
                                         Target="{Binding ElementName=tbAge}"/>
        </StackPanel>
        <dataInput:ValidationSummary Grid.Row="3" Grid.Column="0"
                                     Grid.ColumnSpan="2"/>        
    </Grid>

Some of these helper classes are made available via the toolkit for Silverlight 3 as well.

Labels

The label class lets us bind to an element like a textbox. It will pull the name of the databound property from the annotations and display it. If a validation error is thrown, it will turn red to further reinforce the error. If the field is tagged as required, the label will automatically bold itself to indicate a required field.

Learn more about the Label class

New Bindings

If you take a look at the textbox contorls, you'll see we've added new binding parameters. Specifically, ValidatesOnDataErrors (as opposed to exceptions) and FallbackValue (a value to use when databinding fails).

Learn more about bindings

Description Viewer

The description viewer control provides an easy way to show tips and hints and is similar to the ToolTip service. It will show an informational icon that, when the cursor hovers over, will provide a hint or description.

Learn more about the description viewer

Validation Summary

Finally, we add a validation summary control. The default behavior is to list all errors. When the user clicks on an error, it gives focus to the UI element that caused the error.

Learn more about the validation summary class

Putting it all Together

When you tie this all together and run it (without any additional code behind), this is an example of what you'll see:

Silverlight 4 Beta Data Forms

  • Note the labels automatically pulled from the DisplayAttribute on the entity class
  • The labels are bold due to the RequiredAttribute annotation
  • The labels on properties with errors are colored red
  • I clicked on the information glyph next to the first name text box and was the hint to enter my first name
  • I clicked on the red triangle in the upper right corner of the text box for age and was shown the error that my age is not in the valid range
  • The ValidationSummary control has summarized my errors (if I click on one, I'll be taken to the control with the issue)

As you can see, that's quite a bit of functionality right out of the box, and it allows a nice, clean separation of things like attributes and descriptions from the user interface that presents them.

Jeremy Likness

Earlier I explored some options to allow inline hyperlinks in Silverlight 3 using some extensions and the WrapPanel. In Silverlight 4, which was released as beta earlier this week, the problem is solved in the framework. Silverlight 4 gives us the RichTextArea control, which allows us to organize runs, spans, paragraphs, and even embed other UI elements to create a very richly illustrated document.

To illustrate this, I fired up a new Silverlight Application in Visual Studio 2010 and chose a Silverlight 4 application. Grabbing some more "lorem ipsum" text, I threw it into a RichTextArea control and then began embellishing with hyper links, formatting, and tossed in a red rectangle for good measure. The markup looks like this:


<RichTextArea TextWrapping="Wrap">
            <RichTextArea.Blocks>
                <Paragraph>Lorem ipsum dolor sit amet consectetur adipiscing elit.
                    <Bold>Suspendisse eu erat quis nibh laoreet hendrerit.</Bold>
                    <Italic>Tortor quam, auctor vel elementum et, rhoncus id augue.</Italic>
                    <Span Foreground="BlueViolet">Vestibulum nulla augue, dictum ut placerat et,</Span>
                    <Span>hendrerit a lorem. Vestibulum ante ipsum primis in</Span>
                    <Hyperlink NavigateUri="http://www.wintellect.com/"> faucibus orci luctus </Hyperlink>
                    <Run>et ultrices posuere cubilia Curae; Donec sollicitudin feugiat augue, eu 
                        vestibulum eros dapibus vel.
                    </Run>
                    <InlineUIContainer>
                        <Rectangle Width="20" Height="20" Stroke="Black" Fill="Red"/>
                    </InlineUIContainer>
                    Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.                  
                </Paragraph>
            </RichTextArea.Blocks>
            </RichTextArea>

As you can see, I am able to mix raw text, spans and runs that format colors or fonts, hyperlinks, and even use the InlineUIContainer to toss a rectangle into the mix. After building and publishing, this is what appears in the browser:

Rich text area in Silverlight 4 Beta

As you can see, a very serviceable rendering!

Next, we'll have a quick bit of fun. I add some row definitions and a header:


 <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <TextBlock FontWeight="Bold" Grid.Row="0">Header

I wire the text area into row 1, then add this button to the last row:


  <Button Click="Button_Click" Content="Print" Grid.Row="2"/>

Do you get where I'm going? We don't want to print the header or the button, just the lorem ipsum section, so this is what we wire into the code behind:


public partial class MainPage : UserControl
{
    PrintDocument _pd; 

    public MainPage()
    {
        InitializeComponent();
        _pd = new PrintDocument();
        _pd.PrintPage += new EventHandler(pd_PrintPage);
    }

    void pd_PrintPage(object sender, PrintPageEventArgs e)
    {
        e.PageVisual = MainText;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        _pd.DocumentName = "Lorem Ipsum";
        _pd.Print();
    }
}

Note that we have three steps:

  1. Create a printing surface
  2. Trigger the print by calling the print method (and optionally setting some parameters)
  3. Wiring into the print event and setting the visual to print only what we want (keep in mind we could have created an entirely new set of UI elements here).

The new page looks like this:

Silverlight 4 Beta Print Button

When I click "print" I'm given the familiar print dialog. I selected the XPS writer and saved it as an XPS document. Here is the final result:

Silverlight 4 Beta Page Printed from Browser

I'll continue to follow how Silverlight 4 makes our life easier by integrating into the framework what we used to have to build ourselves!

Jeremy Likness

I started a project to update my personal website using Silverlight. The goal is to use Prism/Composite Application Guidance to build out a nice site that demonstrates some Silverlight capabilities and make the source code available as a reference. One of the first pieces I chose to tackle was ensuring I could facilitate deep linking using Silverlight navigation and still take advantage of dynamic module loading using the Prism framework.

The initial research I did was not promising. Most sites claimed that Prism broke the Silverlight navigation, while others had partial solutions that didn't really cut it for me. Mapping a separate view in the main module to have a named region for every dynamically loaded module seems to be overkill. So, I set out to see for myself if it could be done. The answer, of course, is yes!

While the project is a simple pair of pages, I've built in a few more advanced pieces of functionality to extend its richness as a reference project. In addition to dynamic loading the module for the "biography" page, I've trimmed the size of the XAP files, sprinkled in a little search engine optimization, and used the visual state manager to handle some animations to boot.

You can download the full source code by clicking here. For a working demo, click here. You can use a sniffer or proxy like Fiddler 2 to confirm for yourself that the Biography module doesn't load until you click that tab, BUT you can also navigate directly:

I do apologize in advance for the vanity built into the project ... it is a project with the goal of replacing my biography website so it made since to name it after, well, me.

The first step in creating a deep linking navigation website is to go ahead and create a Silverlight Navigation Application. I called mine JeremyLikness.Main and it gave me JeremyLikness.Web to host it. Go ahead and trash everything in the views folder but the error window (I like that functionality, some might find it annoying), leave the App pieces alone but rename the main page to Shell.xaml.

Here's when things start to get interesting. First, I've seen a lot of implementations that want the pure "my module gets added magically" functionality, so they do things like inject the link to the module when the module itself gets loaded, etc. This is all great but then they also stuff a view in the main application that maps one-to-one with the module, give a new named region per module, and leave me scratching my head wondering, "What did we gain?" To me, the main portion of my app is a single region that can have multiple modules inject their views into it, so that's how I approached this project.

I'm going to be a bit more pragmatic and go ahead and map my links in the main shell because I'm assuming right now the shell is like the overall "controller" and is aware of the other modules. It should, however, be very easy and minimal overhead for me to add a new module later on. I'm not going to worry about the modules injecting the links because then I have to load the module before I can show the link, and that defeats the purpose of dynamically loading the modules. Ideally, your browser doesn't fetch that extra 100K of XAP download if you don't care about reading my biography!

I end up keeping the generated code for the links (I'll go back and rearrange and style it later ... getting it functioning for me comes before making it pretty). I'm starting with two links, so that section looks like this:


 <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
                <StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">

                    <HyperlinkButton x:Name="homeLink" Style="{StaticResource LinkStyle}" 
                                     NavigateUri="/Home" TargetName="ContentFrame" Content="Home"/>
          
                    <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
     
                    <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}" 
                                     NavigateUri="/Bio" TargetName="ContentFrame" Content="Bio"/>
                </StackPanel>
            </Border>

Not bad. Now we're going to start butchering the generated template, so bear with me.

Dynamic Modules

Setting up modules to be dynamic is fairly straightforward. While there are many ways to approach this, the method I used has two key features:

  1. I'm using a XAML configuration for the module, not programmatic, and
  2. to add the module in a way that Prism can dynamically load it, I add it as a Silverlight Application, not a Class Library

That's it! We're going to work a bit backwards and live without the project compiling for a bit until we get all of the pieces put into place. I know I'm going to have a Home and a Bio module. For the sake of simplicity and this example, I'm doing one view per module, but you could obviously do more. You'll see why this makes it easy for me in a minute. First, let's set up the XAML that will describe the modules.

Right click on the main project (the one with your shell) and add a new Resources File. Name it ModuleCatalog.xaml. Blow away everything in there and instead put in the Prism notation for a module, like this:


<m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 xmlns:m="clr-namespace:Microsoft.Practices.Composite.Modularity;assembly=Microsoft.Practices.Composite">
    <m:ModuleInfoGroup Ref="JeremyLikness.ModuleHome.xap" InitializationMode="WhenAvailable">
        <m:ModuleInfo ModuleName="JeremyLikness.ModuleHome.InitModule"
                      ModuleType="JeremyLikness.ModuleHome.InitModule, JeremyLikness.ModuleHome, Version=1.0.0.0"/>
    </m:ModuleInfoGroup>
    <m:ModuleInfoGroup Ref="JeremyLikness.ModuleBio.xap" InitializationMode="OnDemand">
        <m:ModuleInfo ModuleName="JeremyLikness.ModuleBio.InitModule"
                      ModuleType="JeremyLikness.ModuleBio.InitModule, JeremyLikness.ModuleBio, Version=1.0.0.0"/>
    </m:ModuleInfoGroup>
</m:ModuleCatalog>
                 

I've purposefully set the home page to load when available and the bio to load on demand to show the difference between the methods ... I could just as easily load both modules on demand. This simply points to the class that defines the module, and the assembly to find it in. Prism will assume it's available for download in the same directly as the hosted XAP and kindly pull down the XAP when it's needed for us.

We're now referring to some modules we don't have yet. At this point, you could go ahead and create the shells for the applications. In order for the project to be set up correctly for dynamic loading, instead of adding a Silverlight Class Library, you're going to add a new Silverlight Application. Pick the same web page to host it but don't bother with the generation of a test page as it will load into the same test page we used for the main. I called my projects JeremyLikness.ModuleBio and JeremyLikness.ModuleHome.

Once the projects are created, blow away the all of the generated XAML files. You won't need the App object because this will be hosted in our main application. I simply added the references needed for Prism, then created a Views folder and added a Home.xaml in my home project and a Bio.xaml in my bio project. These are UserControl types, not pages. In the root, I created InitModule classes for both projects (note that I referenced this in the ModuleCatalog.xaml). The code looks almost identical - here is the bio:


namespace JeremyLikness.ModuleBio
{
    public class InitModule : IModule
    {
        private IRegionManager _regionManager;

        public InitModule(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }

        #region IModule Members

        public void Initialize()
        {
            _regionManager.RegisterViewWithRegion("ModuleRegion", typeof(Bio));
        }

        #endregion
    }
}

Simple: reference the region manager in the constructor. The Prism will use Unity to resolve the reference and inject it. On the Initialize method, we register our view with the region. The home project will register to the same region, but with typeof(Home) home instead.

Now we've got the catalog and the modules, what's next?

Bootstrapping

We need to tell the Prism framework how to "get started." This means a bootstrapper. Back to JeremyLikness.Main, I add a class called Bootstrapper and base it on UnityBootstrapper. I need to create the shell and set it as the root visual:


protected override DependencyObject CreateShell()
{
    Shell shell = Container.Resolve<Shell>();
    Application.Current.RootVisual = shell;
    return shell;
}

I also need to supply a module catalog. For this, I'll point to the XAML file we created earlier:


protected override Microsoft.Practices.Composite.Modularity.IModuleCatalog GetModuleCatalog()
{
    return Microsoft.Practices.Composite.Modularity.ModuleCatalog.CreateFromXaml(
        new Uri("JeremyLikness.Main;component/ModuleCatalog.xaml", UriKind.Relative));
}

You can see I'm telling it to look to the XAML to create the catalog, then specifying the path to it. The last thing I need to do is go into the App.cs code behind and change the application start up to just run the boot strapper:


private void Application_Startup(object sender, StartupEventArgs e)
{
   new Bootstrapper().Run();
}

Adapting to the Region

Prism works with defined regions that can host views. There are a number of different ways those regions can be implemented. I would ask that you refer to the Prism documentation for this, but basically something like a ContentControl can have a single view active at any given time, while something like a ItemsContentControl can hold multiple views. One source of confusion is what "active" really means. Active views doesn't necessarily mean "visible" or "hidden." I had two challenges for this application: the first was how to host the view, and the second was how to manage the visibility of the views. Ideally, something would hold all of the views as they are selected, then simply make them visible or invisible as they are selected/deselected.

We'll tackle visibility in a minute. ContentControl wasn't an option because it only holds one view at a time. The problem with ItemsControl was related to layout. As each view is injected, it takes up space in the container (this is the same whether it's a items control or a stack panel, etc). Even when I'd collapse the visibility of a control, the original space would still cause the other controls (views) to be shifted, which was not the effect I wanted. I needed something like a Grid where I could stack the views one on top of the other.

Fortunately, making your own type of region is easy. After reading John Papa's excellent post, I made a PrismExtensions folder and built my GridRegionAdapter to allow Prism to use a grid as a container. You can read his article to understand the how/why and see how the adapter is constructer. I had to revisit the boot strapper and tell Prism how to map the adapter to the grid:


protected override RegionAdapterMappings ConfigureRegionAdapterMappings() 
{ 
    RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings(); 
    mappings.RegisterMapping(typeof(Grid), Container.Resolve()); 
    return mappings; 
}

Now I was ready to give the solution a go!

The Problem with Navigation

The first iteration I tried was to declare a single page with the region adapter to process the requests. In my Views folder in the main project, I created a Silverlight Page (Page, not UserControl) and called it Module.xaml. The XAML for the module looked like this:


<navigation:Page x:Class="JeremyLikness.Main.Views.Module" 
           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"
           xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           xmlns:local="clr-namespace:JeremyLikness.Main.Views"
                 d:DesignWidth="640" d:DesignHeight="480"
           Title="Module Page">
    <Grid x:Name="MainGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" cal:RegionManager.RegionName="ModuleRegion">
    </Grid>
</navigation:Page>
      

Going back to the main shell, I mapped all requests to the module, like this:


<Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">

    <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" 
                      Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">
        <navigation:Frame.UriMapper>
          <uriMapper:UriMapper>
            <uriMapper:UriMapping Uri="" MappedUri="/Views/Module.xaml"/>
            <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/Module.xaml"/>
          </uriMapper:UriMapper>
        </navigation:Frame.UriMapper>
    </navigation:Frame>
</Border>

As you can see, pretty much every request is handled by the Module page. In the code behind, I had to work a little bit of magic to ensure the appropriate module would be loaded. First, I added a reference to the module manager:


public partial class Shell : UserControl
{
    private IModuleManager _moduleManager;

    public Shell(IModuleManager moduleManager)
    {
        _moduleManager = moduleManager;
        InitializeComponent();
    }

    private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
    {
    
        string module = e.Uri.ToString().Substring(1);
        string moduleName = string.Format("JeremyLikness.Module{0}.InitModule", module); 
       
        _moduleManager.LoadModule(moduleName);

...

}

The key here was getting the reference to the module manager, then calling the module load on the request. The module manager is smart enough to know when a module has already been loaded, so I didn't have to worry about that. The idea here is that when I request the "bio" tab, the string manipulation maps it to JeremyLikness.ModuleBio.InitModule, then calls the manager. The manager checks to see if it is loaded. If not, it will download the required XAP file and initialize the module. The module would then register the view with the region and it would magically appear!

There were two problems that arose immediately. The first issue was visibility: the different pages were stacking on each other. I'd load the application and see the home page, then click on the bio tab and watch the bio appear overlaid on top of the home page. Definitely not the right solution! We'll address visibility in a minute.

The second was a little more disturbing. The pages were behaving a little strangely so I fired up the debugger and found something disturbing: every time I would navigate to a link, the navigation framework would generate a new instance of the Module.xaml. This, in turn, would create new instances of the views. Just a few clicks of the tab and suddenly I had lots of instances hanging out that I just didn't need.

The solution for this was to create a static view that would live between navigation requests and hold the views as they are stacked in place. The first step was to build the container for the views. Under the Views folder, I created ViewContainer.xaml. The XAML contained the region mapping:


<UserControl x:Class="JeremyLikness.Main.Views.ViewContainer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
   >
    <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
          cal:RegionManager.RegionName="ModuleRegion">
       </Grid>
</UserControl>

The code behind implemented the singleton pattern:


public partial class ViewContainer : UserControl
{
    private static readonly ViewContainer _viewContainer = new ViewContainer();

    private ViewContainer()
    {
        InitializeComponent();
    }

    public static ViewContainer GetViewContainer()
    {
        if (_viewContainer.Parent != null)
        {
            Grid grid = _viewContainer.Parent as Grid;
            grid.Children.Remove(_viewContainer); 
        }

        return _viewContainer;
    }
}

Note that an element can only have one parent, and cannot be added as a child to another element. The GetViewContainer method first detaches the view from its previous parent before returning the instance so that the consumer of the method can use the orphaned view. I removed the region reference from the Module.xaml and added this to the code behind:


public Module()
{
    InitializeComponent();
    MainGrid.Children.Add(ViewContainer.GetViewContainer()); 
}

Now the navigation will still create a new instance of Module every time we navigate, but the module will simply reuse the same container for the views. This ensures that the views persist once they are added and don't have to be reloaded or recreated.

Next, I needed to manage showing and hiding the views so they don't remain stacked on top of each other.

Managing Visibility

To manage the views, I decided to create a service that the views will register to. The service is called when navigation takes place, and then calls back to the views to manage their visibility.

First, I created a new project that would be common across other projects. This was named, ironically, JeremyLikness.Common. First was an interface that the views could use. They provide a name for themselves as well as a method to call to either show or hide. This offloads the need for the view manager to understand how to show or hide a view ... since the view is a UserControl, it should have a pretty good idea.


public interface IPrismView
{
    void Show();

    void Hide();

    string ViewName { get; }
}

Next, I added a reference to the common project in both modules and implemented IPrismView. This is what the Bio.xaml.cs looked like:


#region IPrismView Members

public void Show()
{
    this.Visibility = Visibility.Visible; 
}

public void Hide()
{
    this.Visibility = Visibility.Collapsed;
}

public string ViewName
{
    get { return "Bio"; }
}

#endregion

Now I can create my view manager. In the same common project, I created a class called ActivationManager (continuing the Prism concept of "activating" a view although it is probably misnamed in retrospect). ActivationManager contains a collection of views. It allows a view to register with it, then exposes a method called SwapToView that iterates the views and calls their Show or Hide methods. It looks like this:


public class ActivationManager
{
    List<WeakReference> _views = new List<WeakReference>();

    public void Register(IPrismView view)
    {
        _views.Add(new WeakReference(view));
        view.Show();
    }

    public void SwapToView(string viewName)
    {
        foreach (WeakReference weakRef in _views)
        {
            if (weakRef.Target != null)
            {
                IPrismView view = (IPrismView)weakRef.Target;
                
                if (view != null)
                {
                    if (view.ViewName.Equals(viewName))
                    {
                        view.Show();
                    }
                    else
                    {
                        view.Hide();
                    }
                }
            }
        }
    }
}

Now we need to wire the activation manager in. We only need one copy, so in the boot strapper in the main project, I set up the instance:


protected override DependencyObject CreateShell()
{
    Container.RegisterInstance<ActivationManager>(
        Container.Resolve<ActivationManager>());
    Shell shell = Container.Resolve<Shell>();
    Application.Current.RootVisual = shell;
    return shell;
}

Notice I did this before creating the shell. There is a reason: we need the shell to coordinate the views. The shell has a method that fires when the navigation changes. If you recall, we used this method to tell the module manager to load the appropriate module. Now we'll need to pass in the activation manager and ask it to activate the views. These are the changes to the Shell code-behind:


private ActivationManager _activationManager;

public Shell(IModuleManager moduleManager, ActivationManager activationManager)
{
    _moduleManager = moduleManager;
    _activationManager = activationManager;
    InitializeComponent();
}

private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
{

    string module = e.Uri.ToString().Substring(1);
    string moduleName = string.Format("JeremyLikness.Module{0}.InitModule", module); 
   
    _moduleManager.LoadModule(moduleName);

    _activationManager.SwapToView(module); 

    foreach (UIElement child in LinksStackPanel.Children)
    {
        HyperlinkButton hb = child as HyperlinkButton;
        if (hb != null && hb.NavigateUri != null)
        {
            if (hb.NavigateUri.ToString().Equals(e.Uri.ToString()))
            {
                VisualStateManager.GoToState(hb, "ActiveLink", true);
            }
            else
            {
                VisualStateManager.GoToState(hb, "InactiveLink", true);
            }
        }
    }
}

The last step is to take each module and pass the activation manager into the constructor so the view can register itself. This could probably be moved back into the module initialization (i.e. when the view is injected into the region) and perhaps even something extended on the framework to handle it. However, this works for now, using Bio.xaml.cs as our example:


public Bio(ActivationManager activationManager) : this()
{
    activationManager.Register(this);
}

Notice that I use this() to ensure it calls the default parameterless constructor to InitializeComponent etc etc.

At this point, I claimed victory. After compiling and publishing the project, I was able to navigate between the home and bio tabs, and watch the bio module loaded dynamically when I navigated to the tab. The views swapped in and out nicely. If you were reading this for dynamic module loading ... there it is!

To round out the example, I wanted to show two more things. First, I wanted to take the idea of Show and Hide a step further, and second, I don't believe navigation or deep linking makes sense to discuss unless we also cover search engine optimization.

Visual State Manager

The visual state manager is the key to managing visual states on controls (seems like it was well-named, huh?). I have to thank Justin Angel for pointing this out to me when I was doing a lot of behaviors and triggers for animations that truly belonged in the VSM instead. Really, when we're swapping our views, we are changing the state of the view ("show me" or "hide me"). If we do this programmatically, then we're stuck with the attributes we set. However, if we do this through the VSM, then all of the the transition becomes customizable through the designer and in Expression Blend, so our designers can then tinker with the transitions without touching the code behind.

To demonstrate this, I decided to take both views and give them a ShowState and a HideState. To show the power of the Visual State Manager, I created two different transitions: the home page will explode in using a scale transform, while the biography page will fade in using an opacity animation.

Because there are a million examples that show how to add custom view states using Blend, I decided to document the code behind approach. The main container in our views is a grid, so that's what we're going to manipulate. I want the view to hide immediately, but when it goes to show, it should have a nice animation. This is what the Bio.xaml ends up looking like:


<Grid x:Name="LayoutRoot" Background="White">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStates">
                <VisualState x:Name="ShowState">
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:01.0000000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
                            <EasingDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
                        </DoubleAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:01.0000000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Visible</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="HideState">
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0000100" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
                            <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                        </DoubleAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:01.0000100" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Collapsed</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <TextBlock>This is my bio. It tells people about me and my background.</TextBlock>
    </Grid>

So there are a few things going on here. First, we define a "group" of visual states that I call, sure enough, VisualStates. I am defining two states: a HideState and a ShowState. The hide state has an animation with a zero duration and simply sets the Opacity to 0. The show state animates for a second (you'd normally make this faster, but it helps demonstrate my point) and fades in. While many people are used to the color and double animations, did you know there existed an object animation as well? This allows you to manipulate almost any property on your target control using the visual state. In this case, I won't even have to set the Visibility property in my code behind - I simply define the value in the view state! Notice in the ShowState that the property is set immediately so it becomes visible in time for the animation to fire and fade it in.

So now we simply go to the code-behind for our control and set the state. The VSM expects a control when you set the state, but it will traverse the hierarchy and find the state you specify. So while we set the state on our control, it will use the state definitions that are contained within the grid object. We also make sure we set a default state in the constructor. In this case, it will be hidden because the activation manager will call show when it is registered. This is what our new code-behind looks like:


public partial class Bio : UserControl, IPrismView
{
    public Bio()
    {
        InitializeComponent();
        VisualStateManager.GoToState(this, "HideState", false);
    }

    public Bio(ActivationManager activationManager) : this()
    {
        activationManager.Register(this);
    }

    #region IPrismView Members

    public void Show()
    {
        VisualStateManager.GoToState(this, "ShowState", true);
    }

    public void Hide()
    {
        VisualStateManager.GoToState(this, "HideState", true);
    }

    public string ViewName
    {
        get { return "Bio"; }
    }

    #endregion
}

As you can see, we simply move to a new state and leave it up to the designer to add any fancy animations or other transitions when that happens.

Getting Along with Search Engines

The final piece here is to get along with search engines. Deep linking is nice if you just want to add it to your favorites and jump right in, but doesn't really do much for search engines when they are scanning the page. The search enginges need to have some points like a page title and description to properly index your pages.

In the common project, I created a class called SEOHelper to contain my title, description, and keywords. It exposes a method called PageUpdate that then parses these values into the HTML page. Let's take a look at the class:


public class SEOHelper
{
    private const string TEMPLATE = "metatags = document.getElementsByTagName(\"meta\");"
        + "for (x=0;x<metatags.length;x++) {{"
        + "var name = metatags[x].getAttribute(\"name\");"
        + "if (name == '{0}'){{"
        + "var content = metatags[x].getAttribute(\"content\");" 
        + "metatags[x].setAttribute('{0}','{1}');break;}}}}";

    private List<string> _keywords = new List<string>();

    public string Title { get; set; }

    public string Description { get; set; }

    public void AddKeyword(string keyword)
    {
        _keywords.Add(keyword);
    }

    public void UpdatePage()
    {
        HtmlPage.Document.SetProperty("title", Title);

        string titleSet = string.Format(TEMPLATE, "title", Title);
        HtmlPage.Window.Eval(titleSet);

        string descriptionSet = string.Format(TEMPLATE, "description", Description);
        HtmlPage.Window.Eval(descriptionSet);

        if (_keywords.Count > 0)
        {
            StringBuilder keywordList = new StringBuilder();
            bool first = true;
            foreach (string keyword in _keywords)
            {
                keywordList.Append(keyword);
                if (first)
                {
                    first = false;
                }
                else
                {
                    keywordList.Append(",");
                }
            }
            string keywordSet = string.Format(TEMPLATE, "keywords", keywordList);
            HtmlPage.Window.Eval(keywordSet);
        }
    }
}

I'm not a big fan of burying JavaScript inside of C# classes, so I included it here only to help keep the solution in one place. Ordinarily I'd have some methods defined in a .js file that this would link to.

Setting the title is a call into the document object. Setting the meta tags is a little more convuluted. You could create the tags but in this example, I'm stubbing out empty title, description, and keywords meta-tags, then finding them and updating the content attribute. The TEMPLATE contains the code to iterate the tags, then update the content attribute. The PageUpdate method simply updates the meta tag name and content then asks the page to evaluate the javascript.

Now we just place the object inside of the appropriate view and call it when the view becomes visible. Here is the new Home.xaml.cs:


public partial class Home : UserControl, IPrismView
{
    SEOHelper _helper = new SEOHelper { Title = "Home Page", Description="Home page for the website." }; 

    public Home()
    {
        InitializeComponent();
        VisualStateManager.GoToState(this, "HideState", false);
        _helper.AddKeyword("Home");
        _helper.AddKeyword("SEO"); 
    }

    public Home(ActivationManager activationManager)
        : this()
    {
        activationManager.Register(this);
    }

    #region IPrismView Members

    public void Show()
    {
        VisualStateManager.GoToState(this, "ShowState", true);
        _helper.UpdatePage();
    }

    public void Hide()
    {
        VisualStateManager.GoToState(this, "HideState", true);
    }

    public string ViewName
    {
        get { return "Home"; }
    }

    #endregion
}

As you can see, the helper takes in the settings for the page, then whenever the view is shown (the Show) method, the helper is called to update the page. For testing, this could be abstracted even further to a ISEOHelper to avoid trying to actually access the html page when its not needed.

Trimming the XAP Size

Last but not least is trimming the XAP size. I put most of my references in the main XAP file, so they aren't needed in the modules. By going to the project properties, I can check "Reduce XAP size by using appliciation library caching." This will create a new ZIP file that contains some of the referenced controls on my modules when they build, and not include them in the main XAP. Fortunately, these are already loaded by the main XAP, so there is nothing more to do when the XAP is loaded.

There it is ... I know this was a long blog post for what, in the end, is a simple page with two tabs. However, I hope this has proven that you can combine Prism with Silverlight Navigation and use dynamic module loading will keeping your pages search engine friendly. The VSM piece might have made sense in a separate post but I also wanted to get a good example out there that shows how to wire it in when you're not making a custom control or using Blend. Enjoy!

Download the source

View the demo

Jeremy Likness

One common complaint I see regarding Silverlight is the inability to include inline hyperlinks. While Silverlight does provide a HyperlinkButton, you cannot do something simple like:


This is some text. This is <a href="http://www.wintellect.com/">a hyperlink</a>, in case you were wondering. 

There are a few solutions available via third-party controls, but it's a good exercise to understand the underlying fundamentals of the rendering engine, controls, and objects that make up a TextBlock. In this article, we'll set out on a quest to be able to take a simple set of text, formatted for a text block, and generate inline links.

The first step is to simply open your solution, start a new Silverlight 3 application, and get rolling with some text. The easiest way to grab text is to visit Lorem Ipsum, where you can request however much text you need and it will generate the paragraphs for you. I just grabbed a few sentences and set the width of my control to 200 so I could show the text wrapping. The final markup looks like this (I called my project "SLHyperlink"):

<UserControl x:Class="SLHyperlink.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" d:DesignWidth="640" d:DesignHeight="480"
   Width="200">
      <Grid x:Name="LayoutRoot">
        <TextBlock TextWrapping="Wrap">Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
            Aenean eget turpis id purus tempor tincidunt porttitor eu mi. 
            Vestibulum tincidunt odio quis nibh feugiat faucibus. 
            Fusce rhoncus tristique mi non posuere. 
            Nunc sit amet velit magna.
  </Grid>
</UserControl>

When I run the solution, this is what appears:

Lorem Ipsum

Now, we can get a little fancier. If you are familiar with the TextBlock control, you know you can mix and match different styles of text within the control, and even provide line breaks. You do this using the Run and the LineBreak markup. Let's spruce up the text a bit. I made the font size larger, added a few runs and a line break, and changed the width of the control to 300 to accommodate the larger text:


<TextBlock TextWrapping="Wrap" FontSize="20"><Run FontFamily="Times New Roman">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Run> 
            Aenean eget turpis id purus tempor tincidunt porttitor eu mi. 
            <Run Foreground="Cyan">Vestibulum tincidunt odio quis nibh feugiat faucibus.</Run> 
            Fusce rhoncus tristique mi non posuere.<LineBreak/>
            Nunc sit amet velit magna.</TextBlock>

The result is this:

Lorem Ipsum

Anatomy of a TextBlock

Now that we have the inline text, we can start to dissect the classes. There are a few tools at our disposal. First, we can go into the Object Browser in Visual Studio and search for TextBlock. We find out that it inherits directly from FrameworkElement and is, unfortunately, a sealed class, so we cannot create our own dervied class. There are plenty of text-related dependency properties (font size, font family, font weight, etc) and then a few interesting methods like OnCreateAutomationPeer and the collection of Inlines.

Running RedGate's free .Net Reflector tool, we can generate the shell of the class:


[ContentProperty("Inlines", true)]
public sealed class TextBlock : FrameworkElement
{
    // Fields
    private FontSource _fontSource;
    public static readonly DependencyProperty FontFamilyProperty;
    public static readonly DependencyProperty FontSizeProperty;
    public static readonly DependencyProperty FontStretchProperty;
    public static readonly DependencyProperty FontStyleProperty;
    public static readonly DependencyProperty FontWeightProperty;
    public static readonly DependencyProperty ForegroundProperty;
    private static readonly DependencyProperty InlinesProperty;
    public static readonly DependencyProperty LineHeightProperty;
    public static readonly DependencyProperty LineStackingStrategyProperty;
    public static readonly DependencyProperty PaddingProperty;
    public static readonly DependencyProperty TextAlignmentProperty;
    public static readonly DependencyProperty TextDecorationsProperty;
    public static readonly DependencyProperty TextProperty;
    public static readonly DependencyProperty TextWrappingProperty;

    // Methods
    static TextBlock();
    public TextBlock();
    internal override string GetPlainText();
    protected override AutomationPeer OnCreateAutomationPeer();
    private void UpdateFontSource(FontSource fontSource);

    // Properties
    public FontFamily FontFamily { get; set; }
    public double FontSize { get; set; }
    public FontSource FontSource { get; set; }
    public FontStretch FontStretch { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontWeight FontWeight { get; set; }
    public Brush Foreground { get; set; }
    public InlineCollection Inlines { get; }
    public double LineHeight { get; set; }
    public LineStackingStrategy LineStackingStrategy { get; set; }
    public Thickness Padding { get; set; }
    public string Text { get; set; }
    public TextAlignment TextAlignment { get; set; }
    public TextDecorationCollection TextDecorations { get; set; }
    public TextWrapping TextWrapping { get; set; }
}

What's interesting for us is the Inlines collection. In Silverlight, the System.Windows.Documents.Inline class is summarized as "An abstract class that provides a base for all inline flow content elements." There are exactly two classes that inherit from them, and both of them are sealed: Run and LineBreak. The Run class simply contains a text property:


[ContentProperty("Text", true)]
public sealed class Run : Inline
{
    // Fields
    private static readonly DependencyProperty TextProperty;

    // Methods
    static Run();
    public Run();

    // Properties
    public string Text { get; set; }
}

It turns out if you give your TextBlock a name (x:Name="tbSomething") and then debug, you'll find that the text we entered inside the TextBlock is turned into a collection. The free text goes into a run without additional attributes, so the collection is of runs and line breaks. Not only are these classes sealed, but they inherit directly from DependencyObject, so they are not FrameworkElement (or even UIElement) derived. This means we can't do things like check mouse events or bind to click events.

Instead of creating our own text block control, it appears that the existing has everything we need except the actual hyperlink. After brainstorming for a bit, I decided the easiest way to implement this would be to translate the text block into a wrap panel. A wrap panel does what we want: it allows elements of various sizes to stack together (like text flowing together). If we want an inline hyperlink, we simply need to stack a text block, followed by a navigation button for the hyperlink, followed by another text block. We can separate out the hyperlink by placing it in its own run.

An Extended Run

Even though our Run class is sealed, it derives from Inline which, in turn, is a DependencyObject, so we are allowed to generate attached properties.

The first thing I did was create a static class called RunExtender and add an attached property for a NavigateUrl. This is what I can attach to the run that will become a hyperlink. The code looks like this:


public static class RunExtender 
{  
    public static Uri GetNavigateUrl(DependencyObject obj)
    {
        return (Uri)obj.GetValue(NavigateUrlProperty);
    }
    
    public static void SetNavigateUrl(DependencyObject obj, Uri value)
    {
        obj.SetValue(NavigateUrlProperty, value); 
    }

    public static readonly DependencyProperty NavigateUrlProperty =
        DependencyProperty.RegisterAttached("NavigateUrl",
                                    typeof(Uri),
                                    typeof(RunExtender),
                                    null);
}

Now I can add an inline hyperlink and add the attached navigation property. This won't change anything yet, but it sets us up for the next iteration.

First, I add the namespace to the top of the control:


xmlns:local="clr-namespace:SLHyperlink"

Next, I add some more text to the text block and decorate it with the new attached property:


<TextBlock TextWrapping="Wrap" FontSize="20"><Run FontFamily="Times New Roman">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Run> 
            Aenean eget turpis id purus tempor tincidunt porttitor eu mi. 
            Here is an <Run local:RunExtender.NavigateUrl="http://www.wintellect.com/">inline hyperlink</Run>.
            <Run Foreground="Cyan">Vestibulum tincidunt odio quis nibh feugiat faucibus.</Run> 
            Fusce rhoncus tristique mi non posuere.<LineBreak/>
            Nunc sit amet velit magna.</TextBlock>

The generated output isn't interesting yet, but no errors so far:

Lorem Ipsum

Warping the WrapPanel

Now things are getting interesting. What I want to do is make my text block a resource, then move it into a wrap panel. Attached properties come to our rescue again, because I can create an attached property for a wrap panel that points to my text block resource. When it is attached, we'll parse the inline collection and build out a new set of children for the wrap panel to render.

We're going to have to move a lot of values from the reference text block to our targets in the wrap panel. The first thing I did was to add some static collections of attributes for the text block, inline element, and a generic control (in the case of the hyperlink button we'll generate). I also want to clean the text as we move it from one to the other, so I set up a regular expression to help strip whitespace. This block looks like:


private static FieldInfo[] _tbInfo = typeof(TextBlock).GetFields(BindingFlags.Static | BindingFlags.Public);
private static FieldInfo[] _rInfo = typeof(Inline).GetFields(BindingFlags.Static | BindingFlags.Public);
private static FieldInfo[] _cInfo = typeof(Control).GetFields(BindingFlags.Static | BindingFlags.Public);
private static readonly Regex _reg = new Regex(@"\s+");

Notice we are just getting the public and static properties from the types.

The clone method I created could probably be refactored and cleaned up several times over, but it does the trick. I want to be able to transfer properties from a source to a target. If the source and target are the same type, we can reference the same dependency properties. If they are different types, we'll need to lookup the dependency property on the target that has the same name as the dependency property on the source. Take a peek at this:


private static void _Clone(DependencyObject src, DependencyObject tgt, FieldInfo[] fi)
{
    _Clone(src, tgt, fi, null);
}

private static void _Clone(DependencyObject src, DependencyObject tgt, FieldInfo[] fi, FieldInfo[] fiTgt)
{
    for (int i = 0; i 

(Yes, I know there is some duplicated code that could be pulled out into another method)

So we essentially have our source and target, and the collection that contains the fields and properties. I only send a second collection in if the target is different.

We begin by iterating all properties on the source. We need to make sure we get a valid reference. I then filter the properties to only move what I'm interested in. For the text block, it's the font, line, and foreground properties, as well as the text alignment and text wrappig. I don't want, for example, to get the "Height" property (we'll let the engine size it for us) and I certainly don't want to move the "Text" property (we'll be iterating the collection of inlines for that).

For the run, it's just font information and the foreground.

If the value is a nested object (for example, a brush), we simply set the value on the target. If the target is a different type, I first iterate the target list of properties to find the property with the same name, then set the object to that.

If it's not a nested object, I get the value, then set the value on the target. Again, if the target is a different type, I have to find the corresponding dependency for the target and then set the value on that.

Now that we've got some nice helpers in place, we can set up a new attached property that points to a text block. Remember, my goal is to take that in, parse it, and output elements into a wrap panel.

Here is the setup:


public static TextBlock GetTargetTextBlock(DependencyObject obj)
{
    return (TextBlock)obj.GetValue(TargetTextBlockProperty);
}

public static void SetTargetTextBlock(DependencyObject obj, TextBlock value)
{
    obj.SetValue(TargetTextBlockProperty, value); 
}

public static readonly DependencyProperty TargetTextBlockProperty =
    DependencyProperty.RegisterAttached("TargetTextBlock",
                                typeof(TextBlock),
                                typeof(RunExtender),
                                new PropertyMetadata(null, new PropertyChangedCallback(OnTargetAttached)));

And now it's time to do the actual parsing. What I want to do is take each run and make it either a new text block (we are mapping to multiple text blocks because the wrap panel is going to wrap on the outermost container ... if we put all the runs inside a single text block, it will only wrap in the text block and not in the context of the wrap panel container) or a hyperlink button. The hyperlink button will take on the attributes of the text block except the foreground (we'll keep the default of that being blue to show that it's a link). All of these will become children of the new wrap panel.

Don't forget that the wrap panel exists in the toolkit that you can download here. We simply need to add a reference to System.Windows.Controls.Toolkit in our project.

Here's the code:


public static void OnTargetAttached(object obj, DependencyPropertyChangedEventArgs args)
{
    WrapPanel panel = obj as WrapPanel;
    if (panel != null)
    {
        TextBlock src = args.NewValue as TextBlock;
        if (src != null)
        {
            foreach (Inline inline in src.Inlines)
            {
                if (inline is LineBreak)
                {
                    TextBlock newBlock = new TextBlock();
                    newBlock.Inlines.Add(new LineBreak());
                    panel.Children.Add(newBlock); 
                }
                else if (inline is Run)
                {
                    Run run = inline as Run;
                    Uri navigateUri = run.GetValue(NavigateUrlProperty) as Uri;
                    if (navigateUri != null)
                    {
                       HyperlinkButton button = new HyperlinkButton();
                        button.Content = run.Text;
                        button.NavigateUri = navigateUri;
                        _Clone(src, button, _tbInfo, _cInfo); 
                        panel.Children.Add(button);
                    }
                    else
                    {
                        Run newRun = new Run { Text = _reg.Replace(run.Text.Replace('\n',' ')," ").Trim() };
                        _Clone(run, newRun, _rInfo);
                        TextBlock newBlock = new TextBlock();
                        _Clone(src, newBlock, _tbInfo);
                        newBlock.Inlines.Add(newRun);
                        panel.Children.Add(newBlock);
                    }
                }
            }
        }
    }
}

Now that we've got that all in place, it's time to update our main page. First, we'll add a reference to the toolkit:


xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

Next, we pull our text block into the resources section and give it a key. This makes it a resource now instead of an inline text block:


<UserControl.Resources>
        <TextBlock x:Key="tb" TextWrapping="Wrap" FontSize="20"><Run FontFamily="Times New Roman">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Run> 
            Aenean eget turpis id purus tempor tincidunt porttitor eu mi.<LineBreak/> 
            Here is an <Run local:RunExtender.NavigateUrl="http://www.wintellect.com/">inline hyperlink</Run>.
            <Run Foreground="Cyan">Vestibulum tincidunt odio quis nibh feugiat faucibus.</Run> 
            Fusce rhoncus tristique mi non posuere.<LineBreak/>
            Nunc sit amet velit magna.</TextBlock>
    </UserControl.Resources>

In our main grid, instead of the text block, we'll now use a wrap panel and set the text block as the target:


<Grid x:Name="LayoutRoot">
   <controls:WrapPanel local:RunExtender.TargetTextBlock="{StaticResource tb}"/>
</Grid>

Now we run it, and this is what we get:

Lorem Ipsum

It's the same text as before, but with a nice, clickable hyperlink. Clicking the hyperlink validates that it does indeed take us to the Wintellect home page.

Now you can add inline hyperlinks to your heart's desire simply by decorating the run and using the wrap panel.

There are several third party controls available that help with rendering HTML and hyperlinks that you can use, but I always believe it's helpful to understand the how and why. Hopefully this exercise assisted you with a better understanding of dependency objects and properties and more specifically the text rendering functionality that is available out of the box with Silverlight 3.

You may download this example here.

Jeremy Likness

Dynamic data is a technology that enables RAD (rapid application development) for data-driven applications. What is a data-driven application, or rather, when does it make sense to use ASP.NET Dynamic Data?

Any type of CRUD (create/read/update/delete) application is a prime candidate for dynamic-driven applications. In fact, if you are building an internal site simply to administer or configure certain data stores, dynamic data is a very viable solution.

There is a major misconception that data driven entities relies on generated code and therefore suffers from the same issues many of the older "code generators" did. The reality is that dynamic data can live side-by-side with a traditional application and is extremely extensible. There are plenty of customization hooks that can empower you to rapidly generate a framework yet still maintain control over the user experience, validation, and business logic.

This post is for those of you either working with or considering using dynamic data. These are just a few tips based on my personal experience that may help with building your dynamic data solution. I am using LINQ to SQL for this example, but most of these tips are applicable to the entity framework flavor as well.

Adding Table MetaData

The first and key step to understand is how to extend your generated tables with meta data. There is no way to directly apply meta data to the LINQ generated classes, but with a little bit of magic we can use a custom meta data class.

Step One: create a partial class with the same name as your generated table. In the dbml code-behind, the table will be declared something like this:

[Table(Name="dbo.MyTable")]
public partial class MyTable : INotifyPropertyChanging, INotifyPropertyChanged 

In this case, I will create a MyTable.cs file. It is important this lives in the same namespace as your LINQ class (navigate to the top of the designer.cs class to see what the namespace is) and is declared as a partial class.

Your class will be empty, like this:

public partial class MyTable
{
    
}

Step Two: We will create a metadata class to help provide additional hints to the engine. I like to put this class into the same .cs file as the partial class to make it easier to understand and manage. Now our code will look like this:

public partial class MyTable
{
    
}

public class MyTableMetaData 
{

}

Now the "glue" to tie the LINQ class to the meta data class. You must use System.ComponentModel and System.ComponentModel.DataAnnotations, then decorate the extended LINQ class with the MetadataType attribute. The code looks like this:

[MetadataType(typeof(MyTableMetaData))]
public partial class MyTable
{
    
}

public class MyTableMetaData 
{

}

Now the metadata is "glued" to the LINQ class. So, let's do our first customization and change the table name so it doesn't show "MyTable" in the UI, but instead displays as "My Table":

[MetadataType(typeof(MyTableMetaData))]
[DisplayName("My Table")]
public partial class MyTable
{
    
}

public class MyTableMetaData 
{

}

Customizing the Field Template

If you navigate in your dynamic data solution to DynamicData -> FieldTemplates you'll find a collection of user controls that the dynamic data engine uses to render the fields. All of these are customizable. For example, the default textbox is a fixed width. You may want to size it to fit the width of the container. In the CSS, you can add a class:

.cssTextBox {
   width: 100%; 
}

Then crack open the Text_Edit.ascx file and add the attribute: CssClass="cssTextBox" to the textbox definition. You can, of course, style the control even further as needed.

Foreign Key References

Dynamic data entities tries to make a "best guess" about which column of a table makes sense to display for a foreign key. For example, let's assume we have a "Student" class that associated with "Classroom." The dynamic data engine may "guess" that the student's phone number is the most appropriate field to show. Obviously, you would prefer to list their full name. To do this, simply decorate the table class (not the metadata class) with the DisplayColumn annotation, like this:

[DisplayColumn("FullName")]
public partial class Student 
{

}

Custom Controls

Creating custom controls is easy. You may have a particular field that is an integer value for a specific range. It makes more sense to use a slider control instead of the auto-generated textbox. Here are the steps to create your custom control:

Display, Edit, or Both?

Create a user control under DynamicData -> FieldTemplates. The format for these controls is controlname and controlname_edit. You do not have to supply both ... you might only want to override the display mode, or the edit mode. In this case, we're doing the edit mode, so you would create a user control called Slider_Edit.ascx.

Inherit from System.Web.DynamicData.FieldTemplateUserControl

This is required for your custom field control.

Override DataControl

This should return the main control holding the field state. For example, if your slider has the identifier MySlider, your override will look like:

public override Control DataControl 
{
   get 
   {
      return MySlider;
   }
}

You can get the value of the current field using FieldValueString.

For Edit Controls, Override ExtractValues

ExtractValues is the interface between your custom control and the data store. The ExtractValues method is called with a IOrderedDictionary that contains all of the columns in the data store. Your job is to to take a text value from your control and pass it back into the dictionary using the ConvertEditedValue helper method. In our slider example, if the value is exposed by SelectedValue, you would wire in the value like this:

protected override void ExtractValues(IOrderedDictionary dictionary) 
{
   dictionary[Column.Name] = ConvertEditedValue(MySlider.SelectedValue); 
}

Making a Field Readonly (Custom Control)

Now that we know how to customize our controls, here's how to make a field readonly.

  1. Navigate to DynamicData -> FieldTemplates
  2. Right click on Text.ascx and select "copy"
  3. Right click on the FieldTemplates folder and select "paste"
  4. Rename the pasted control to "ReadonlyText_Edit" and make sure the markup matches the code behind (you'll need to change the class name from TextField to ReadonlyTextField_Edit.
  5. Add the UIHint to the field you wish to make read only

How do we provide the hint? Navigate to the meta data object you created for the table, and decorate the attribute. In "MyTable" if I want to make "MyField" read only, I would do this:

[MetadataType(typeof(MyTableMetaData))]
public partial class MyTable 
{
}

public class MyTableMetaData 
{
   [UIHint("ReadonlyText")]
   public object MyField { get; set; }
}

Notice that I name the property I'm overriding, but declare it as a simple object. I'm not typing it here. The purpose of the meta data is provide annotiations as hints to the dynamic data engine. My hint tells it to use the ReadonlyText control. When displaying the field, the engine searches for ReadonlyText.ascx and cannot find it, so it defaults to the original target, Text.ascx. In edit mode, it finds ReadonlyText_Edit.ascx and therefore instantiates that control, which simply displays the field and does not allow editing.

Applying Validation Attributes

Applying validation attributes is simple. Let's assume we have a field that is required, and cannot exceed 50 characters in length. Applying these validations is as simple as:

public class MyTableMetaData 
{
   [Required]
   [StringLength(50,ErrorMessage="My field cannot exceed 50 characters in length.")]
   public object MyField { get; set; }
}

There is event built-in support for a regular expression validator!

Extending the User Experience

To extend the user experience is quite simple. Let's assume, for examle, you have an enumeration of "type" in your table, and type translates to "square", "circle" and "triangle." You wish to enhance the control by providing a little more information about the item that was selected. You can easily create your custom control, then sprinkle in your customizations. Consider, for example, a Type_Edit.ascx markup that looks like this:

<asp:DropDownList ID="ddType" runat="server" CssClass="droplist">
    <asp:ListItem Value="0" Text="Square" />
    <asp:ListItem Value="1" Text="Circle" />
    <asp:ListItem Value="2" Text="Rectangle" />
</asp:DropDownList> <asp:Label ID="lblType" runat="server" />

Beneath that, we add a JavaScript block (using JQuery):


    var hints = new Array('All sides are the same length!', 
         'Circles have an intimate relatinship with pi',
         'A rectangle is a shape where parallel sides are equal length');

    $(document).ready(function() {
        $('#<%= ddType.ClientID %>').change(function() {
            setTypeHint();
        });
        $('#<%= ddType.ClientID %>').val('<%# FieldValueEditString %>');
        setTypeHint();
    });

    function setTypeHint() {
        var value = $('#<%= ddType.ClientID %>').val();
        $('#<%= lblType.ClientID %>').text(hints[value]);
    }

Now you can easily see the new "hint" every time the drop down field changes.

Changing Field Names

Changing the label or column heading that appears for a given column is as simple as changing the display name for a table. On the property you wish to provide a hint for, simply add the DisplayName attribute:

public class MyTableMetaData 
{
   [DisplayName("My Field")]
   public object MyField { get; set; }
}

Swapping out Pages

Sometimes you may want to override the built-in functionality for a given page. For example, on a grid list, you might want to restrict the columns that are displayed. Definining your own page in place of the built-in template is simple.

  1. Under the DynamicData folder, create a new folder called CustomPages
  2. Under CustomPages, create a new folder with the same name as the class you want to change the page for. For example, if your class is called MyTables, you will create a folder called MyTables
  3. Add the page you wish to override. In our example, we'll copy the List.aspx page from the PageTemplates folder and paste it into the MyTables folder. Now, when the list for MyTables is displayed, it will use the new page instead of the supplied template.

In the grid definition, I can add the asp:DynamicField tag for any fields I wish to display, and leave out the ones I don't want (or I might even decide to use something besides a grid altogether)

The Foreign Key Edit Bug

If your table has a many-to-many relationship, you may have observed a bug. Let's say we have Groups and Persons, and a person can belong to multiple groups. In the "Group" display, there will be a link generated for "View Persons" that takes me to the list of persons associated to the that group. If I click "edit" however, suddenly the class name for the LINQ entity appears intead of a nice link!

This bug is easy to fix. You don't want the user editing the associations "in line", so simply copy the Children.ascx field template and paste it as Children_Edit.ascx. This will cause the same "view link" code to fire in edit mode, and allow the user to navigate to the associations and edit them directly, rather than being presented with the result of a ToString that was never overridden.

Complex Validation (LINQ Flavor)

In the many-to-many example, it is often a requirement that only one unique relationship exists (for example, you do not want to have multiple instances of "Person A belongs to Group 1" in your many-to-many link table). This may be enforced by a database rule. However, when you fire up your dynamic data application and test adding a duplicate link, you simply see the yellow exclamation mark indicating a JavaScript error and see that a unique index constraint was violated. This isn't very user friendly!

Fortunately, the LINQ class provides a hook to perform your own validation, called OnValidate. For this particular example, I wrote a static class to extend my data access validations, that looked like this:

public static class PersonGroupLinkExtensions
{
    // check for a duplicate prior to inserting
    public static bool IsDuplicate(int personId, int groupId)
    {
        using (MyDatabaseDataContext context = new MyDatabaseDataContext())
        {
            int count = (from link in context.PersonGroupLinks
                         where link.PersonID == personId
                         && link.GroupID == groupId
                         select link).Count();
            return count > 0;
        }
    }
}

Simple enough: simply validate whether or not that combination already exists. Then, in the partial class I used to extend from the LINQ class, I implement the partial method OnValidate: (partial methods are different than overrides ... good homework project if you are not familiar with them).

partial void OnValidate(System.Data.Linq.ChangeAction action)
{
    if (action.Equals(System.Data.Linq.ChangeAction.Insert))
    {
        if (PersonGroupLinkExtensions.IsDuplicate(this.PersonID, this.GroupID))
        {
            throw new ValidationException("Combination already exists and duplicates are not allowed.");
        }
    }
}

Conclusion

This is by no means an exhaustive coverage of dynamic data. There is much more to explore, from scaffolding to routes and the Entity Framework. Hopefully this is a good guide to help you get started, jump over a few hurdles many people encounter, and also discover just how flexible and rich the tools provided by dynamic data truly are.

Jeremy Likness

The much-anticipated next release of the SQL 2008 R2 November CTP is here ... for those of you using Azure, the ability to connect directly to a SQL Azure instance via the object explorer has been long-awaited!

Jeremy Likness

For those of you who have been experimenting with the CTP and waiting eagerly for the control to go to release, it's finally here! The Bing Maps Silverlight SDK is released to version 1.0.

Jeremy Likness

It's here! I haven't had the opportunity to play with it yet, but I just downloaded the bits for the Microsoft SDK for Facebook platform and am really looking forward to tinkering!

Jeremy Likness

Silverlight has myriad ways to connect to other systems and retrieve information for your applications. It is a common question people ask ("How do I get my data from the database to Silverlight?") and each method has its own pros and cons. The purpose of this project, "Silverlight Communicator," is to provide a simple, easy reference project that demonstrates three sample methods for communication in Silverlight 3. While these certainly aren't all of the ways Silverlight can obtain data, it does summarize more commonly used methods.

Download Source Now (44 Kb)

Silverlight Communicator

The main page is straightforward and uses the MVVM (Model-View-ViewModel) pattern to bind to the selections (no code-behind). I kept it simple and sweet: just a grid with two listboxes, which are bound to the view model that is instantiated as a static resource.

<UserControl x:Class="SilverlightCommunication.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" 
    xmlns:local="clr-namespace:SilverlightCommunication"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
    <UserControl.Resources>
        <local:ViewModel x:Key="ViewModel"/> 
    </UserControl.Resources>
        <Grid x:Name="LayoutRoot" DataContext="{StaticResource ViewModel}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <ListBox Grid.Column="0" ItemsSource="{Binding CommunicationTypes}" DisplayMemberPath="Name"
                 SelectedItem="{Binding Path=Communication,Mode=TwoWay}"/>
        <ListBox Grid.Column="1" ItemsSource="{Binding Months}" DisplayMemberPath="Name"/>
  </Grid>
</UserControl>

The view model exposes a collection of CommunicationType. This could probably be an enum but for the contrived example, it is loaded up and wired in the view model constructor and maps to the options for choices of the communication type. The view model also exposes a collection of Month, which is a class that contains just one property: Name (you guessed it: the name of the month). Again, a contrived example but it made more sense to bind to a class than a simple string.

If you notice in the code behind, I wired in SelectedItem="{Binding Path=Communication,Mode=TwoWay}". This will data bind the selected item of the list box to the property called Communication on the view model. This allows me to intercept the setter and work some magic. The "magic" looks like this:

set
{
    _communicationType = value;
    IMonthService service = ServiceFactory.GetService(value);
    if (service != null)
    {
        service.MonthsLoaded += new EventHandler<MonthArgs>(service_MonthsLoaded);
        service.RequestMonths();
    }
}

As you can see, when a communication type is selected, the view model goes to a factory and retrieves a service that honors the IMonthService contract. It then wires into a loaded event (where it will insert the months into the Months property) and requests the month list. Because Months is an ObservableCollection, it will fire an event to notify the UI that it has changed and the result will be a month list populated in the list box on the right side.

The month service contract is simple, but this is where we will implement three different ways to retrieve our list of months:

namespace SilverlightCommunication
{
    public interface IMonthService
    {
        void RequestMonths();

        event EventHandler<MonthArgs> MonthsLoaded;
    }
}

Before we jump into the specific methods, here's a peek at the factory. Again, the focus here is the communication methods, not a full-blown enterprise application. You'll see a lack of exception handling and other "good coding practices" here so we can focus on the meat of the project. Based on the type, the factory just returns the appropriate instance.

I also just want to call this out: I know you won't be spending all day on the application, so I don't mind newing up the instances. In a production application, these would probably use the singleton pattern to provide a single instance, or perhaps be configured in an inversion of control container with a lifetime manager.

public static IMonthService GetService(CommunicationType type)
{
    if (type.ID.Equals(1))
    {
        return new WCFMonthServiceImpl();
    }
    else if (type.ID.Equals(2))
    {
        return new RESTMonthService();
    }
    else if (type.ID.Equals(3))
    {
        return new CallbackMonthService();
    }
    else return null; 
}

Method One: WCF Service

WCF is one of the more popular methods. It is also fairly straightforward with Silverlight. On the server side, we define a service that simply returns a list of strings for each month. The contract looks like this:

[ServiceContract]
public interface IMonthService
{
    [OperationContract]
    List<string> GetMonths();
}

And the implementation is simple:

public List<string> GetMonths()
{
    return new List<string> { "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", 
        "Diciembre" };
}

The months will return in Spanish to distinguish the results from the other modes of communication.

The first key to making the service useable by Silverlight is to make sure it has a simple binding. The Web.config most likely generated it as a wsHttpBinding, what we want is a basicHttpBinding. A quick change leaves a configuration that looks like this:

<system.serviceModel>
  <behaviors>
   <serviceBehaviors>
    <behavior name="SilverlightCommunication.Web.MonthServiceBehavior">
     <serviceMetadata httpGetEnabled="true" />
     <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
   </serviceBehaviors>
  </behaviors>
  <services>
   <service behaviorConfiguration="SilverlightCommunication.Web.MonthServiceBehavior"
    name="SilverlightCommunication.Web.MonthService">
    <endpoint address="" binding="basicHttpBinding" contract="SilverlightCommunication.Web.IMonthService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   </service>
  </services>
 </system.serviceModel>

In production, we'd probably secure the service and use an HTTPS endpoint, and define a specific fault contract to manage errors.

At this point you should be able to publish the service and browse to it locally.

If your computer complains that there is a "page not found" at the service endpoint (on my machine, at http://localhost/MonthService.svc), the services are most likely not registered.

To register them, follow these steps:

  1. Open a command line as administrator
  2. Browse to the Windows Communication Foundation folder, on most systems it will be C:\windows\microsoft.NET\v3.0\Windows Communicatoin Foundation
  3. Run "ServiceModelReg -i"

Now you should be registered and able to browse to your service.

On the Silverlight side, we add a service reference. In this project, I added it as WCFMonthService. This generates the ServiceReferences.ClientConfig file. You will most likely have to modify this file to point to the location of your service, unless you are hosting at the localhost root as I did. To see how you can manipulate your service bindings to automatically adjust to the install location, read my post Abstracting WCF Service Calls in Silverlight 3 (and read the caveat about HTTPS as well.)

Now the implementation of WCFMonthServiceImpl is straightforward. In the request, we create a client to connect to the service, register to the loaded event, and fire it off:

public void RequestMonths()
{
    WCFMonthService.MonthServiceClient client = new SilverlightCommunication.WCFMonthService.MonthServiceClient();
    client.GetMonthsCompleted += new EventHandler<SilverlightCommunication.WCFMonthService.GetMonthsCompletedEventArgs>(client_GetMonthsCompleted);
    client.GetMonthsAsync();
}

And when the service comes back, we load our args and fire the loaded event:

void client_GetMonthsCompleted(object sender, SilverlightCommunication.WCFMonthService.GetMonthsCompletedEventArgs e)
{
    WCFMonthService.MonthServiceClient client = sender as WCFMonthService.MonthServiceClient;
    client.GetMonthsCompleted -= client_GetMonthsCompleted;
    if (MonthsLoaded != null)
    {
        MonthArgs args = new MonthArgs();
        foreach (string month in e.Result)
        {
            args.Months.Add(new Month { Name = month }); 
        }
        MonthsLoaded(this, args); 
    }
}

(If you're bothered by the way I call the loaded event, read my note at the end of the callback method).

Traditional SOAP/WCF calls definitely have the most overhead of the methods we'll cover (although the ability to define the service as binary certainly helps). Your best friend when troubleshooting services is a proxy or sniffer like Fiddler. This will tell you if the plugin is requesting a clientaccesspolicy.xml (I've included one as an example, and if you host this in the root, it should satisfy the request) but also allow you to inspect the traffic.

For this method, our post contains a formatted SOAP request:

POST /MonthService.svc HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Length: 135
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IMonthService/GetMonths"

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body><GetMonths xmlns="http://tempuri.org/" />
   </s:Body></s:Envelope>

And the response is in an XML envelope:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <GetMonthsResponse xmlns="http://tempuri.org/">
         <GetMonthsResult xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:string>Enero</a:string>
        <a:string>Febrero</a:string>
        <a:string>Marzo</a:string>
        <a:string>Abril</a:string>
        <a:string>Mayo</a:string>
        <a:string>Junio</a:string>
        <a:string>Julio</a:string>
        <a:string>Agosto</a:string>
        <a:string>Septiembre</a:string>
        <a:string>Octubre</a:string>
        <a:string>Noviembre</a:string>
        <a:string>Diciembre</a:string>
</GetMonthsResult></GetMonthsResponse></s:Body></s:Envelope>

Method Two: RESTful Service or Straight Web Stack

REST is a different type of service (Representational State Transfer). It uses the existing web (HTTP) protocol for communication, allowing "verbs" (you may be familiar with POST and GET, and REST adds more) and makes the assumption that a URL represents a certain "state." A URL might contain information about a product as /PRODUCT/1 and the expectation is that this URL always returns that product object in its current state. REST provides more flexibility than SOAP for the formatting of the response (it might be a string, a JSON object, a simple XML document, etc).

Many popular APIs like Twitter use the REST form of communication. ASP.NET provides support for these types of calls via the WebGet attribute. To simplify this example, however, I simply wired a simple handler that returns a list of months (in Italian, to distinguish them from the other methods). The handler code behind is very simple:

private const string MONTHS = "Gennaio,Febbraio,Marzo,Aprile,Maggio,Giugno,Luglio,Agosto,Settembre,Ottobre,Novembre,Dicembre";

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";
    context.Response.Write(MONTHS);
}

As you can see, it literally spits out a list of months.

On the Silverlight side, we move from the concept of a WCF client to the more generic WebClient. This allows us to download strings or other content from the web, as well as upload content. It even includes support for credentials. In my case, I implemented the GetMonths with a simple request to download the string from the handler. Also, note I have hard-coded the URL. You may want to change this if your application is not hosted at the root.

public void RequestMonths()
{
    WebClient client = new WebClient();
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    client.DownloadStringAsync(new Uri("http://localhost/MonthHandler.ashx", UriKind.Absolute));
}

Once the string has been loaded, it's very easy to parse out and load (note that again, I'm not diving into error handling here, although one of the benefits of using the WebClient is vastly superior/simpler error handling over the WCF client).

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    WebClient client = sender as WebClient;
    client.DownloadStringCompleted -= client_DownloadStringCompleted;
    string[] months = e.Result.Split(',');
    MonthArgs args = new MonthArgs();
    foreach (string month in months)
    {
        args.Months.Add(new Month { Name = month });
    }
    if (MonthsLoaded != null)
    {
        MonthsLoaded(this, args);
    }
}

As you can see, it becomes simple string manipulation. We could just as easily retrieve an XML document and parse it using LINQ if we wanted to.

The post for this is simple, as the entire request is coded into the URL:

GET /MonthHandler.ashx HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

The response? Event simpler ...

Gennaio,Febbraio,Marzo,Aprile,Maggio,Giugno,Luglio,Agosto,Settembre,Ottobre,Novembre,Dicembre

Method Three: Callback (via DOM Interaction)

This is probably the least known and used methods. Because Silverlight can interact with the host browser, it can also interact with traditional ASP.NET callbacks, postbacks, JQuery, and the AJAX framework. This method is useful when you have an existing application and you are integrating new Silverlight components. In one line of business application I was building, we used the existing callbacks to iterate fast proof of concepts and then slowly rebuilt the calls as services where we needed.

The first step is to implement ICallbackEventHandler, which Ido in the default page. When the callback is raised, Iignore any parameters and simply return a list of months in English. The important element of the code behind here is the Page.ClientScript.GetCallbackEventReference. This sets up the call so I know exactly how to execute the callback. A little known fact is that if you do not call this at least once (even if you discard the output), ASP.NET will not wire up a listener for the callback! It must be called in order to set that up.

In the page, there are two JavaScript functions to assist with the callback. They look like this:

// on the return from the callback, finds the control and injects the months
function callbackHandler(result,context) {
    var slControl = document.getElementById('silverlightControl');
    slControl.Content.SilverlightApp.LoadMonths(result); 
}

// just takes the callback reference and triggers the callback
function doCallback() {
    <%=CALLBACKREF%>;
}

The first method is the callback method that is referenced in the code-behind (Default.aspx.cs). It is called with the result (our months list) and the context (null). Note the call to get the Silverlight control itself (this is not the host DIV element, but the actual OBJECT tag). If you use the ASP.NET Control, you will grab this by the client id of the control. Note the syntax of "Content.SilverlightApp.LoadMonths(result)." We'll get to that in a minute.

The doCallback function is just a wrapper for the method we generated in the code behind. If you view the source, you'll see it generates like this:

function doCallback() {
   WebForm_DoCallback('__Page',null,callbackHandler,null,null,false);
}

Now let's jump into the Silverlight application and look at the CallbackMonthService implementation. The constructor wires up the class to be accessible in BLOCKED SCRIPT

public CallbackMonthService()
{
    HtmlPage.RegisterScriptableObject("SilverlightApp", this);
}

This is where the "SilverlightApp" in the JavaScript above came from.

When the RequestMonths method is called, it triggers the callback like this:

public void RequestMonths()
{
   HtmlPage.Window.Invoke("doCallback");
}

When the callback is completed, the JavaScript method will call back to the class and pass in the month list. To facilitate this, I provided a method labeled with the ScriptableMember attribute to make it callable from JavaScript. The method splits the string, loads the arguments, and then fires the loaded event.

[ScriptableMember]
public void LoadMonths(string monthList)
{
    string[] list = monthList.Split(',');

    MonthArgs args = new MonthArgs();

    foreach (string month in list)
    {
        args.Months.Add(new Month { Name = month });
    }

    if (MonthsLoaded != null)
    {
        MonthsLoaded(this, args); 
    }
}

For those of you new to programming, a good homework assignment would be to investigate the potential bug above. I want to call it out so I'm not accused of spreading bad coding habits, but doing it this way make help it stick. The way I raise the MonthsLoaded event is not the best practice, especially considering the multi-cast nature of the underlying delegate. If that doesn't make sense, do some research and it will help you to understand events more (and why I am always unregistering my events once they are fired).

The event was registered to by our view model, which will bind to the observable collection and show the months on the grid.

In the end, the request for this method is similar to a REST call, with a few parameters that the ASP.NET framework uses to track and route the request and response:

POST /default.aspx HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://localhost/
Content-Length: 141
Pragma: no-cache
Cache-Control: no-cache

__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTExOTc0MjQyMjVkZOSAEQGSb7mMBhudDS%2FpDmv5GtNs&__CALLBACKID=__Page&__CALLBACKPARAM=null

But the response is just as simple:

0|January,February,March,April,May,June,July,August,September,October,November,December

(The 0 and pipe format help route multiple responses)

Conclusion

There you have it: a simple demonstration of three methods for getting data into your Silverlight application. I haven't touched upon local communication, sockets, or other more advanced methods, but this should provide a simple shell/skeleton for further exploration. In the future we'll talk more about securing those services and doing some more advanced things with messages on the client and server.

Download the Code (44 Kb)

Jeremy Likness

OK, so we've been through quite a series of iterations and refactoring for something simple: triggering a story board animation based on an event somewhere else. We used dependency and attached properties, we used custom behaviors, and now we're going to do it completely "out of the box."

I figured this one would be easiest to show as a video, so this is the first one I've posted to my blog. I don't have good audio so I used the "notepad" technique. What I'm showing is how to take a storyboard and trigger it based on an event fired by something else, using only what comes built-in with Blend. There is no code-behind and in fact the only XAML I edit is for the list boxes (sorry, I know there's a data tab but I still code HTML in notepad).

Here it is:

Click to View Video

Jeremy Likness

For all of the Prism fans out there, a newer version has been released. You can download it here.

Jeremy Likness