Help Wanted

I have some ideas about improving this blog that will require going through past messages and adding forward/backward references and FAQ indicators and more.  If you are willing to work for “recognition” and eternal gratitude, please send email to jliberty@microsoft.com  with Blog Slog in the subject line!  Thanks.

Wow! What a response!  Thank you all; I have so many volunteers I hardly know what to do.  Can’t thank you all enough.

 

-jesse

Silverlight

Posted in z Silverlight Archives | Comments Off on Help Wanted

Drag and Drop with Managed Code

 

The last time I looked at Drag and Drop was with Silverlight version 1 and now seemed like a good time to see how one might accomplish this seemingly straight forward task with managed code.

The experience was interesting. Once I had it working, it was hard to explain why it had been difficult, though it did seem that the documentation took you right up to what you needed to know and then stopped short. I’m not certain that is true, but I know I struggled longer than I expected to.  In any case, now that it is working, it is easy to demonstrate.

This blog entry will make short work of it. To keep things simple, we’ll just draw a circle and a square and drag them around the surface of the larger canvas (we’ll use canvas because it uses absolute positioning which makes positioning the shape much easier). I’ve added color to the canvas so you can see where its boundaries are.

DragAndDropRunning
(Composite image of dragging circle)

  
The Xaml file is very simple,

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="DragDrop.Page"
Width="800"
Height="600"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<Canvas Background="AntiqueWhite">
<Ellipse
x:Name="Circle"
Height="150"
Width="150"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="#FFFFFF00"
Stroke="#FF000000"
Canvas.Left="10"
Canvas.Top="25" />

<Rectangle
x:Name="Square"
Height="100"
Width="100"
Canvas.Left="200"
Canvas.Top="50"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="Red"
Stroke="Black"
StrokeThickness="1"
Opacity="0.75" />
</Canvas>
</UserControl>

The Supporting Code

All of the code for this example is in Page.xaml.cs.  We want to implement three event handlers for each shape:

  1. MouseLeftButtonDown – the user has started to drag
  2. MouseMove – the user is dragging
  3. MouseLeftButtonUp – the user has stopped dragging

The key to understanding how this works is that these events are fired by the shapes themselves, not by the mouse or the canvas. Once that is clear, the rest follows naturally.

To make for easier-to-maintain code, we’ll share event handlers between the Square and the Circle.

public partial class Page : UserControl
{




// are we currently tracking the mouse?
private bool isTracking = false;
  // constructor
public Page()
{
InitializeComponent();

Circle.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );
Square.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );

Circle.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );
Square.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );

Circle.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
Square.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
}

 

MouseLeftButtonDown

Clicking the left mouse button acts as a signal to begin dragging. We’ll set the member flag to indicate that we are tracking, and then we’ll want to set a few properties on the shape.

Unfortunately, we have only the sender (type object) and the MouseButtonEventArgs OriginalSource property (also of type object). This is not a problem, however, as we know that any object firing this event is of type shape, so we are safe to cast accordingly,

