Matt Casto's .NET Journal RSS 2.0
 Monday, March 23, 2009

This is part 1 of my Silverlight 3 Feature By Feature series of blog posts.

No More Blank Slate

The first thing you may try after installing the Silverlight 3 Beta 1 Tools is creating a new Silverlight application. There is a new project template available called Silverlight Navigation Application. Using this project template creates a Silverlight project with a few things already set up for you. This is a departure from what we've had so far - a blank slate that is intimidating and doesn't really help new developers.

The new project contains the typical App.xaml but now with a bunch styles used in the main page. The MainPage.xaml is a generic, but nice looking, layout for an example Silverlight application. There are links to the Home and About views, which are both located in the Views folder of the project along with a view reserved for errors.

SilverlightNavApp_SlnExpl

Running the application without any changes shows the full page Silverlight application. Click on the links will change the URL in your browser and update the browsing history. You can use these URLs to go to a specific view. For example, from the About view copy the URL, then open an alternative browser and paste in the URL. Viola! Deep linking!

SilverlightNavApp_FirstRun

How It Works

The trick to the navigation, as implemented in the project template, is the Frame control in MainPage.xaml.

   1: <UserControl x:Class="SilverlightNavigation.MainPage"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation">
   5: ...
   6:     <navigation:Frame x:Name="Frame" Source="/Views/HomePage.xaml"
   7:                   HorizontalContentAlignment="Stretch"
   8:                   VerticalContentAlignment="Stretch"
   9:                   Padding="15,10,15,10"
  10:                   Background="White"/>
  11: ...
  12: </UserControl>

In particular, notice the navigation namespace. The project has a reference to the System.Windows.Controls.Navigation assembly which contains new controls and other things used for navigation.

The Frame is instructed to navigate in the Click event handler of the buttons.

   1: private void NavButton_Click(object sender, RoutedEventArgs e)
   2: {
   3:     Button navigationButton = sender as Button;
   4:     String goToPage = navigationButton.Tag.ToString();
   5:     this.Frame.Navigate(new Uri(goToPage, UriKind.Relative));
   6: }

I don’t exactly like the method of storing the destination page in the buttons’ Tag property, but that could easily be encapsulated by a custom NavigationButton control. Perhaps we’ll get one before RTW? I’ll definitely have to expand on this in a separate blog post.

HomePage.xaml and AboutPage.xaml are both Page objects instead of UserControl, which is typically the base control of new XAML files in a Silverlight 2 project. Its easy enough to add new navigable content to your application. Just add a new item to your project, and choose the Silverlight Page template in the Add New Item dialog.

Custom Navigation

What I wanted to do with my Silverlight Overview application was have a tree view control listing all of the examples, and each of these example pages showing up as a unique URL so I could link to a specific example. My original Silverlight Demo application had examples split into tab controls. Each tab was a separate XAML file. I could have modified these to be a Page instead of UserControl, but I wanted to break them down further and didn’t relish the thought of having 30+ Page files.

Using Reflector, I found that the Frame control’s Navigate method is using the NavigationService. Looking into this code wasn’t leading me anywhere so I decided to look at the Silverlight 3 documentation on MSDN. Interestingly, the only page that I found related to navigation, Navigation Overview, hasn’t been updated for Silverlight 3 and contains incorrect information. Finally I found Tim Heuer’s Navigation Framework screencast and blog post which shows how to use the UriMapper to accomplish what I’m looking for.

<nav:UriMapper x:Key="uriMapper">
    <nav:UriMapping Uri="Examples/{example}" MappedUri="/ExamplePage.xaml?example={example}" />
</nav:UriMapper>

Currently the UriMapper can only be defined in the App.xaml. Hopefully we’ll be able to move this to resource dictionary or even the same file as the Frame control.

Along with my changes to the App.xaml I added one Page to my project, ExamplePage.xaml.

<navigation:Page x:Class="SilverlightOverview.ExamplePage" 
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title="Example Page"
           xmlns:slo="clr-namespace:SilverlightOverview"
           Loaded="Page_Loaded">
    <Grid x:Name="LayoutRoot" Background="White">
        <slo:XamlViewer x:Name="viewer" />
    </Grid>
