| Comments

in my previous post i talked about converting rss data to json using the asp.net ajax javascriptserializer class.  i wanted to use this because i wanted an easier way of interacting with some simple data for a sample i was messing with.  i didn't really see the need to wrap it in a web service call, etc. and in the end i wanted json data.  period.

so why did i want the json data?  to mess with it in of course! what i wanted to do was display my rss feed data in a different way, just out of curiosity.  my goal: display my rss data, in my own handwriting, on a post it note.  in silverlight.  here's what i did.

the font

first, i needed my own handwriting in a true type font (fyi: silverlight supports using open type and true type fonts).  so i went on over to the tablet pc powertoys and grabbed the "My Font Tool" -- this is a tool that allows you to ink the alphabet and then it turns it into a true type font for you.  i did that process and boom, i bring you "Tim Heuer Normal":

Tim Heuer Normal TrueType

okay, great, that step is done.  on to the post it.  headed on over to istockphoto.com for a quick gander at some good stuff and snagged a good one for me.  downloaded it with my credits, used expression design to clean it up and it was ready to go, png-style.

the silverlight application

now on to silverlight...i started using expression blend to create my project.  a simple canvas that had my post-it note image on it and then added some TextBlock elements to represent the rss item title and text:

the hosting page for the silverlight control

now in the page that will be hosting the control i had to add the reference to my JSON-ized rss data using my asp.net handler that i previously wrote about.  i ran into a snag here as i suddenly realized that my json-izer just emitted json data.  that's it.  it wasn't referenced in and javascript variable or anything.  in some situations maybe that is fine, but i needed to "set" a variable to the json data to be able to reference the object later.  i quickly added a param to my json-izer to specify a callback method.  what this would do (if present) would emit javascript that basically called a function.  so if you pass in "c=evalRss" it would result in emitting:

evalRss([{...json data...}]);

this would allow me to set the object data to a variable.  in my hosting page i can now add a reference to my json-izer as such:

<script src="http://blah/rss2json.ashx?u=http://feeds.feedburner.com/timheuer&c=evalRss"></script>

of course i needed to implement the function so i added a simple javascript variable and the callback function:

var rss = null;
function evalRss(objGraph)
rss = objGraph;

as emiril would say "bam" -- now i have an "rss" object to mess around with...okay, moving on.

setting the textblock elements to the rss data

in my quick sample here, i'm only going to use the latest item in the rss feed, but read later on how you could use them all...remember, sample here folks.

i already had a default handleLoad function that was stubbed out for me and wired up by expression blend, so i'll go ahead and use that.  in the handleLoad function i take the control reference, find my TextBlock elements and set them to my rss data (remember, since my json-izer was a script reference, the json data is already there):

handleLoad: function(control, userContext, rootElement) 
this.control = control;
this.header = control.content.findName("ItemHeader");
this.itemtext = control.content.findName("ItemContent");
this.header.Text = rss[0].Channel.Items[0].Title;
this.itemtext.Text = rss[0].Channel.Items[0].Description;

okay, whew, got that far.  so when i run the application i get:

RSS Data

yeah, data.  yes, i see it to.  the html.  blech.  i'll have to think about that.  but for now, let's move on.  now i did notice that my text blabbed on beyond the image height and for this sample i didn't like that.  no problem...back to blend.  i created a rectangle (no stroke, no fill) that was the same left/top/width/height as my ItemContent TextBlock.  then with a ctrl+click on both those elements (rectangle, textblock) i headed up to the object menu, select path...make clipping path.  done.  my textblock now is clipped at the shape of the rectangle (you'll not the Clip data added in the textblock attributes).

embedding the font

but wait, i'm not done!  i said that i wanted this in my handwriting.  sweet, i'll just set the textblocks to my font...er...um...wait.  argh.  that's not supported (yet).  no worries there is a way!  here's how to go about it (or at least one way).  first add your true type font to your project.

NOTE: fonts usually have licenses with them.  you need to make sure you understand your font's license before you start embedding it all over the place.  in my case, i contacted tim heuer headquarters and they said it was okay.

now, how do i get the font on the textblock.  here's the process i used.  first, i new'd up a downloader object to get silverlight to download the font to the control and thus have access to it.  i put this in my handleLoad event handler because i want the font to be there asap:

 this.downloader = control.createObject("downloader"); 
Silverlight.createDelegate(this, this.handleFontDownloaded));
this.downloader.open("GET", "timheuer.ttf");