void Shape_MouseLeftButtonDown( 
object sender,
MouseButtonEventArgs e )
{
isTracking = true;
Shape s = e.OriginalSource as Shape;


// For robust code, you should test that s is not null

With a reference to the shape, you can now set the opacity to half its current value. We won’t set it to a fixed value (e.g., 0.5) as that would break any shape whose initial opacity is not 1 (such as our square!).

s.Opacity *= 0.5;

(We’ll restore this later by doubling the value, returning it to whatever it was, without the need to cache the original value)

When the user is dragging, it is possible that the mouse will move off the shape which will cause the MouseMove event to stop firing (the technical term for this is “bad“). To prevent that, we’ll capture the mouse:

s.CaptureMouse();

MouseMove

Each time the user moves the mouse a MouseMove event is fired. We test for whether we are tracking the mouse (the IsTracking private member variable is set in ButtonDown and cleared in ButtonUp) and if so we get the current position of the mouse from the MouseEventArgs,

void Shape_MouseMove( object sender, MouseEventArgs e )
{
if ( isTracking )
{
double currentMouseX = e.GetPosition( null ).X;
double currentMouseY = e.GetPosition( null ).Y;

These values will be the new position for the Left and Top values of our shape. While this works okay for a square, it is counter intuitive for a Circle as a Circle’s top-left corner is actually that of the invisible bounding rectangle, as illustrated here (with the bounding rectangle filled in artificially in turquoise),

BoundingRect1

Since the bounding rectangle is actually invisible however, the user is forced to drag from a point to the north-west of the circle, a disconcerting and odd experience,

BoundingRect2

To eliminate that, we’ll reposition to the center of the shape,

    Shape s = e.OriginalSource as Shape;
    Canvas.SetLeft( s, currentMouseX  – s.Width / 2);
    Canvas.SetTop( s, currentMouseY – s.Height / 2);

MouseLeftButtonUp

When the left mouse button is released, we’re done dragging, we can release our capture of the mouse and set IsTracking to false, remembering to restore the opacity to its original value

void Shape_MouseLeftButtonUp( 
object sender,
MouseButtonEventArgs e )
{
isTracking = false;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 2;
s.ReleaseMouseCapture();
}

 

Here is the complete Page.xaml.cs in one place for easy copying:

using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;

namespace DragDrop
{
public partial class Page : UserControl
{
private bool isTracking = false;

public Page()
{
InitializeComponent();
Circle.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );
Square.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );

Circle.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );
Square.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );

Circle.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
Square.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
}

// ** Button down **
void Shape_MouseLeftButtonDown(
object sender,
MouseButtonEventArgs e )
{
isTracking = true;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 0.5;
s.CaptureMouse();
}


// ** Mouse Move **
void Shape_MouseMove(
object sender,
MouseEventArgs e )
{
if ( isTracking )
{
// get the mouse position
double currentMouseX = e.GetPosition( null ).X;
double currentMouseY = e.GetPosition( null ).Y;

// center the shape at the mouse position
Shape s = e.OriginalSource as Shape;
Canvas.SetLeft( s, currentMouseX - s.Width / 2);
Canvas.SetTop( s, currentMouseY - s.Height / 2);
}
}

// ** Button up **
void Shape_MouseLeftButtonUp(
object sender,
MouseButtonEventArgs e )
{
isTracking = false;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 2;
s.ReleaseMouseCapture();
}
} // end class
} // end namespace
 
Try it: 

 

 

-j

Posted in z Silverlight Archives | Comments Off on Drag and Drop with Managed Code

Navigating threads

For the past couple weeks I’ve been ironing out a new navigation feature that I’ve added to my blog. The goal is to allow you to follow a topic as it threads through the blog, skipping over intervening messages, or going back to see previous messages on the topic.

While tags help with this, they are not efficient for following a series of messages that build on one another. Thus I’ve settled on this convention: when I add a message that builds on a previous message, even obliquely, I add a backward pointer to the new message and a forward pointer to the old message.

Previous: Name of previous entry    Next: Name of next entry

The goal is that you will be able to follow a discussion thread through the blog, skipping over the intervening messages as you desire, without this system getting in your way if you wish to ignore it.

Posted in z Silverlight Archives | Comments Off on Navigating threads

Pie Chart and Column Chart videos post

NewPieChartVideoI’m pleased to announce that my videos on the Silverlight Toolkit PieChart and Columns chart are now available. 

What is very nice is that once you understand how one of these charts works, working with the other becomes almost self-evident.

 

 

 

 

 

 

 

Posted in z Silverlight Archives | Comments Off on Pie Chart and Column Chart videos post

Tag + Phone = Contact

This excellent idea from Microsoft UX Evangelist René de Paula Jr arrived just 1/2 a day too late for me to try it out at Code Mash, but I will do so at my next opportunity. He suggests placing a Microsoft Tag encoding my VCard as the final slide in my presentation; which I think is nothing short of brilliant.

ContactMe

(note, using the gettag phone application on the image above will, in fact, add my contact information to your contacts).

It will be interesting to think about how these tags might be integrated into Silverlight applications.

Posted in z Silverlight Archives | Comments Off on Tag + Phone = Contact

Building A HyperVideo Player – 1

 

 

 

In a previous posting, I began a fast and furious mini-tutorial on building a hyper-video player. In this segment, I’ll demonstrate how to:

  • Use Encoder to add markers to a video
  • Use Encoder to create a player
  • Modify the player Encoder creates using templates
  • Have the player respond to each marker as it is encountered

To begin, you’ll need a bit of video. I downloaded the 4th segment of the video on Building a Skinnable Custom Control and then cut out the middle to create a very abridged version that runs just over a minute.

AbridgedMovie

I then imported that video into Encoder, and added markers as shown in the earlier blog entry.

Use Encoder to create a player

With the markers in place I turned to creating my player. Again, this is reviewed in the previous blog entry so I won’t repeat that here, but now we’re ready to actually make the changes.  For today’s exercise, this is a process of eliminating those controls that we don’t need. We’ll start by opening the player in Expression Blend and as with any custom control you may now ask to edit a copy of the template,

EditPlayerTemplate

You are prompted, as usual to pick a name and to choose whether to put the template into the file or into App.xaml (for the entire application). We’ll choose the latter. Once these choices are made you are dropped into the template editor, the view states are revealed as are the parts of the media player.