</navigation:Page>
   1: public partial class ExamplePage
   2: {
   3:     public ExamplePage()
   4:     {
   5:         InitializeComponent();
   6:     }
   7:  
   8:     private void Page_Loaded(object sender, RoutedEventArgs e)
   9:     {
  10:         if (this.NavigationContext.QueryString["example"] != null)
  11:         {
  12:             viewer.XamlFilename = string.Format("SilverlightOverview.Xaml.{0}.xaml",
  13:                                                 this.NavigationContext.QueryString["example"]);
  14:         }
  15:     }
  16: }

Running the project shows that my URLs to look like this.

SilverlightNavApp_URL

You can even try it for yourself if you have the Silverlight 3 Beta 1 runtime installed.

I really wanted to avoid the “Examples/” part of the URL since I only have one view, but there is a limitation built in which throws exceptions if I don’t have at least a something in there.

At this point all I had to do was add a TreeView and Frame to a Grid in my MainPage.xaml, bind the tree to a static list of example data, and my application is running. I’d like to figure out a way to dynamically change the page’s title, but I ran out of time. At first glace it appears that the only place to do this is from within the Page control, but I bet there’s way to get the currently displayed page from the Frame.

You can view the Silverlight Overview application here. At the time of writing this blog post, the deep linking is the only Silverlight 3 feature that’s been added.

Summary

The Good:  The Navigation Framework is a really great addition to Silverlight!

The Bad:  I’d rather be able to manually add items to the browser history and display pages based on the URL, but this solution will be fine for now. I think there might be a way to do that, but I could not find any other documentation and I ran out of time to look through everything with Reflector.

The Beautiful:  I finally have something to point to when Flash developers ask what Silverlight has to offer that Flash/Flex does’t.

(note – I wanted to summarize with the good, the bad and the ugly, but there’s nothing truly ugly about Silverlight 3 so I went with the opposite)

Monday, March 23, 2009 12:11:13 AM (Eastern Standard Time, UTC-05:00)  #    Comments [4] -
silverlight

I’m starting a series of blog posts where I’d go through each of Silverlight 3’s new features. To do this, I’m taking my Silverlight Demo application and updating it to include these new features.

Silverlight Overview

To start this off, I’ve converted my demo application to work with Silverlight 3 Beta 1 and posted it on CodePlex as Silverlight Overview. This application is a great interactive introduction and overview of XAML, controls and data binding in Silverlight. Currently the project only covers features through Silverlight 2, but I will be updating it as I cover each feature of Silverlight 3.

Feature By Feature

I’ll update this post with links as I add posts for each feature of Silverlight 3 to my series.

  • Deep Linking
  • Out of Browser (coming soon)
  • Data Binding (coming soon)
  • Perspective 3D (coming soon)
  • Easing Animations (coming soon)
  • Pixel Shader (coming soon)
  • Resource Dictionaries (coming soon)
  • Bitmap Enhancements (coming soon)
  • more when I get there ;-)
Monday, March 23, 2009 12:06:23 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight
 Saturday, March 14, 2009

In the spirit of Code Share Week, I’ve decided to share a base class we’ve been using for our test classes on my current project.

Specification

