Page view counter

December 2008 - Posts

Hypervideo – Getting Started

 

 

 


 

For those of you who want to get started with hypervideo and don't want to wait for the videos or the full tutorial, here is the first of a series of fast mini-tutorials.

The first step is to pick a video you'd like to use as your "source." The source will be the video you'll link from.

If you don't have it already, you'll need to download Encoder by going to the Expression Web Site and clicking on Encoder in the lower right hand corner as shown in the cut-down image below

MicrosoftExpression

3. Buy (or try) Encoder, and be sure to download Service Pack 1 and the Encoder SDK

GetEncoder

Once you are set up, you are ready to use Encoder to add markers to your video and to ask Encoder to emit a player for you that you will modify.

Importing The Video

 

Open Encoder and choose File->Import

EncoderImport

and navigate to the video you want to import.  It will appear in the Media content window of Encoder and you can watch it by pressing the play button.

VideoPlayingInEncoder

The area I marked A represents the imported video. On the control toolbar you can see the elapsed time (area B). Above that, in the area marked C is the "playhead."

MetaData

The right side of Encoder has four tabs:

  • Encode
  • Enhance
  • MetaData
  • Output

For now, we care only about the last two.  The Metadata tab offers the ability to name the output video (and add an enormous amount of metadata such as copyright, genre, etc.) and to add markers,

MetaDataTab

 

There are many ways to add markers, but one of the easiest is to move the playhead to the place in the video you want the marker, and then to press the Add button. 

Four editable fields are made available for each marker:

  • Time (Elapsed time into the video in thousandths of a second)
  • Value (any arbitrary value that will serve as a name for the marker)
  • Thumbnail (a boolean indicating whether or not a thumbnail should be created)
  • Keyframe (a boolean indicating whether or not a keyframe should be created)

MarkerDetail

The thumbnail is used when creating chapters (as for a DVD movie) to show an image indicating what is in that scene of the film.

Creating a keyframe instructs Encoder to put an IFrame at that location. The documentation notes that this can shorten seek time for the marker" but again is not relevant for the work we'll be doing.

For our purposes Thumbnail and Keyframe should be unchecked

What To Put In Value

Traditionally, the Value field is filled with some indication of what is happening in the video at that time location, though see my previous blog entry for a discussion of why that may or my not be desirable.

Once You've Added The Markers

Once you've added all the markers that you wish to add, and adjusted their exact timing to whatever level of precision you choose, you are ready to encode the video and to enlist Encoder in creating a player for you.

MarkersReadyToEncode

Creating The Player

Switch to the output panel, where you will pick a Silverlight 2 player and you want to click on the white dot (shown surrounded in red here)

OutputPanel

When you choose the Silverlight 2 Default player template an image of the player will appear.

EditControlInBlend

Clicking on the white dot and choosing Edit Copy in Expression Blend will open a dialog box asking you for a name for the template. Give it a name and click OK and Blend will open with a security warning. You can click Yes and Blend will fully open and inform you that you must build the project to work with it. Click Project->Build Solution and when it completes you should see the player in the art board and the Objects and Timeline will indicate that within the Layout Root is a single object: myPlayer.

Encoding the Video

Before you go any further, don't forget to return to Encoder and finish encoding the video! Make sure the output tab is active and examine the Media File Name and the Directory,

JobOutput

The default name for your new encoded video is created by appending the default extension (wmv) to the original file name. You can change either or both parts of this.  You can also pick the directory you'd like to place the encoded video into.  There are some checkboxes below that can be helpful as well.

Once you have this set as you like, click the Encode button in the lower left hand corner and your video will begin encoding, with a countdown clock telling you how much time remains. If you checked "Preview in Browser" when you finish a browser will open and your video will display (though there may be a short delay).

Files, Files, Who Has The Files?

At this point you have two sets of important files:

  • The encoded video and some helper files to look at it
  • The emitted player and the source code for modifying it