TemplatedPlayer

This allows you to drill down into the player and simply delete those controls we won’t need, including the entire set of “miscControls,”

miscControls

 

 

 

 

which are conveniently highlighted on the player to indicate which controls you are about to assassinate,

image

In the same way, I proceeded to eliminate the buttons used for rapid navigation

NavButtons

Once these were deleted the player was simplified and ready for use.

SimplifiedPlayer

 

 

Responding to the Markers

I’d like to tell you that responding to the markers that we added to the video involves a bit of tricky programming, and you’re lucky you found my blog because I can show you how to do it right….

Opening the project in Visual Studio reveals otherwise. You’ll remember that what we’ve created is a template for the ExpressionPlayer class that was emitted by Encoder and that is found in ExpressionPlayerClass.cs:

namespace ExpressionMediaPlayer
{
public class ExpressionPlayer : MediaPlayer

Stripping out the using statements and comments reveals that the class created by Encoder is just a specialization of Media Player. MediaPlayer’s source is provided as well. Opening MediaPlayer.cs and scrolling down to the Events region reveals this:

public event TimelineMarkerRoutedEventHandler MarkerReached;

That is the event we want to respond to; it is fired every time the player encounters a marker in the video.

The EventArgs type that we are passed is well documented in the standard Silverlight documentation, which includes among other things sample code that makes our work embarrassingly easy,

public void OnMarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
{
timeTextBlock.Text = e.Marker.Time.Seconds.ToString();
typeTextBlock.Text = e.Marker.Type.ToString();
valueTextBlock.Text = e.Marker.Text.ToString();
}

All we need is a TextBlock to display the values we’ll receive when we hit the marker. Open Page.xaml and add two rows to the grid, and a TextBlock in the second row,

  <Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition
Height="9*" />
<RowDefinition
Height="0.5*" />
</Grid.RowDefinitions>
<ExpressionPlayer:ExpressionPlayer
Margin="0,0,0,0"
x:Name="myPlayer"
Style='{StaticResource ExpressionPlayerBlogVersion }'
Grid.Row='0' />
<TextBlock
x:Name='Message'
Grid.Row='1' />
</Grid>

You can now implement the event handler in Page.xaml.cs,

public partial class Page : UserControl
{

public Page( object sender, StartupEventArgs e )
{
InitializeComponent();
myPlayer.OnStartup( sender, e );
myPlayer.MarkerReached +=
new TimelineMarkerRoutedEventHandler( myPlayer_MarkerReached );
}

void myPlayer_MarkerReached( object sender,
TimelineMarkerRoutedEventArgs e )
{
Message.Text = e.Marker.Text + " at " + e.Marker.Time.Seconds.ToString() +
" seconds."
}
}

The result, as we hoped, is that the player shows the video and when it encounters a marker, it shows the name of the marker and the time the marker was hit. The easiest way to test this is to navigate to the output directory you designated in encoder,

EnodedDirectory

and pick up a copy of the the Default.html and the .wmv file output by encoder.  Drop these in the debug directory of the encoder folder

TestingFromDebug

Double click on Default.html and “let ‘er rip!”

WorkingHyperVideo

Note the marker indicated at just below the (cropped) player.  Be careful when you recompile, the default.html in the Encoder project will be over-written.

 

Previous: HyperVideo: Getting Started       Next: HyperVideo Put To Work

Posted in z Silverlight Archives | Comments Off on Building A HyperVideo Player – 1

Silverlight Toolkit WrapPanel

The Silverlight Toolkit includes a couple new panels, one of which is the incredibly handy WrapPanel.

[ Updated Jan. 4 to include working example ] 

In its most straight forward use, the WrapPanel allows you to add UIElements which it positions sequentially (typically left to right) until there is insufficient space, at which time it creates a new row beneath the most recent; that is, it wraps.

Creating a simple test program reveals a few interesting aspects about the wrap panel. To do this, open Visual Studio and create a new Silverlight Application. Be sure to add a reference to the Microsoft Windows Controls.dll that came with the Toolkit (the trick is remembering where you’ve put them!)

AddRefToMicrosoftWindowsControls

You’ll also need to create a namespace at the top of Page.xaml, but Intellisence is prepared to be of some assistance,

AddNameSpace

That done, my sample program creates a wrap panel with a single button in it; here’s the complete Xaml listing:

<UserControl x:Class="WrapPanel.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:controls="clr-namespace:Microsoft.Windows.Controls;
assembly=Microsoft.Windows.Controls" Width="800" Height="600"> <Grid x:Name="LayoutRoot" Background="White"> <controls:WrapPanel x:Name="WPanel" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Orientation="Horizontal"> <Button x:Name="Add" Content="Add!" FontFamily="Georgia" FontSize="24" Width="Auto" Height="Auto" Background="#FF0000FF" Margin="5" /> </controls:WrapPanel> </Grid> </UserControl>

 

The goal of the code that supports this page is that when the user clicks on the add button one of four controls is randomly chosen, created and added to the panel. 

using System;
using System.Windows;
using System.Windows.Controls;

namespace WrapPanel
{
  public partial class Page : UserControl
  {
    private Random rand = new Random();