We’ve been using a Specification base class for our NUnit test classes, which is kind of following the BDD style of unit testing.

   1: [TestFixture]
   2: public class Specification
   3: {
   4:     [SetUp]
   5:     public void Initialize()
   6:     {
   7:         Mocks = new MockRepository();
   8:         Before_each();
   9:         ReplayAll();
  10:         Because();
  11:     }
  12:  
  13:     [TearDown]
  14:     public void Cleanup()
  15:     {
  16:         After_each();
  17:     }
  18:  
  19:     protected virtual void Before_each() { }
  20:     protected virtual void After_each() { }
  21:     protected virtual void Because() { }
  22:  
  23:     public MockRepository Mocks { get; private set; }
  24:  
  25:     protected T Mock<T>() where T : class
  26:     {
  27:         return MockRepository.GenerateMock<T>();
  28:     }
  29:  
  30:     protected T Stub<T>() where T : class
  31:     {
  32:         return MockRepository.GenerateStub<T>();
  33:     }
  34:  
  35:     protected T Stub<T>(params object[] args) where T : class
  36:     {
  37:         return MockRepository.GenerateStub<T>(args);
  38:     }
  39:  
  40:     protected T Partial<T>() where T : class
  41:     {
  42:         return Mocks.PartialMock<T>();
  43:     }
  44:  
  45:     protected T Partial<T>(params object[] args) where T : class
  46:     {
  47:         return Mocks.PartialMock<T>(args);
  48:     }
  49:  
  50:     protected void Raise(object mock, string eventName, object sender, EventArgs args)
  51:     {
  52:         new EventRaiser((IMockedObject)mock, eventName).Raise(sender, args);
  53:     }
  54:  
  55:     protected virtual void ReplayAll()
  56:     {
  57:         Mocks.ReplayAll();
  58:     }
  59:  
  60:     protected void spec_not_implemented()
  61:     {
  62:         MethodBase caller = new StackTrace().GetFrame(1).GetMethod();
  63:  
  64:         spec_not_implemented(caller.DeclaringType.Name + "." + caller.Name);
  65:     }
  66:  
  67:     protected void spec_not_implemented(string specName)
  68:     {
  69:         Console.WriteLine("Specification not implemented : " + specName);
  70:     }
  71:  
  72: }

A typical Specification

Here’s a typical specification written to test user account creation.

   1: public class When_creating_a_new_user_account : Specification
   2: {
   3:     private IThirdPartyUserService _thirdPartyUserService;
   4:     private IUserDetailController _userDetailController;
   5:     private CreateUserCommand _newUserCommand;
   6:     private UserService _userService;
   7:  
   8:     protected override void Before_each()
   9:     {
  10:         _thirdPartyUserService = Stub<IThirdPartyUserService>();
  11:         _userDetailController = Stub<IUserDetailController>();
  12:         var lookupService = Stub<ILookupService>();
  13:         var logService = Stub<ILogService>();
  14:         var encryptionService = Stub<IEncryptionService>();
  15:         _newUserCommand = new CreateUserCommand();
  16:         _thirdPartyUserService.Stub(tpus => tpus.CreateUser(_newUserCommand)).Return("fakeAuthTicket");
  17:         encryptionService.Stub(es => es.Encrypt(_newUserCommand.Password)).Return(_newUserCommand.Password);
  18:         _userService = new UserService(_thirdPartyUserService, _userDetailController, 
  19:                                         logService, lookupService, encryptionService);
  20:     }
  21:  
  22:     protected override void Because()
  23:     {
  24:         _userService.CreateUser(_newUserCommand);
  25:     }
  26:  
  27:     [Test]
  28:     public void Should_call_the_ThirdParty_user_service()
  29:     {
  30:         _thirdPartyUserService.AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
  31:     }
  32:  
  33:     [Test]
  34:     public void Should_call_the_UserDetailController_to_persist_data()
  35:     {
  36:         _userDetailController.AssertWasCalled(udc => udc.Insert(_newUserCommand.Login,
  37:             _newUserCommand.Password, _newUserCommand.Email));
  38:     }
  39: }

Specification using RhinoAutoMocker

One problem we ran into was that the UserService class kept having dependencies added as more functionality was added to the class. We’re using StructureMap as an IoC container, so there’s no impact to code when you add a dependency to a constructor, but it was requiring us to refactor our tests since we’re not using StructureMap to create instances inside of our tests.