you'll notice that i added an event listener for the "completed" event of the downloader.  that is where the magic happens with two functions: setFontSource and fontFamily (okay, one function, one attribute).  the SetFontSource (setFontSource in javascript) expects a downloader object as the only parameter.  we're going to use the this.downloader object we created above.  we'll do the setFontSource-ing on our TextBlock elements.  after we call that function, then we can go back to the TextBlock elements and set the fontFamily attribute to the named font value.  i call out named because even though your font file might be "timheuer.ttf" that is not the name of the font family.  all this is done in the handleFontDownloaded event handler and looks like this when completed:

handleFontDownloaded: function(sender, eventArgs) 
this.header.fontFamily = "Tim Heuer Normal";
this.itemtext.fontFamily = "Tim Heuer Normal";

so what is happening here?  well silverlight has downloaded the font file using the downloader.  we've passed the downloader reference (which is the sender in the downloader completed event) to the setFontSource property of an element (in our case the TextBlock).  once the font source has been set we set the fontFamily.  so how does silverlight know what to look for?  magic i tell you, magic.  because we've set the font source to a downloader (which downloaded a file), that is the location it is now looking for the fontFamily value...and iterates through that downloader until it finds a match...in our case a true type font named "Tim Heuer Normal" to use.  once we have that i re-run the application and here we have:

RSS Data with Tim Heuer Font 


what about more than one font?

but what if you wanted multiple fonts?  would you need multiple downloaders?  no.  you see, the downloader supports compressed (zipped) files.  and it doesn't just have to be fonts.  it could be a mixture of media, fonts, xaml assets, etc.  in fact, that is how zero gravity gets all its assets for the game prior to play.  if you had a zip file that you added the "timheuer.ttf" file into, really the only thing that would change would be the downloader.open() function to downloader.open("GET", "myzipfile.zip") -- your setFontSource and fontFamily code wouldn't change!  if i had two fonts in the zip file then i could change the header to something like this.header.fontFamily = "Knockout C" or whatever other true type font is in the zip file.

having some fun

now that we have all that wired up, we can move things around and make it look like i posted a note just sticking it on the frigde or something -- not linear.  i can simply add a rotatetransform on my canvas and i'll get:

the fonts, etc. change no problems.

so my little quest was complete.  i got my handwriting in my rss feed in silverlight.  yippeee.  now if only i had an investor.

the issues and controls

there were issues as you saw.  first the characters.  the "my font" tool doesn't ask me to write every possible characters, so if i used some that weren't in my font, blech.  the point here is that you'd likely use a cool font that was professional.

the html -- yes.  i'll have to think about this one as i do have a use for this concept coming up.  my rss feed is html.  silverlight doesn't really have an "html" survace...it isn't interpreting <p> as a paragraph break, etc.  in this sample, it might be problematic, but other areas where you have text in textblocks and are embedding fonts you shouldn't have that issue.

what if you wanted to display all rss feeds?  would you need 10 textblocks and set them 10 times?  well, kinda.  my suggestion here is to use the control approach.  i already have the xaml for my post-it display.  i could take that, put it in a control, stuff it into the zip file with my font and have a control i could reference.  (for an example screencast on user controls in v1.0 see this link) for example, i could encapsulate the post-it in a control that looked something like this:

RssNotebook.RssItem = function(control, target, header, desc, x, y, downloader) 
this.header = target.findName("ItemHeader");
this.itemtext = target.findName("ItemContent");

this.header.fontFamily = "Tim Heuer Normal";
this.itemtext.fontFamily = "Tim Heuer Normal";
this.header.Text = header;
this.itemtext.Text = desc;
target["Canvas.Top"] = y;
target["Canvas.Left"] = x;

then i can extract the RssItem xaml, put that in a file and add it to a zip with my timheuer.ttf file.  I now have a zip with RssItem.xaml and timheuer.ttf.  now with that i can alter my downloader completed event to look like this:

handleFontDownloaded: function(sender, eventArgs) 
var top = 0;
for (var i=1; i<3; i++)
var postit = this.control.content.createFromXaml( sender.getResponseText("RssItem.xaml"),
new RssNotebook.RssItem(this.control, postit, rss[0].Channel.Items[i].Title,
rss[0].Channel.Items[i].Description, 0, top, sender); top += 100;

so what you see happening here is two things.  first let me be clear that this is still a sample, and for the control part i added a scale transform to reduce the size of the image just so i could display it here.  okay, what is happening is that i'm iterating through two of the rss items and createing the RssItem control within that iteration (createFromXaml) getting the xaml out of the downloaded zip file.  then in that control i'm doing the fontSource-ing and fontFamily-ing for the TextBlocks represented in their control. 

pretty cool huh?

i hope this may help with some things.  if not, ask me questions.  i've included the sample code in this post to help you out.

File: RssNotebook-single-style.zip</> (sample using single style)
File: RssNotebook-control-style.zip</> (sample using control style with zip file)

if you have any suggestions for other things you'd like to see, keep them coming!

| Comments

i know i posted earlier with a pointer to the preview sdk over in sneathville, but i walked through the docs this morning and just wanted to re-iterate the need to look at the breaking changes document included in the preview sdk.  why? because when i look at the numerous samples i see that some are likely to be affected.  wouldn't you want your sample to run when the release candidate is put in the wild?  i would.

breaking changes...ugh...they suck.  but bear in mind this is beta and we knew there could be some.  in looking through the docs, i wanted to highlight some that i felt were more common.  the docs do a good job of discussing the change, and showing before/after code.

anyhow, here's my list:

removing 'javascript:' in event handlers

note this applies to if you are coding your even handlers in your xaml like this:

<Canvas x:Name="myButton" MouseLeftButtonUp="javascript:foo" />

you'd want to change that not to include the javascript: prefixer.  personally, i'm of the belief you shouldn't embed your event handlers in your xaml necessarily.  i heard (and saw) a very good discussions on reasons why it might not be a good idea especially if you have designers generating xaml for you.  each generation of xaml from a tool like Expression Design won't 'merge' event handler wire-ups.  what this means is that if you have xaml with event handlers like this and your designer checks in a new xaml file, your app might break because they are using a design tool that may not have functions to enable event handler wire-up in xaml.  i'm babbling here, but note the change if you are.

removing "Sys."

probably going to affect everyone.  instead of Sys.Silverlight.foofunction() you'll need to remove the Sys. prefixer here.  quite simply, the namespace "Sys." was removed in the RC.

using the downloader object

one of my favorite little objects in silverlight.  in the beta bits, there was a third param in the creation that enabled you to choose whether the downloader would perform async or not.  that param is now removed...all downloads are async.  the sdk doc describes a method you can do to trick out the beta bits, but note that the third param is no longer there.

downloader.open("get", file, true) 
downloader.open("get", file)

visibility:hidden is now visibility:collapsed

um, it couldn't be explained any simpler.  hidden and collapsed meant the same thing, so we picked one and kept it consistent...hidden is no longer...use collapsed.

elements in Resources node must be named

good practice anyway that should have been followed, but if you are creating resource storyboards, etc. then you need to name them using the x:Name attribute.  this applies to anything in <Canvas.Resources>

AddEventListener returns a token for RemoveEventListener

basically if you were using removeEventListener before, you'd specify the object and the event handler function.  now, you have to pass a pointer to the token.  so when you add an event listener, you'll get a token as an object return.  you'll then use *that* in the remove command instead of the function name.  something like this:

var enterToken = myObj.addEventListener(“MouseEnter”, myEnterHandler);
myObj.removeEventListener(“MouseEnter”, enterToken);

version property in plug-in creation is obsolete

instead, use isVersionSupported instead.  this is what the new silverlight.js file looks for (note: the new silverlight.js file is also located in the preview SDK).

so there are my key highlights.  there are more, and you really should download the preview sdk and read the docs.  prepare yourself.  prepare your samples (myself included, i need to find the time to go back, but i'd imagine your samples are much more important).  get ready for RC baby!

| Comments

one really great feature about silverlight is the packaging aspect of it.  what do i mean by this?  well, you can essentially put a ton of assets into a compressed file and pull them out as needed.  this would provide you the ability to have a single asset package that is compressed, and thus saving on some download time.  of course there would be tradeoffs that you'd have to consider, but for sample sake, let's assume they are good.

so how would you do that?  well let's say you have a bunch of images in a file name 'assets.zip' (here we have 2):

in our silverlight application we want to load those up and then maybe use them individually later at some point in an event.  here's the xaml i'm working with for this sample:

   1:  <Canvas
   2:      xmlns="http://schemas.microsoft.com/client/2007"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      Width="605" Height="314"
   5:      >
   6:      <Rectangle Stroke="#FF000000" x:Name="progressBar" Width="0" Height="18" Canvas.Top="1">
   7:          <Rectangle.Fill>
   8:              <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
   9:                  <GradientStop Color="#FFCAE8B0" Offset="0"/>
  10:                  <GradientStop Color="#FF68C51A" Offset="1"/>
  11:              </LinearGradientBrush>
  12:          </Rectangle.Fill>
  13:      </Rectangle>
  14:      <Rectangle Stroke="#FF000000" Width="600" Height="18" Canvas.Top="1"/>
  15:      <Image x:Name="logoImage" Width="318" Height="204" Canvas.Left="282" Canvas.Top="23"/>
  16:      <Canvas Width="117" Height="28" Canvas.Top="64" MouseLeftButtonUp="handleButton2Click">
  17:          <Rectangle Stroke="#FF000000" RadiusX="4" RadiusY="4" x:Name="buttonPicture2" 
Width="117" Height="25" >
  18:              <Rectangle.Fill>
  19:                  <LinearGradientBrush EndPoint="0.613,-1.095" StartPoint="0.503,1.975">
  20:                      <GradientStop Color="#FF58DD65" Offset="0.067"/>
  21:                      <GradientStop Color="#FF42BBB8" Offset="1"/>
  22:                  </LinearGradientBrush>
  23:              </Rectangle.Fill>
  24:          </Rectangle>
  25:          <TextBlock Width="57" Height="25" FontFamily="Calibri" FontSize="14" Text="Picture 2" 
                     Canvas.Left="33" Canvas.Top="3"/>
  26:      </Canvas>
  27:      <Canvas Width="118" Height="28" Canvas.Top="23" MouseLeftButtonUp="handleButton1Click">
  28:          <Rectangle Stroke="#FF000000" RadiusX="4" RadiusY="4" Width="118" Height="25" 
                     x:Name="buttonPicture1" >
  29:              <Rectangle.Fill>
  30:                  <RadialGradientBrush>
  31:                      <GradientStop Color="#FFDDB758" Offset="0.067"/>
  32:                      <GradientStop Color="#FFBBAF42" Offset="1"/>
  33:                  </RadialGradientBrush>
  34:              </Rectangle.Fill>
  35:          </Rectangle>
  36:          <TextBlock Width="57" Height="25" Canvas.Left="33" Canvas.Top="3" FontFamily="Calibri" 
                     FontSize="14" Text="Picture 1"/>
  37:      </Canvas>
  38:      <TextBlock x:Name="percentComplete" Width="110" Height="27" Canvas.Top="96" 
                     FontFamily="Calibri" FontWeight="Bold" Text="" TextWrapping="Wrap"/>
  39:  </Canvas>

i'm using the javascript programming model here and my xaml file has an associated javascript file that looks like this (minus the silverlight creation script):

   1:  var dl = null;
   3:  function onDownloadProgressChanged(sender, eventArgs)
   4:  {
   5:      var pcnt = Math.floor(sender.downloadProgress * 100);
   7:      sender.findName("progressBar").width = sender.downloadProgress * 600;
   8:      sender.findName("percentComplete").text = sender.downloadProgress * 100 + "%";
   9:  }
  11:  function onDownloadCompleted(sender, eventArgs)
  12:  {
  13:      var img = sender.findName("logoImage");
  14:      img.setSource(sender, "PIC_0004.jpg");
  15:  }
  17:  function initDownloader(host)
  18:  {
  19:      dl = host.createObject("downloader");
  21:      dl.addEventListener("downloadProgressChanged", "onDownloadProgressChanged");
  22:      dl.addEventListener("completed", "onDownloadCompleted");
  24:      dl.open("GET", "timfaces.zip", true);
  26:      dl.send();
  27:  }
  29:  function resetImage(host, imgName)
  30:  {
  31:      var img = host.content.findName("logoImage");
  33:      if (!dl) { initDownloader(host); }
  35:      img.setSource(dl, imgName);
  36:  }
  38:  function handleButton1Click(sender, eventArgs)
  39:  {
  40:      var host = sender.getHost();
  42:      resetImage(host, "PIC_0004.jpg");
  43:  }
  45:  function handleButton2Click(sender, eventArgs)
  46:  {
  47:      var host = sender.getHost();
  49:      resetImage(host, "PIC_0012.jpg");
  50:  }

notice the two events wired up on initDownloader and the two callback events that happen when those events are completed.

take a look at the function onDownloadCompleted...this is where we leverage the compressed asset file.  for this sample, we want to use images.  so basically we are setting an image object source to an item in the zip file.  we first find the associated element, then setSource providing the name which resides in the zip file.  that's it, we are done!

in my sample here, i chose to implement "dl" as a global variable so i could access it later.  while at MIX this week i was able to get some better practices of wiring up some object prototypes and include the downloader as an object essentially of the other javascript objects.  i know it sounds confusing.  open up blend 2 preview and start a project, look at the scene.xaml.js file and you'll see what i mean...it really isn't that confusing.  i just had this working sample and wanted to share.

the concept of using a downloader in conjunction with a compressed asset file intrigues me and i hope you may find it useful.  now this isn't the only way you could use this method (picture assets), as i believe the intent actually was more of a packaging concept intended for xaml files that you can pull out and load. as an example, in the onDownloadCompleted let's assume i had a file in there called newFunction.xaml that was there for some additional layouts, etc.  i could do something like this (again, assuming in the onDownloadCompleted method):

var newXaml = sender.getResponseText("newFunction.xaml");

then with that text i can do some createObjectFromXaml functions or something like that.  pretty cool.

have fun, check out today.