    public Page()
    {
      InitializeComponent();
      Add.Click += new RoutedEventHandler( Add_Click );

    }

To support that goal, a private member variable of type Random is added as is an event handler for the "Add" button that was created in the Xaml.

All the interesting work happens in the event handler. If you start by creating controls all of the same size,

 void Add_Click( object sender, RoutedEventArgs e )
 {
   Button b = new Button();
   b.Content = DateTime.Now.ToLocalTime().ToString();
   b.Width = 120;
   b.Height = 35;
   b.Margin = new Thickness( 5 );
   this.WPanel.Children.Add( b );
}

you get a very uniform appearance as each control is added until there is not enough room and then a new row is begun. (in the example shown I’ve made the control somewhat smaller and the Add button the same size as the buttons I’m creating):

UnifromSizes

If,  instead, you create different objects, then different things begin to happen. In the next example I’ll create one of four types of objects

void Add_Click( object sender, RoutedEventArgs e )
{
  int choice = rand.Next( 0, 4 );
  Control c;
  switch ( choice )
  {
    case 0:
      // make a button
    case 1:
      // make a text box
    case 2:
      // make a short list
    case 3:
    default:
     // make a password control
  }

 // set the font size
 // set the width and height and margin
 // add the control to the wrap panel
  
}

A few interesting questions arise. What if I set their font size randomly and what if I set the height to auto (you do this programmatically by setting it to the value double.Nan).

void Add_Click( object sender, RoutedEventArgs e )
{
  /*
  Button b = new Button();
  b.Content = DateTime.Now.ToLocalTime().ToString();
  b.Width = 120;
  b.Height = 35;
  b.Margin = new Thickness( 5 );
  this.WPanel.Children.Add( b );
  */

  
  int choice = rand.Next( 0, 4 );
  Control c;
  switch ( choice )
  {
    case 0:
      Button b = new Button();
      b.Content = DateTime.Now.ToLocalTime().ToString();
      c = b;
      break;
    case 1:
      TextBox t = new TextBox();
      t.Text = rand.Next(0,int.MaxValue-1).ToString();
      c = t;
      break;
    case 2:
      ItemsControl i = new ItemsControl();
      i.Items.Add( "Cormac McCarthy" );
      i.Items.Add( "Neal Stephenson" );
      i.Items.Add( "Marcel Proust" );
      i.Items.Add( "Virginia Woolfe" );
      c = i;
      break;
    case 3:
    default:
      PasswordBox p = new PasswordBox();
      p.Height = 35;
      p.Password = "Secret";
      c = p;
      break;
  }

  c.FontSize = rand.Next( 6, 18 );
  if ( c is ItemsControl )
  {
    c.FontSize = Math.Max( c.FontSize, 10 );
  }
  c.Width = Double.NaN;
  c.Height = Double.NaN;
  c.Margin = new System.Windows.Thickness( 5 );
  
  this.WPanel.Children.Add( c );
 
}

AutoSizedWrapPanel

I find the results interesting, though not necessarily what I want.  One approach is to fix the height of the buttons, which gives another, also interesting effect. A quick way to try this is to make a small code modification:

if ( c is ItemsControl )
{
  c.FontSize = rand.Next( 8, 18 );
  c.Height = Double.NaN;
  //c.FontSize = Math.Max( c.FontSize, 10 );
}
else
{
  c.FontSize = 12;
  c.Height = 30;
}

This causes the other controls not to resize but to center on the larger list.

CenteredOnList

By using panels within panels, you can of course get just about any effect you like.

(I’ve not posted the source code because it’s all here)

Here is a working example in an iframe:

 

 

Previous  The Wrap Panel


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Silverlight Toolkit WrapPanel

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

 

 

 

 

 

Posted in z Silverlight Archives | 1 Comment

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

Posted in z Silverlight Archives | Comments Off on HyperVideo Continuing the dialog

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

    Posted in z Silverlight Archives | Tagged | Comments Off on HyperVideo

    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.

    Posted in z Silverlight Archives | 10 Comments

    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.

    Posted in z Silverlight Archives | Comments Off on Application Set: Templates & Custom Controls