StructureMap comes with a separate assembly containing the RhinoAutoMocker which my colleague Jon Kruger suggested would solve our constant refactoring problem. You can use the auto mocker functionality to automatically mock all dependencies of a class. This also cleans up your code because you don’t have to create fields for dependencies that you plan on using in multiple test methods.

   1: public class When_creating_a_new_user_account : Specification
   2: {
   3:     private RhinoAutoMocker<UserService> _mocker;
   4:     private IThirdPartyUserService _thirdPartyUserService;
   5:     private IUserDetailController _userDetailController;
   6:     private CreateUserCommand _newUserCommand;
   7:  
   8:     protected override void Before_each()
   9:     {
  10:         _mocker = new RhinoAutoMocker<UserService>();
  11:         _newUserCommand = new CreateUserCommand();
  12:         _thirdPartyUserService = _mocker.Get<IThirdPartyUserService>();
  13:         _thirdPartyUserService.Stub(tpus => tpus.CreateUser(_newUserCommand))
  14:                                     .Return("fakeAuthTicket");
  15:         _userDetailController = _mocker.Get<IUserDetailController>();
  16:         _mocker.Get<IEncryptionService>().Stub(es => es.Encrypt(_newUserCommand.Password))
  17:                                     .Return(_newUserCommand.Password);
  18:     }
  19:  
  20:     protected override void Because()
  21:     {
  22:         _mocker.ClassUnderTest.CreateUser(_newUserCommand);
  23:     }
  24:  
  25:     [Test]
  26:     public void Should_call_the_ThirdParty_user_service()
  27:     {
  28:         _thirdPartyUserService.AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
  29:     }
  30:  
  31:     [Test]
  32:     public void Should_call_the_UserDetailController_to_persist_data()
  33:     {
  34:         _userDetailController.AssertWasCalled(udc => udc.Insert(_newUserCommand.Login,
  35:             _newUserCommand.Password, _newUserCommand.Email));
  36:     }
  37: }

AutoMockingSpecification

I took this a step further and created a base class that is used when you’re only testing one class. It doesn’t add all that much functionality, but it does make your specs look much cleaner.

   1: public class AutoMockingSpecification<T> : Specification
   2:     where T : class 
   3: {
   4:     private bool _replayTheClassUnderTest = false;
   5:  
   6:     public RhinoAutoMocker<T> Mocker { get; set; }
   7:  
   8:     protected override void Before_each()
   9:     {
  10:         base.Before_each();
  11:         Mocker = new RhinoAutoMocker<T>();
  12:     }
  13:  
  14:     protected override void ReplayAll()
  15:     {
  16:         base.ReplayAll();
  17:         if (_replayTheClassUnderTest)
  18:             Mocker.ClassUnderTest.Replay();
  19:     }
  20:  
  21:     public virtual void PartialMockTheClassUnderTest()
  22:     {
  23:         Mocker.PartialMockTheClassUnderTest();
  24:         _replayTheClassUnderTest = true;
  25:     }
  26: }

Specification Using AutoMockingSpecification

Here’s our sample UserService specification refactored to use the AutoMockingSpecification base class.

   1: public class When_creating_a_new_user_account : AutoMockingSpecification<UserService>
   2: {
   3:     private CreateUserCommand _newUserCommand;
   4:  
   5:     protected override void Before_each()
   6:     {
   7:         base.Before_each();
   8:         _newUserCommand = new CreateUserCommand();
   9:         Mocker.Get<IThirdPartyUserService>().Stub(tpus => tpus.CreateUser(_newUserCommand))
  10:                                             .Return("fakeAuthTicket");
  11:         Mocker.Get<IEncryptionService>().Stub(es => es.Encrypt(_newUserCommand.Password))
  12:                                         .Return(_newUserCommand.Password);
  13:     }
  14:  
  15:     protected override void Because()
  16:     {
  17:         Mocker.ClassUnderTest.CreateUser(_newUserCommand);
  18:     }
  19:  
  20:     [Test]
  21:     public void Should_call_the_ThirdParty_user_service()
  22:     {
  23:         Mocker.Get<IThirdPartyUserService>().AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
  24:     }
  25:  
  26:     [Test]
  27:     public void Should_call_the_UserDetailController_to_persist_data()
  28:     {
  29:         Mocker.Get<IUserDetailController>().AssertWasCalled(
  30:             udc => udc.Insert(_newUserCommand.Login, _newUserCommand.Password, _newUserCommand.Email));
  31:     }
  32: }

 

I’m pleased with the result, and it seems to be pretty popular with the other developers on our project.

Saturday, March 14, 2009 2:29:41 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -

 Friday, March 13, 2009
I'll be speaking at the Cincinnati Silverlight Firestarter event at the Microsoft office in Mason, OH on March 28th.  Following in the Cleveland event's footsteps, this is going to have local speakers and is a great full day introduction to Silverlight.  I'll be giving the Controls and Databinding post-lunch talk again. (Hopefully this time my laptop will work with the projector.)

 