The encoded video should be in the directory you chose (in the example shown above, the files would be in c:\demo\HyperVideo Blog 1\VISTA64DT 12-30-2008 12.45.51 PM\ where VISTA64DT is the name of my machine and the rest of the name is a time stamp.

Inside that directory will be a copy of the .xap file for the emitted player, a .dat file that contains a great deal of information about the video and the markers, a default.html and the encoded wmv file. Double clicking on the html file will bring up your video in the emitted video player.

Where is the Player?

The player itself is in the default output location unless you took steps to put it elsewhere. On my machine that is C:\Users\Jesse\Documents\Expression\Expression Encoder\Templates

Under that directory I will find a directory with the name of the template, in this case, Silverlight 2 Blog Version inside of which is another Default.html and copy of the .xap file, but more important, is also a Source directory. In that directory is the complete source for the custom control player that I will want to modify.

Spec'ing the Player

The player that is emitted by encoder is a good start, but it encourages use of markers in exactly the wrong way for our purposes. We are not interested in chapters, we are interested in providing metadata and reacting to embedded markers as events. Thus, there is much we want to strip away: specifically everything circled in red in this next image:

PlayerSpec

You can see, however, why we wanted Encoder to create the player; it is far easier to start with this and remove what we don't want than to create all the functionality from scratch.

Working With The Project

If you open this project in Blend and Visual Studio (and I recommend opening it in both) there is a fleeting temptation to panic when you look in page.xaml:

<UserControl x:Class="MediaPlayerTemplate.Page"
    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:ExpressionPlayer="clr-namespace:ExpressionMediaPlayer;
          assembly=ExpressionPlayer"
    mc:Ignorable="d"
    Width="Auto" 
    Height="Auto">
    <Grid x:Name="LayoutRoot">
    <ExpressionPlayer:ExpressionPlayer
      Margin="0,0,0,0"
      x:Name="myPlayer" />
  </Grid>
</UserControl>

 

 

 

 

 

All that you have is a single, monolithic control. How are you going to modify that??

It's Just A Skinnable Custom Control

Great news!  What Encoder has provided to you is a skinnable custom control, exactly as described in these four videos:

What encoder has done is to create a custom class, ExpressionPlayer that derives from MediaPlayer.

public class ExpressionPlayer : MediaPlayer

Rather than providing ExpressionPlayer with a default look, they rely on MediaPlayer for that, but wonderfully, MediaPlayer's source is also included, and as you'd expect there is a Themes folder with a generic.xaml file that does contain the default appearance.

In addition, MediaPlayer.cs provides the attributes that constitute the Parts and States contract

(excerpt)

[TemplatePart(Name=MediaPlayer.StretchBox, Type=typeof(FrameworkElement))]
[TemplatePart(Name=MediaPlayer.VideoWindow, Type=typeof(FrameworkElement))]
[TemplatePart(Name=MediaPlayer.TextblockErrorMessage, Type = typeof(TextBlock))]
[TemplatePart(Name=MediaPlayer.ClosedCaptionBackground, Type = typeof(Rectangle))]

which makes skinning (templating) the Expression player far easier.

What We'll Do In the Next Installment

Having encoded the video and emitted a player, and having explored enough to see that we have the resources to template that player we've reached a good stopping point.

Next time we'll modify the player to strip it down and we'll teach it to respond to markers by placing the name of the marker just below the player. Once we can do that, we'll have established the fundamental architecture and we can begin to enhance the player to respond in more meaningful ways.

Previous:  Hypervideo- Continuing the Dialog      Next: Building a Hyper-Video Player: Phase I

 

 

 

 

 

HyperVideo Continuing the dialog

 


 

Ben wrote that he hopes I will dive deep into decoupling the type or name of the markers from the data-driven information, and I want to respond that this is an important part of decoupling the link from the response to that link, though I'm not sure it is totally required.

The case for unnamed Markers

The argument in favor starts with the observation that there is a natural tendency to think of the source video and the target (linked-to) video as a single unit.

For example, assume you are working with the video shown in the upper left corner in the figure below and you note that at this point the user is assumed to understand how to handle  events in a templated control, but may need more information. It is natural to assume that the hyper-video link would that issue, and would "of course" lead to a video (or blog post or article) to provide that background information.

SingleLink

It would be natural to name the marker placed here "ClickEventForTemplatedControl." The simple act of changing the name of the marker to  (e.g.,) Marker7 might free you in some ways to think about linking to lots of other supporting material as well.

Circular Error Probability (C.E.P.)

Weapons experts talk about Circular Error Probability, which Wikipedia describes as "an intuitive measure of a  weapon system's accuracy… defined as a circle, centered about the mean, whose boundary is expected to include 50% of the population within it.

 

A key difference between a hyper-link in hyper-text and a hyperlink in video is that in hypertext I can create a link with exact placement, down to a punctuation mark!  Video, by its nature, does not easily lend itself to such precision. Thus you are left with two options:

  1. You indicate to the user that there is more information, but leave some inevitable uncertainty (CEP) about what it is that you are linking from or

image

or 2. You add text to indicate precisely what the hyper-video link will provide.

image

There are advantages in the very imprecision of the first example that I'm not sure we've all had time to think about, let alone explore, but I intuit that this is an area rich in possibilities, both for creating infuriating and frustrating user experiences and, possibly, for creating wondrously flexible creative interfaces.

Videos and Blogs and Cabbages and Kings

I'm actively recording these videos but they'll take a while to post (especially because of the holidays), but that gives us all an opportunity to explore some of the ramifications before we settle into the details of how to implement.

Meanwhile, another special request: so far all the documentation I've found on modifying the player that encoder emits assumes that you will choose a Silverlight 1 version of the player and work in script. My example uses a Silverlight 2 player and work in C#. If you run across any examples or documentation of someone else doing that (modifying a Silverlight 2 player emitted from encoder) I'd love a link.  Thanks!

Enjoy your holidays and stay tuned, much to come.

 Previous: Hypervideo      Next: Hypervideo – Getting Started

HyperVideo

 

This posting will reintroduce the concept of Hyper-video, the subject of a series of forthcoming videos.

The concept of HyperVideo is most easily explained by a series of examples.

  • MugabeYou are watching the news and the anchor person says "Robert Mugabe, president of Zimbabwe, today announced…" you click on the question mark on the screen and are presented with a menu:
    1. Zimbabwe History (Web link)
    2. Zimbabwe Government and Politics (Article)
    3. President Mugabe Biography (Video)
    4. Go to Wikipedia/Zimbabwe
  • You are watching a video on how to use a Silverlight Toolkit control and you realize that you don't know how to install the Toolkit. You click on Help -- the video pauses and a second video opens that provides the background information you need.


  • You are watching a HR training video and the person in the video mentions investing in a 401K. The word 401K appears on the screen and when you click on it, the first video pauses and a second video begins detailing your retirement plan options. But here's the kicker:  the supplemental video you are seeing is quite different from the 401K video your manager would see. The system chooses which video to display based your management level and years of service.
What have you already seen about this? Please email to me:

  • Anything you've seen where the idea of Hypervide has been explored
  • Any documentation on modifying an Encoder-emitted video player using managed code
  •  

    Much to Explore

    Building hypervideo will cause us to consider a number of interesting aspects of Silverlight and related technologies.

    As a start, Markers Expression Encoder can simplify creating the "markers" in the video.

    The Media Element (or a control derived from the Media Element) will fire an event each time a marker is encountered. There are numerous traditional and non-traditional ways to respond to that event. EncoderOutput

    Encoder will also create a working player to get us started.

    At its heart, the player is a control or a set of controls that can be skinned to change its appearance and can be subclassed to change its behavior

    Interpretation of the markers can be decoupled from the type or name of the markers, and can be data driven based on information obtained (e.g.,) through a web service

    iStock_InjectionRedXSmall


    Note that for complete decoupling, markers can be injected into the video at run time, rather than permanently encoded into the video.

    Whither Hypervideo?

     

     

     

     

     

     

     

    I am reminded that the value of hypertext was not fully realized for quite a while after it was first introduced. (Wikipedia estimates that it was at least 20 years from invention to widespread use). It will be interesting to see if hypervideo turns out to have lasting value or is yet another technology in search of a need.

     

     


    More: Hypervideo – Continuing the Dialog

    Passing Parameters Into Silverlight Applications

    I was working on a chapter about the Application Model for our forthcoming book and reviewed the examples on passing parameters into Silverlight applications. I thought, "Hey! That would make a great video!"  And it does, but Tim already made one, which I highly recommend.

    Since it never hurts to review, I'm going to write this up quickly, fully acknowledging that this is 90% his work; so only read on if you haven't happened to catch his presentation of this material yet and this might be new to you (I have added a few new bits that I learned as I worked this through).

    What You're Trying To Accomplish

    The idea is this: you want to be able to create a Silverlight application that allows for passing in some information through the html or aspx page that will be integrated into the Silverlight application at run time. Remembering that Silverlight runs on the client, that information must be picked up just as the application begins to run inside its hosting html or aspx page. Here, briefly, is how you can do that:

    If you are hosting in an HTML page, you'll add a new parameter to the object tag 

    ObjectTag

    You'll find there are already a number of parameters there, you'll add one whose name is initParams and whose value is any number of name/value pairs that you'd like to pass as parameters to your program. For example,

    <object data="data:application/x-silverlight-2," 
       type="application/x-silverlight-2" 
       width="100%" height="100%">
           <param 
           name="initParams" 
           value="programmer=Jesse Liberty,
           blog=http://silverlight.net/blogs/jesseliberty" />

    The name/value pairs are comma separated and you may have as many as you like,

    <object data="data:application/x-silverlight-2," 
       type="application/x-silverlight-2" 
       width="100%" height="100%">
          <param 
          name="initParams" 
          value="programmer=Jesse Liberty,
          blog=http://silverlight.net/blogs/jesseliberty",
          title=silverlight geek,
          codeRippedOffFrom=tim heuer,
          conceptDemonstrated=initializing parameters />

     

    In this second example, I'm passing in five initializing parameters. The keys are

    • programmer
    • blog
    • title
    • codeRippedOffFrom
    • conceptDemonstrated

    and their respective values are

    You can see that this lends itself readily to being placed in a dictionary, and that is exactly what will happen, they are placed into an IDictionary<string><string> available to you from the Application_Startup method in App.xaml.cs (but only there, and thus only when your application is starting up).  You therefore want to grab these values and put them somewhere you can get to them later, when you'll need them.

    Stashing Away The Values

    The canonical solution is to place them into the global resources dictionary, thus

    private void Application_Startup( 
       object sender, StartupEventArgs e )
    {
      if ( e.InitParams != null )
      {
        foreach ( var item in e.InitParams )
        {
          this.Resources.Add( item.Key, item.Value );
        }
      }
          
      this.RootVisual = new Page();
    }

     

    Using the parameters

    Once the parameters are safely tucked away we can think about using them in the running program.  I wrote a small example program that has a TextBlock for a title, a ListBox to display some data and then two rows that display information if that information is passed in through parameters.

    The first row will display the programmer's name if there is a parameter whose key is programmer, and the second will provide a link to the programmer's blog if there is a parameter whose key is blog.   Here is the Xaml that sets that up:

    <TextBlock
      x:Name="Programmer"
      Grid.Row="1" Grid.Column="1"
      FontSize="14"
      Margin="10,0,0,0" />
    <HyperlinkButton
      x:Name="BlogLink"
      Grid.Row="2" Grid.Column="1"
      FontSize="14"
      Margin="10,0,0,0" />
    <TextBlock
      x:Name="BlogText"
      Grid.Row="2"
      Grid.Column="1"
      FontSize="14"
      Margin="10,0,0,0" />

    Notice that both the HyperlinkButton and the TextBlock occupy the same row and column. The first thing we do in the load handler is to make them both invisible,

     void Page_Loaded( object sender, RoutedEventArgs e )
     {
       BlogText.Visibility = Visibility.Collapsed;
       BlogLink.Visibility = Visibility.Collapsed;

    We'll check the resources for the link and if we find one, we'll make the link visible; if not, we make the textblock visible and put a message there that there is no link.

    Retrieving Values from the Resources Collection

    Following Tim's approach, I've factored out the job of getting the value out of the Resources given a key, checking first to ensure that the key exists in the resources collection and returning an empty string otherwise,

    private string GetParam( string p )
    {
      if ( App.Current.Resources[p] != null )
        return App.Current.Resources[p].ToString();
      else
        return string.Empty;
    }
    Note: You might expect to use the TryGetValue method on the Resources collection, which does exactly this work for you, but the Silverlight documentation notes that this is not intended for use in user code with the ResourcesDictionary class.

    With our GetParam method in place, we can try to get the value for the Programmer and the address for the blog, placing them in local (temporary) variables,

    void Page_Loaded( object sender, RoutedEventArgs e )
    {
      BlogText.Visibility = Visibility.Collapsed;
      BlogLink.Visibility = Visibility.Collapsed;
    
      string programmer = GetParam( "programmer" );
      string blog = GetParam( "blog" );
    
      if ( programmer.Length > 0 )
        Programmer.Text = "Programmer: " + programmer;
      else
        Programmer.Text = "Programmer unknown";

    The next step is to test whether we received a legitimate blog address. If so, we want to make the HyperTextButton visible and set its text and its URI, otherwise we'll make the TextBlock visible and set its text to some sort of error message,

    if ( blog.Length > 0 )
    {
      BlogLink.Content = "Programmer's Blog";
      BlogLink.NavigateUri = new System.Uri( blog );
      BlogLink.Visibility = Visibility.Visible;
    }
    else
    {
      BlogText.Text = "No blog provided";
      BlogText.Visibility = Visibility.Visible;
    }

    The result is very gratifying, the parameters are integrated into the running Silverlight program seamlessly,

    ParametersCompleted

    A very nice, and easily overlooked feature. Again, for complete coverage, I recommend Tim's video and the complete source code for the example shown today is available here.

    Application Set: Templates & Custom Controls

    When we started creating How Do I videos, the idea was to have stand alone videos that do not depend on one another. That is still the ideal, though from time to time we do have two or three part videos because the material is just too complex to cover in the 15-20 minutes we like to set as the maximum for a video.

    I've been noodling on the idea of Application Sets, the rather odd concept of having your stand-alone video and building on it too. 

    An Application Set in its ideal form, can be decomposed into two or more stand alone Modules. You can view either module without the other, but together they add value to each other.

    Each Module in turn consists of two or more Units (where a unit can be a blog entry, a tutorial or a video). Again, each unit can stand alone, but together they add value to one another.

    The idea is to build the Modules organically – that is, they arise as the units are created, without a plan, in response to the natural development of ideas.

    Here are two closely related modules that have evolved into a single Application Set:

    Module I – Styles and Templates

    Module II – Skinnable Custom Controls

    This is not to suggest that the set is complete, but rather that there is now enough to lend some coherence among the parts; that in addition to each of these modules and units having some value on its own (I hope), the module as a whole should have a value and in turn the set of the two modules has  value as well.

    Eventually, if this idea makes sense, we'll find a way to package the entire set together for easy distribution, complete with up to date code, as a unit.

    Enjoy.

    Bubbles – 1 Chart – three Axes

     

    In this follow up to yesterday's blog post about the Bubbles Chart available from the December Release of the Silverlight Toolkit, I'd like to explore the unique advantages the bubbles chart provides for finding outliers in many real world situations.

    The scenario I'm contriving is this: I'd like to examine two vital sets of (fictional) information at once

    • How many blog blog posts and videos have we created on each of 8 important topics
    • On average, how interested are our members in each of these topics.

    I could create two charts and compare them side by side, but a bubbles chart instantly identifies where I have problems and where I'm on track…

    ThreeWayFullView

    In this chart, the larger the bubble the greater the average user interest, on a scale of 0 to 100.  The Y axis (on the left side) is the number of blog entries and videos on the topic (the negative numbers are an artifact of accommodating a large bubble that falls below zero), the X axis lists the 9 topics (at the moment, the bubbles chart can only place integers and dates, so my Topics class uses an ID and a lookup, explained below. Clicking on a bubble causes its information to be displayed above.

    The bubble I've clicked on in the image above is number 5 (Skinning) and it is indicating we've got it about right, the interest level is 60 out of 100, and we've done 125 posts which is tracking appropriately.  In the cropped image below I focus on two outliers,

    ThreeWayBubbles

    The tiny bubble up at 350 indicates that we have a topic of little interest that we are spending too much time on, and the giant bubble down around 0 (actually indicating 5 posts) is a sure sign we have a high interest topic that we're ignoring. An equal sized bubble up and to the right shows a high interest topic we are covering well.

    Key here is that at a glance we've identified two problems that are easily missed without this chart, and easily solved with this information.

    How It Works

     

     

    The implementation is very much as you saw yesterday. To get to the heart of it, I created a single page version that has only  the following files:

    • Page.xaml
    • Page.xaml.cs
    • App.xaml
    • App.xaml.cs
    • BlogTopic.cs

    The App.xaml files. Page.Xaml is posted, here is an excerpt that illustrates the important points…

      <Grid
        x:Name="Layout"
        Background="White">
        <Grid.RowDefinitions>
          //….
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
           //….
       </Grid.ColumnDefinitions>
        <Border  //….  />
        <TextBlock
          x:Name="Message" //… />
        <charting:Chart
          x:Name="DrillDownChart"
          BorderBrush="Gray"
          Margin="1"
          Grid.Row="1"
          Grid.ColumnSpan="3">
          <charting:Chart.Series>
            <charting:BubbleSeries
              Title="."
             IndependentValueBinding="{Binding TopicID}"
              DependentValueBinding="{Binding NumberOfPosts}"
              SizeValueBinding="{Binding AverageRating}" />

          </charting:Chart.Series>
        </charting:Chart>
      </Grid>
    </UserControl>

    The three lines that matter are the binding of the Independent and Dependent values and the SizeValue. These are bound to properties of the BlogTopic class which, as you've seen with other classes, both defines its members and defines a static method to generate the data we'll need.

    In this case, since I need to provide integers for the IndependentValueBinding, I provide a TopicID as an integer, and a static Dictionary that maps these integers to strings (e.g., TopicID 2 = Web Services.  The complete listing for BlogTopic.cs  is posted, here is an excerpt,

    namespace Bubbles3D
    {
      public class BlogTopic
      {
       public static Dictionary<int, string> Topics =
              new Dictionary<int, string>();

        public int TopicID { get; set; }
        public int NumberOfPosts { get; set; }
        public double AverageRating { get; set; }


        public static List<BlogTopic> CreateData()
        {
          Topics.Add( 1, "Toolkit" );
          Topics.Add( 2, "Web Services" );
           //….

          List<BlogTopic> BlogTopics = new List<BlogTopic>();

          BlogTopics.Add(
            new BlogTopic() {
                  TopicID = 1,
                NumberOfPosts = 250,
                AverageRating = 65 } );
                 //….
          return BlogTopics;
        }

    Finally, the only remaining code is in the Page.xaml.cs where the ItemSource must be attached to the bubble series and the Selection changed event must be handled.  Here is that code in full,

    using System.Windows.Controls;
    using System.Collections.Generic;
    using System.Windows;
    
    using Microsoft.Windows.Controls.DataVisualization.Charting;
    namespace Bubbles3D
    {
      public partial class Page : UserControl
      {
        private List<BlogTopic> blogTopics;
        public Page()
        {
          InitializeComponent();
          Loaded += 
              new System.Windows.RoutedEventHandler( Page_Loaded );
        }
    
        void Page_Loaded( 
              object sender, System.Windows.RoutedEventArgs e )
        {
          BubbleSeries bSeries = 
                 DrillDownChart.Series[0] as BubbleSeries;
          blogTopics = BlogTopic.CreateData();
          bSeries.ItemsSource = blogTopics;
          bSeries.IsSelectionEnabled = true;
          bSeries.SelectionChanged += 
               new SelectionChangedEventHandler( bSeries_SelectionChanged );
          Message.Text = 
              "Larger bubbles are more popular, higher bubbles are are topics with more articles";
        }
    
        void bSeries_SelectionChanged( 
          object sender, SelectionChangedEventArgs e )
        {
          if ( e.AddedItems.Count > 0 )
          {
            BlogTopic blogTopic = e.AddedItems[0] as BlogTopic;
            Layout.DataContext = blogTopic;
            Message.Text = blogTopic.NumberOfPosts.ToString() + 
                 " posts on " + 
                  BlogTopic.Topics[blogTopic.TopicID] + 
                  " with an average interest of  " + 
                  blogTopic.AverageRating.ToString() + 
                  " on a scale of 0 to 100";
          }
        }
      }
    }
     
    Source: Bubbles3D.zip
    Posted by jesseliberty | 13 comment(s)
    Filed under: ,

    Bubble chart

     

    This is the first of a mutli-part entry on the Bubble Chart from the Silverlight Toolkit.  I became interested in this chart when I was working on my soon-to-be-released videos on the PieChart and the Column Charts, which share a common idiom and form.

     
    <!-- pseudo chart layout -->
    <charting:Chart x:Name="<name>" BorderBrush="<color>" Margin="<#>" Grid.Row="<#>" Grid.ColumnSpan="<#>"> <charting:[PieSeries | ColumnSeries | BubbleSeries] IndependentValueBinding="{Binding Path=<property>}" DependentValueBinding="{Binding Path=<property>}" /> </charting:Chart>

    For a pie chart whose name is DrillDown , if you want your margin to be 1 and you want to place it in row 1 of the grid with a column span of 3, and if you have a data object you will bind to that has properties Letter and Count, your Xaml will look like this (note the substitutions for the values in angle brackets)

    <charting:Chart x:Name="DrillDownChart"
                    BorderBrush="Gray"
                    Margin="1"
                    Grid.Row="1"
                    Grid.ColumnSpan="3">
      <charting:PieSeries IndependentValueBinding="{Binding Path=Letter}"
                          DependentValueBinding="{Binding Path=Count}" />
    </charting:Chart>
    

     

    Creating the Column Chart just substitutes a ColumnSeries for a PieSeries,

    <charting:Chart x:Name="DrillDownChart"
                    BorderBrush="Gray"
                    Margin="1"
                    Grid.Row="1"
                    Grid.ColumnSpan="3">
      <charting:ColumnSeries IndependentValueBinding="{Binding Path=Letter}"
                             DependentValueBinding="{Binding Path=Count}" />
    </charting:Chart>
    

     

    Easy as, er, pie.

    Who took my ItemSource?

    The code behind is a great place to put the itemsource, which can be a collection of any object that has the two properties Letter and Count. (For the video I used the same set of words that I generate for the other controls, and created a dopey useful little class that counts how many words begin with each letter of the alphabet)

    The key code in wiring this up looks like this:

    PieSeries pieSlice = DrillDownChart.Series[0] as PieSeries;
    pieSlice.ItemsSource = frequencyCounters;
    

    where frequencyCounters is defined as

    private List<FrequencyCounter> frequencyCounters;
    and FrequencyCounter itself is defined (in part) as
     public class FrequencyCounter
     {
       public int Count { get; set; }
       public char Letter { get; set; }

    There is also a static method to do the counting, but we can ignore that for now.

    [Don't get too caught up in these details, they're all available in the coming video and in the code that comes with it. The essential point is that you can create a business class that has the two properties that your chart will use for input. You can provide a a collection of those business objects as the the source for the chart and bind it dynamically while declaring the chart in Xaml. ]
    
    

    If you feed this collection to the pie chart, zap (xap?)  instant analysis of how many words begin with each letter (essential for quantitative analysis of meaningless information).

    PieChart

    Swap in the column chart and the same information now shows the letters distributed in columns.

    Columns

     

    The Bubbles Chart

    What caught my attention  when I was building these examples, however, was the Bubbles chart.  At first glance, it seemed to follow the same pattern,

     <charting:Chart.Series> 
      <charting:BubbleSeries Title="!"
        IndependentValueBinding="{Binding Path=ASCII}"
        DependentValueBinding="{Binding Path=Count}" 
        SizeValueBinding="{Binding Path=Count}" />
      </charting:Chart.Series>
    </charting:Chart>

    But wait! Note that there are now three values!  That third sets the size of the bubble, and in the examples shown on the Toolkit site it is set to the same binding as the  dependent value , so that is what I've done tonight (it's late, I'm tired, and let's start easy).

    Bubbles

    It makes for a very interesting chart, where the size of the bubble represents the size of the dependent value (in this case the count) and has a lot of appeal for  those of us who like this kind of representation in cloud tagging,

    CloudTagging

    But What About A Third Axis Of Information?

    The obvious question, though,  is whether this doesn't also offer the opportunity to represent a third piece of information. For example, might we not use the x axis to represent the Tag, and the Y axis to represent the number of articles on the tag, and the size of the bubble to represent the average length of the article? Or perhaps the size of the bubble could represent the average rating articles on that tag.  That latter approach would give the user a  pretty good idea at a glance if a blog was writing about what people care about. Large bubbles high up in the chart would mean a very responsive blog (lots of articles on popular topics).  Once could begin to talk about blogs that float and blogs that sink.

    I will pursue this tomorrow. This is exciting. 

     

    Posted by jesseliberty | 10 comment(s)
    Filed under: ,

    Podcast interview on animation

    I'm pleased to announce that my Sparkling Client interview on Animation is now posted. In honor of that interview, I've created a button with in-state animation that will take you to the podcast, presented here through Silverlight Streaming, and analyzed, briefly, below…

    There are two aspects to the button above.

    Create the Templated Button

    First, creating the button was a quick job of templating a normal button, as explained in these two videos (currently available) and parts 3 and 4, to be posted soon.

    SkinnableCustomControlsPart1       SkinnableCustomControlsPart2 
                          (click on image to go to video)

     

    My quick steps were to open a new Blend project, add a button, make it a template, add simple visual behavior for mouse over, mouse pressed etc., and then add repeat forever animation on not having the focus (annoying, eh?).  I then brought it into visual studio, cleaned up the Xaml a bit, went to add the event handler and realized: oops! wanted that to be a hyperlinkButton and so changed it in the resource definition (fortunately they are very similar) and shazam! 

    Streaming

    The second aspect is streaming. (you can tell by the big word streaming just above).  Creating an application and displaying it live in the blog is absurdly easy.  The steps are:

    1. Make your application work
    2. Create an account on Microsoft Silverlight Streaming By Windows Live where you will find not only extensive documentation (see the SDK) but also links to the Admin Site where you can get a free account with 10MB of storage free during the Beta period. 
    3. Upload the zap file and let it create a manifest for you (okay, the right way is to upload a zip with the manifest) and it will offer you the iframe code…

    AddIframe

    There is a second, longer procedure, but this works really well for a blog. (I cut down the height and width for the button above).

    That's it. Instant working button. 

    Sorting a List<t> (What was I thinking??)

    This entry updated after a night's sleep and the return of my cerebral cortex.

    In one of my earlier entries you'll find something approximating this bit of nonsense…

    public string DoSort(List<string> words)
    {
    List<string> temp = words.Sort(); // No, but thanks for playing.
    return temp
    }

    Replace with

    words.Sort();   // sorts list in place.

     

    iStock_BoyWithBrainXSmall

    For those of you who commented on my earlier attempt to explain how this would compile I can only tell you that I carefully tested it, but must have been sleep walking. I have a section in both of my books on C# that clearly says I was wrong, I have no idea what brain malfunction caused this, but I find that when this kind of thing happens the best thing is to take a nice long bath and throw the radio in.

     

     

     

    -j

    Posted by jesseliberty | 5 comment(s)
    Filed under:

    New Blog Features

     

    To meet the needs of various readers, some of whom would like this blog to be totally focused on Silverlight features, and some who value a broader perspective, I'm making a few changes.

    [1] All entries will have one  the tags listed in the table below,  starting immediately. This should help readers filter and find what they are looking for.

    [2] I've broken out all discussion of Mac programming to a separate page accessible at any time from the sidebar.  There will be a brief entry tagged Mac when that page is updated.

    [3] I've started a page on IronRuby and it is my intention to learn IronRuby and, eventually to begin providing IronRuby samples for many of my videos and tutorials. This too will be accessible from the sidebar.

    [4] Consolidation and Focus: all non-Silverlight/programming related material has been moved off of this blog and to the latest incarnation of my private blog. All technical information has been consolidated from all other blogs to this one. 

    [5] All Twitter accounts have been closed except  this one (@jesseliberty) which I am using, among other things, as a mini-blog and for general tweets. [It is far less structured that this site; caveat emptor.] Its use will wax and wane, but I do intend to use it a good bit more.

     

    Tag Definition
    Silverlight Information about the language, programming, etc.     
    Mini-Tutorial Extended discussion on a Silverlight topic
    Announcement Information of general interest to the community
    Blog Information about this blog
    Perspective My perspective on a technical issue
    BlogUpdate Updating a previous entry
    IronRuby Announcement that the IronRuby page updated
    Mac Announcement that the Mac Programming page updated
    Event Announcement of an upcoming event
    Book Announcement of a forthcoming book (or related)
    Video Announcement of release of a video
    Tutorial Announcement of release of a video
    Interview Announcement of an interview or podcast

    I expect that while a majority of the entries may be tagged with one of the bottom 11, the vast majority of the words written will be tagged with the top 2. It will be interesting to track.

    Thanks.

     

    -j

    Posted by jesseliberty | with no comments

    First two Silverlight Toolkit videos posted

    I'm very pleased to say that my first two Silverlight Toolkit videos are now available.

    SLToolkitIntro

    The first is a gentle introduction to the Silverlight Toolkit, how to get it, what it's for, how to set it up, and so forth.

    It is only a little over 8 minutes (had I thought of it, I'd have added 17 seconds in homage to one of my favorite directors) and there is no code – it is just a road map to get you started.

     ToolkitAutoCompleteBox

    The second video begins the series proper with the AutoCompleteBox control.

    The video begins by showing, very briefly, the multi-page application that will be used throughout the series to obtain the data needed by many of the controls as explained here.

    The bulk of the video explains how the auto-complete box works, and the code is available in both C# and VB.

    Try It Out! (It doesn't quite fit, but this will give you a sense of what we build in the 2nd video...

     

     To try it, click on load data.  When you switch to the load data page, click on Load Words. Once the words are loaded click on Return To First Page (in the lower right). Back here on the first page notice that it now tells you that it is holding 492 words and now the first button is AutoCompleteBox and it is enabled. Click that and start typing in the text box. You should, after the second letter, see choices pop up. Whatever you choose will be passed back here when you click Return.

    Posted by jesseliberty | 4 comment(s)
    Filed under:

    A home for Toolkit Video Examples

    I eagerly agreed to create two videos each week reviewing the Silverlight Toolkit controls. My goal was to provide dead-simple examples both in my blog and in the videos so that anyone can come along and see how to use these controls with no muss., no fuss.  I’m quoted in Wikipeda as having said “Write like you won’t be in the room when what you’ve written is read, because you won’t”  I’m not sure I said it, and I’m not sure it is original, but I certainly agree with it.

    I certainly believe that example code is not  the place to show off cool coding technique, nor is it the place for lots of indirection or irrelevant extra bits that get in the way of understanding the point being explained. This was hammered home to me nearly twenty years ago when I was using an ISAM database library to build a database engine in C for PBS.  The product was great, but the documentation was written with very complex examples illustrating what turned out to be very simple API calls (I suspect they just lifted the examples right out of the program).   Once stripped down it was all very easy to use but at first glance it was a nightmare of indirection.

    Siren Song of A Unified Presentation

    It came as something as a shock to me, therefore, when I succumbed to the temptation to put all my Toolkit examples into a single multi-page application.

    ToolExplorationFirstPage

    After all, I certainly could create each video totally on its own, and have independently get the data it needs to populate the control. But there is something so compelling about getting the data once, and then using that data as the source for all the controls that it was just irresistible. 

    It turns out that by providing a starter program, the user who wants to concentrate only on the toolkit control really doesn’t need to know how the data retrieval or the page switching works. Just create a new page for the example, wire it into the provided starter kit and ignore the details. As you view more videos, more buttons light up, and you can view them in any order you like.

    iStock_headwithgearsNB: This entire exercise in explaining my decision is, I’m told, somewhat counter-cultural. The proper Microsoft approach is to make a decision, preferably the right one, and then FIPO!  It is, I suspect, a personal imperative, that I write about why I’ve chosen a particular approach, and show how one could argue for a different decision. (Is this intellectual honesty or simply indecisive perseveration?)

    I will have to start tagging these as Ramblings so those of you who write in to say “stick to Silverlight and keep all the rest silent” won’t have to create a macro, and those of you who like the peek inside my brain can read on.

    The Architecture of the Containing Application

    My other excuse, rationalization, justification, explanation for using this approach was that it builds on the architecture explained in my latest tutorial and it is always nice to see an architectural approach put to work.

    So, while getting rid of all this and making each example stand on its own would be simpler, this turned out to be so elegant  that I can’t quite bring myself to kill it.

    [ Larry Weiss, who was at one time something of a mentor and who built the most successful ATM machines in the world, said, in a most memorable phrase, “the secret of success in UI design is a readiness to kill your own children.” – by which he meant (thank goodness) a readiness to kill those designs you created and most cherish. ]

    How It Works

    When you download the source with any of the toolkit videos you will receive two zip files:

    • ToolkitExplorationStarter
    • fooCompleted

    where foo is the name of the control being explored.

    The latter is the complete source code for the example as shown in the video, the former is the the complete structure into which each page will be placed.  (Of course each of these will be available in either VB or C#)

    The starter program consists of the following files

    • App.xaml and App.xaml.cs
    • Page.xaml and Page.xaml.cs
    • PageSwitcher.xaml and PageSwitcher.xaml.cs
    • LoadWords.xaml and LoadWords.xxaml.cs
    • ISwitchable.cs
    • Switcher.cs

    as well as the usual references folder, Properties folder and a project for Toolkit Exploration.Web.   You’ll want to open the references to ensure that the reference to Microsoft.Windows.Controls.dll is pointing to the right file on our machine – or change it to do so.

    The changes in App.xaml.cs and the use and details of all of the files other than LoadWords and LoadWords.xaml.cs are explained in detail in the tutorial, and so I won’t recapitulate that here except to say that it allows you to switch from one page to another and to pass in data. The page that is called implements ISwitchable, and the data is passed via the required UtilizeState method,

       1: public void UtilizeState( object state )
       2: {
       3:   if ( state != null )
       4:   {
       5:     sortedWords = state as List<string>;
       6:     myAutoComplete.ItemsSource = sortedWords;
       7:   }
       8: }

    Adding a Control to the Structure

    Each time we want to examine a new control, we’ll just create a new page an plug it into the structure with three steps:

    1. Make the new page (e.g., AutoCompleteBox.xaml and AutoCompleteBox.xaml.cs) and be sure the class implements ISwitchable,

    public partial class AutoCompleteBoxPage : UserControl, ISwitchable

    2. Implement the (required) UtilizeState as shown above (the snippet above actually is from AuutoCompleteBox

    3. Enable the button in Page.xaml.cs and set its event handler

    Page.Page():

    AutoComplete.Click += new System.Windows.RoutedEventHandler( AutoComplete_Click );

    Page.AutoComplete_Click:

       1: void AutoComplete_Click( object sender, System.Windows.RoutedEventArgs e )
       2: {
       3:   Switcher.Switch( new AutoCompleteBoxPage(), words );
       4: }

     

    Page.UtilizeState:

    public void UtilizeState( object state )
       {
         AutoComplete.IsEnabled = true;

    That’s it; the new test page is added.  When you click on the AutoCompleteBox button the new page is shown to demonstrate the control, utilizing the same data (the list of words) that the other controls use,

    AutoComplete

    The code for the AutoCompleteBox sample page is simplified by the design as the data is passed in,

       1: public void UtilizeState( object state )
       2: {
       3:   myAutoComplete.ItemsSource = state as List<string>; 
       4: }

    and thus becomes a non-issue – you still see how it is assigned but don’t have to worry for each control about how to obtain the data.

    I look forward to seeing how this all works out.

    -j

    Posted by jesseliberty | 6 comment(s)
    Filed under: ,

    Creating Skinnable Custom Controls - Video

    SkinnableCustomControlsPart2

     

     

    I have completed the four part video series Creating Skinnable Customer Controls and I'm pleased to say they are rolling out onto the site. Part 2 is now available (click on the image). Parts 3 and 4 should post very soon.

     

     

     

    Related information:

    Thanks!

    Tutorial on multi-page applications posted

    Very pleased to announce that my tutorial on Multi-page applications is now available in both C# and VB and in both HTML and in PDF format.  

    tutorial8

     

    Set Theory

    It is my hope that this approach to multi-page applications will prove useful, though of course it is not the only way to approach this problem. That said, I will be leveraging this solution in a series of forthcoming videos and blog posts about the Silverlight Toolkit.

    This brings up the concept of stand alone units (blog posts, videos, etc.) that also live in Modules, and then in Sets – an idea that I've been toying with for about two months.

    This idea may have merit or not, but The Toolkit seems to offer a good opportunity to start down the path.  The concept of Sets is to have three tiers at which developers can access information:

    1. Individual Units that stand alone

    2. Modules that are groups of Units but that are orthogonal to one another

    3. Sets that tie some number of modules together into a coherent and comprehensive whole.

    The original premise behind How Do I videos was that the developer could dip into a video without needing to have seen any other video; we've stretched this into pairs and even small groups of videos where needed, but we still believe in the original idea.

    Modules provide an opportunity to have the best of both: individual stand alone units and then groups of units where the soul is greater than the hum of its parts (see Douglas Hofstadter – The Mind's I; only he could combine a pair of puns with a Spoonerism) . 

    Once two or more modules have been created, it is possible to imagine creating a set: a group of modules that together provide comprehensive coverage of a topic of interest; in this case, complete coverage of the Toolkit.

    Key to this idea is that each unit stands on its own, with the module providing the connections between them. Similarly, each module is independent of all other modules, with the Set providing the overarching theme.

    Stay tuned, as I build more units on the Toolkit, I'll create a map (or Table of Contents) and when it makes sense, I'll cluster them into Modules.

    Thanks.

    -j

    The Wrap Panel

     

    The Silverlight Toolkit includes a wrap panel that allows you to add elements to it and will automatically wrap those elements either horizontally or vertically as required to fit them within the size of the panel. All you need to play with WrapPanel is a source of numerous controls – and the easiest way to do that is to generate them programmatically.

    To do this, I'll borrow the code I used to create words in this blog entry on obtaining a lot of words, and put it to use here.   To keep the example for this blog simple, I've stripped this down, and added all the words into the source code, eliminating the code surrounding acquiring the words themselves. 

    The WrapPanel does not wrap words, however, it wraps controls.  Thus, we'll use the words as source for the creation of TextBlock controls and it is the TextBlocks that we'll wrap. But to show that we can also wrap other controls (and to take a quick tangent into the programmatic creation of the source property for images) we'll add one image.

    Here's how we do it.

    First, we'll lay out our page in Blend.

    WrapPanel

    You can see that we have two rows and two columns. The picture is cropped so it is a bit difficult to see the true proportions, but the top:bottom is approximately 2:7 and left:right is approximately 1:9. 

    The Go button gets the words and puts them into the word display panel much as in the previous columns, and then it calls PopulateWrapPChildren, which is the method we're interested in. Here's the result:

    WrapPanelWorkingHorizontal

    Clicking the Veridical Radio Button causes the controls to be reorganized within the pattern to wrap vertically rather than horizontally

    WrapPanelWorkingVert

    Implementation

    We implement this by iterating through all the words in the collection and creating a new TextBlock for each, adding each newly created TextBlock to the WrapPanel. 

     

    foreach ( string word in words )
    {
      WrapP.Children.Add ( new TextBlock 
         { Text = word, Margin = new Thickness (3) } );

    To make this just a tiny bit more interesting, I've added a counter, and when we've added the 10th TextBlock, I then add an Image control.  The image control needs its source set, which is trivial to do in Xaml but somewhat more complex in C#. I'll set the source to a jpeg on the Silverlight site, which can be done in a single line of code (if you have C programmer roots),

    WrapP.Children.Add( new Image() {  Source = new System.Windows.Media.Imaging.BitmapImage(
      new System.Uri("http://silverlight.net/Themes/silverlight/images/learn/tutorial-icons-controls.jpg")),  
      Stretch = System.Windows.Media.Stretch.None} );

    but which is far easier to understand if implemented in three easy-to-debug statements, using interim variables,

    System.Uri theUri = 
       new System.Uri( "http://silverlight.net/Themes/silverlight/images/learn/tutorial-icons-controls.jpg" );
    
    System.Windows.Media.Imaging.BitmapImage bmi = 
      new System.Windows.Media.Imaging.BitmapImage( theUri );
    
    WrapP.Children.Add( 
       new Image 
          { 
             Source = bmi, 
             Stretch = System.Windows.Media.Stretch.None 
          } );
    Here is the source: WrapPanelDemo.zip
     
     

                                                                  Next: Silverlight Toolkit WrapPanel


    This work is licensed under a Creative Commons Attribution By license.
    Posted by jesseliberty | 10 comment(s)
    Filed under: ,
    Next