Agenda:

 8:30 AM: Registration

 9:00 AM: An Introduction to Silverlight (Jeff Blankenburg)

 10:30 AM: An Introduction to XAML (Joe Wirtley)

 11:45 AM: Lunch break

 12:30 PM: An Introduction to the Tools (Josh Holmes)

 2:00 PM: An Introduction to Controls & Data Binding (Matt Casto)

 3:30 PM: Server Communication (Sam Nasr)

 4:45 PM: Giveaways and closing


To register for this event, please go to https://www.clicktoattend.com/invitation.aspx?code=136101


Hope to see you there!

Friday, March 13, 2009 9:17:55 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight
I was reading Shawn Wildermuth and John Papa's blog posts about all of the tools that they use for Silverlight development, and it finally pushed me to put a thought that's been rattling around in my brain into words.

Last weekend I was at the Art & Code conference at CMU in Pittsburg presenting, along with Tim Hibner, an introduction to Silverlight. Being in that environment reminded me of what it was like when I was a student and was looking at various programming languages. One of the things I was interested in doing back then was developing video games. I remember looking into Flash programming and was turned off by the cost of the development environment. To be honest, that was a while ago and I don't remember what the costs were, but I do remember the feeling that I couldn't bother with the hassle of learning the platform.

Developing video games like today's casual Flash games is a huge opportunity for an entry point to learning Silverlight. Just look at all of the Flash game sites out there. There are actually some Silverlight specific game sites getting started now like Silver Arcade and Silverlight Club. In fact, there is currently a Silverlight game development contest with a grand prize of $5000, which should definitely get people interested.

The first place people interested to start with Silverlight are pointed to is the Get Started page on the official Silverlight web site. This page starts out by linking to the Silverlight Tools for Visual Studio 2008 SP1, which in turn requires you to already have Visual Studio 2008 or Visual Web Developer Express installed with Service Pack 1. Assuming the user downloads the Visual Web Developer Express, they have a joy filled hour+ of baby sitting installs. Then, the second step is to download and install the Expression Blend 2 trial, and download and install the Expression Blend 2 Service Pack 1 on top of that. Gah! It goes on from there.

I'm seriously wondering how many people make it that far, or have given up at this point. I think the final straw for me would have been the fact that Blend is only a 30 day trial. What do I do after that? Pay $499 for Expression Blend or $999 for Expression Studio? No way! Even as a professional developer today I wouldn't pay that. And, sure, there's DreamSpark, but that's an extra hassle, and the get started page doesn't even mention it.

I love Silverlight, but its been easy for me since I've been developing on the Microsoft platform for over 10 years and I have access to MSDN downloads. Thank goodness for the fact that Blend is available through that, or else no one would bother with it.

Microsoft has done a great job with making free versions of its tools available lately, but for all the weight they're putting behind Silverlight I don't understand why they don't, at the very least, have an Express version of Blend. I would even suggest that there should be a free version of the entire Expression Suite, although a name like Expression Suite Express is kinda silly. :-)

Friday, March 13, 2009 7:09:13 AM (Eastern Standard Time, UTC-05:00)  #    Comments [10] -
silverlight | tools
 Monday, November 03, 2008
Last Saturday's Silverlight Firestarter event in Cleveland was a blast.  Being able to express my excitement for Silverlight to so many people (around 70 people showed) that had little to no experience with it was unbelievable.

I had problems connecting my Dell Inspiron 1720 laptop to the external display so the projector wouldn't work.  I had the same problem last Tuesday night at the CINNUG presentation, but this time John Stockton was there to save the day.  I was able to present all of my material on his machine without much of a hitch.

Jeff Blankenburg did a top notch job presenting the keynote and improvising in his Tools talk when his Blend install wouldn't work with Silverlight 2 projects.  Sarah Dutkiewicz was inspirational in her XAML basics session - she gave a clear introduction to XAML while being sick and barely able to talk!  Finally, John Stockton's presentation on Server Communicatiion in Silverlight showed why he's the man.  :-D

The project and slide files that I used for the presentations are available from my Sky Drive:

Monday, November 03, 2008 10:10:04 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight
 Tuesday, October 21, 2008
I'll be speaking at the Cleveland Silverlight Firestarter event on November 1st.  This event is going to have mostly the same structure as the NYC Silverlight Firestarter, but with (mostly) local speakers.  For instance, I'll be filling Shawn Wildermuth's shoes by giving the Controls and Databinding afternoon talk.

 

Agenda:

 8:00 AM: Registration

 9:00 AM: Keynote/Intro to Silverlight 2 (Jeff Blankenburg)

 10:30 AM: XAML Basics (Sarah Dutkiewicz)

 Noon: Lunch break

 1:00 PM: The Tools (Jeff Blankenburg)

 2:30 PM: Controls & Data Binding (Matt Casto)

 4:00 PM: Server Communication (John Stockton)


To register for this event, please go to http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032392883&Culture=en-US


Hope to see you there!

Tuesday, October 21, 2008 1:09:19 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight
 Tuesday, October 07, 2008
My submission to the Create a Sports Game in Silverlight Contest hosted by Team Zone Sports ended up in second place!

The game is called Ball Blocks because I couldn't come up with a better name at the time.  You play by drawing a square over the balls where the four corners of the square are on top of the same type of ball.  The bigger the square (more balls inside of it) the more points you get and the more time gets added back to the timer.

The game currently has a bug in it where it can freeze the browser during the game over animation when time expires.  This seems to happen more often on slower machines.  It may be because of the spinning textblock ... I'm just not sure.

Because of time spent trying to fix this bug, I didn't get sounds fully implemented and didn't get a far into the game development as I'd hoped.  I'm hoping to spend some more time on it some time soon and get some of the features I'd originally envisioned implemented.

I've created a Ball Blocks project on CodePlex and uploaded the code.  The project has been updated to work in Silverlight 2.0 RC0 so it should be ready once Silverlight 2 is released.

Tuesday, October 07, 2008 10:35:12 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight
 Monday, April 21, 2008

This is a very simple animation that can be used just about anywhere.

[[ If you're viewing this post through an RSS reader, you won't be able to see the Silverlight example ]]

Following is my Page.xaml for this example.  There was no code needed.

<UserControl x:Class="AnimationSample.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="300" Height="150">
  <Grid x:Name="LayoutRoot" Background="White">
    <Grid.Triggers>
      <EventTrigger RoutedEvent="Grid.Loaded">
        <EventTrigger.Actions>
          <BeginStoryboard>
            <Storyboard x:Name="CrawlingBorder" RepeatBehavior="Forever">
              <DoubleAnimationUsingKeyFrames Storyboard.TargetName="rectangle" 
                Storyboard.TargetProperty="(Shape.StrokeDashOffset)" BeginTime="00:00:00">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="5" />
              </DoubleAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger.Actions>
      </EventTrigger>
    </Grid.Triggers>
    <Rectangle Stroke="Green" StrokeThickness="6" StrokeDashArray="3,2" StrokeDashCap="Round" 
               Margin="20" StrokeDashOffset="0" StrokeLineJoin="Round" x:Name="rectangle">
    </Rectangle>
    <TextBlock FontFamily="Lucida Sans Unicode" FontSize="24" 
               Text="Crawling Border" FontWeight="Bold" 
               HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FFDE680A"/>
  </Grid>
</UserControl>
Monday, April 21, 2008 9:55:36 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
silverlight

I gave a talk at the Central Ohio Day of .NET last Saturday about Silverlight 2.  The presentation was written in Silverlight 2 Beta 1 and included examples of functionality built into Silverlight versions 1 and 2, and the beginning steps in creating the presentation itself.

I have much more planned to be added to the presentation, so I created a CodePlex project called PresentLight.  I'm hoping that other people will like the idea of giving a presentation in the technology that they're speaking about, and maybe they'll use the framework or even add their own content!

I uploaded a slightly older version than the one I gave at CODoDN to silverlight.live.com, check it out by clicking on the following preview image.  The XAP is 14 MB so expect a decent wait for everything to load ... I need to reduce the size.  I'll update this post with a better example as soon as I have it available.

Much thanks goes out to Jeff Blankenburg for building the original slide deck that I based this presentation on.  Also, I got the idea from David Sleeckx's WPF presentation, which is an excellent way to get an overview of WPF.

Using the Presentation

You can navigate the slides through the menu on the left, or move forward one slide by clicking on the header area.  A few of the slides don't have much at first, but clicking in the slide area will show text which was talking points for that part of the presentation.  The interactive slides in the middle should be pretty self explanatory - you can modify the XAML in most of the examples to see changes in real time.

The screen shots at the end can be clicked on to view the full size.  I wanted to keep the entire presentation in Silverlight, so I was trying to use screen shots instead of jumping into Visual Studio.  These slides were taking over an hour each to prepare, because I was trying to give each one a different type of animation.  I think they ended up being a little disjointed though - its much more natural to see someone working with the environment than seeing screen shots of some code, then the solution explorer, then XAML.  I'm definitely going to have to give more thought to that area.

Plans for the Future

I plan to have the slides stored in data rather than hard coded in the page code behind.  I'm going to integrate more examples, such as Isolated Storage, Communications with web services and through sockets, and dynamic languages integrated directly into the slides, like I did with the XAML examples.

Also, I'm going to expand more on some of the user controls that I created as part of the application.  I already went into the scrolling textbox control in my last post, so there will be more of that on the way.

Monday, April 21, 2008 9:15:26 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2] -
silverlight
 Sunday, April 13, 2008

The TextBox control included with Silverlight 2 Beta 1 is a welcome addition.  There was no such control in previous versions of Silverlight, including the alpha.

Unfortunately, the TextBox control is very limited at this point.  It does not support scrollbars when it's content is larger than it's size.  You can "scroll" the next by moving the cursor, but that's just enough to make it functional.  Selecting text past what's visible doesn't automatically scroll to the cursor.  Also, there's no text wrapping, although setting the AcceptsReturn property to True will allow line breaks in the text.

I wanted to have a text box with a little more functionality for my projects, so I decided to see what I could do.  What follows is the simple ScrollingTextBox control that I created.  I didn't spend a ton of time on this because I fully expect this "missing" functionality to be included by Beta 2, or at least by the time Silverlight 2 is released.

 

To build this, I first created a Silverlight application project and added a Silverlight control called ScrollingTextBox.

<UserControl x:Class="PresentLight.ScrollingTextBox"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid x:Name="LayoutRoot">
    <ScrollViewer x:Name="sv" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
      <TextBlock x:Name="hiddenTextBlock" Opacity="0" />
      <TextBox x:Name="tb" AcceptsReturn="True" TextChanged="tb_TextChanged" />
    </ScrollViewer>
  </Grid>
</UserControl>

The internal TextBlock control is only there to serve as a way to get the actual size of the text.  TextBlock controls will automatically resize to fit their contents, so if I keep it's text the same as the internal textbox control, it will resize accordingly.  The default value for Width and Height dependency properties in Silverlight is Auto, which causes this resize behavior.

Since the ScrollViewer control automatically set's it's scrollable region to fit it's contents, it will be resized to fit the internal textblock.  The internal textbox control will automatically resize to fit it's container, since I haven't set any width or height on it.

Then I added a dependency property for setting the control's Text, which takes care of setting the textbox's text value.  Finally, I handled the TextChanged event on the internal TextBox control to resize based on my internal TextBlock's size.

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

namespace PresentLight
{
    public partial class ScrollingTextBox : UserControl
    {
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set
            {
                SetValue(TextProperty, value);
                tb.Text = value;
            }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), 
                               typeof(ScrollingTextBox), null);


        public ScrollingTextBox()
        {
            InitializeComponent();
        }

        private void tb_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (hiddenTextBlock != null)
            {
                hiddenTextBlock.Text = tb.Text;
                tb.Width = hiddenTextBlock.ActualWidth;
                tb.Height = hiddenTextBlock.ActualHeight;
            }
        }
    }
}

The result is a marginally better control.  There are a lot of possible improvements for me to make, such as possibly handing the selection changed event on the textbox to scroll the ScrollViewer to the cursor's position.  That will have to wait for a future post.

Sunday, April 13, 2008 9:41:18 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2] -
silverlight
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Matt Casto
Sign In
All Content © 2010, Matt Casto
Theme based on DasBlog theme 'Business' created by Christoph De Baene (delarou)