Sean’s Stuff

29 October, 2010

An Application to Let You View WPF Logical Trees

Filed under: WPF — Sean @ 10:00 pm
Tags: ,

In WPF, a logical tree is just the hierarchy of elements that make up your user interface.  If your user interface is defined in XAML, the logical tree is the set of elements from the XAML, organized into a tree based on their parent/child relationships.

Logical Tree Basics

The logical tree can also be thought of as a model that describes the relationships between objects at runtime.  Knowing the logical tree can be helpful in understanding:

  • Resource lookup
  • Property inheritance
  • Event routing

As an example, the logical tree for the following XAML:

 <Window x:Class="WpfApplication4.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="A window.." Height="350" Width="525">
     <StackPanel>
         <Button Content="Click Me" Height="23" HorizontalAlignment="Left" Width="75" Click="button1_Click" />
         <TextBox />
         <ListBox>
             <ListBoxItem Content="Barley"/>
             <ListBoxItem Content="Oats"/>
         </ListBox>
     </StackPanel>
 </Window>

can be represented by the following logical tree:

You can use the LogicalTreeHelper.GetChildren method to traverse a logical tree and enumerate all of the objects in the tree.

Every element in a logical tree is a DependencyObject, so you pass a top-level object that derives from DependencyObject into the GetChildren method.  The method returns a collection of children of that object.

 // Enumerate each immediate child of main window.  (Does NOT descend down tree)
 foreach (Object obj in LogicalTreeHelper.GetChildren(mainWindow as DependencyObject))
     Debug.WriteLine(obj.ToString());

An Application for Viewing Logical Trees

I wrote a little application that opens a specified .xaml file and then displays the logical tree from that .xaml file in a TreeView.

Here’s what the end result looks like:

To start, you just drag a .xaml file onto the surface of the application’s main window.  It then goes through the following steps:

  • Uses XamlReader.Load method to load the .xaml file into memory, creating objects to represent each element found in the .xaml file
  • Uses LogicalTreeHelper.GetChildren method to traverse the logical tree
  • For each node in the object tree, manually adds type name and (if it exists) object name to a TreeView

Current limitations:

  • Throws an exception if you try to load .xaml that includes an x:Class attribute  (you need to remove the attribute before loading the file)
  • Can’t load .xaml fragments if they don’t include the required XAML vocabulary namespaces
  • Have tested with Window as root element, but no guarantee that it works for other root elements

Where to Find WPF Logical Tree Application

You can find full source code on Codeplex, at wpflogicaltree.codeplex.com.

Under the Covers

The GUI for the application is simple–basically just a Label and a TreeView:

 <Window x:Class="DisplayWpfTrees.MainWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="Drag XAML Files onto This Window to See WPF Logical Tree" Height="350" Width="525" AllowDrop="True"
     Drop="Window_Drop" >
     <ScrollViewer VerticalScrollBarVisibility="Auto">
         <StackPanel Name="spMain" >
             <Label Content="Logical Tree" Height="28" Background="AliceBlue"/>
             <TreeView Name="tvLogical" />
         </StackPanel>
     </ScrollViewer>
 </Window>

You use drag and drop to tell the application to load a .xaml file.  The DragEnter event allows limiting the application to files being dropped.  The Drop event picks up the name of the file being dropped and then calls a helper class to do the loading and initialization of the TreeView.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;

namespace DisplayWpfTrees
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// DragEnter allows prohibiting disallowed formats on drop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effects = DragDropEffects.None;
                e.Handled = true;
            }
        }

        /// <summary>
        /// DragEnter allows prohibiting disallowed formats on drop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effects = DragDropEffects.None;
                e.Handled = true;
            }
        }

        /// <summary>
        /// When file is dropped on window, dump its logical tree to our TreeView
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Drop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

            string filename = files[0];     // Only deal with first one
            FileInfo fi = new FileInfo(filename);

            if (fi.Extension == ".xaml")
            {
                tvLogical.Items.Clear();

               MyLogicalTreeHelper.LoadAndAddXAMLFile(tvLogical, filename);
            }

            e.Handled = true;
        }

    }
}

Finally, the MyLogicalTreeHelper class includes the method LoadAndAddXAMLFile, which does the work of loading the file and building up the TreeView elements.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace DisplayWpfTrees
{
    public class MyLogicalTreeHelper
    {
        /// <summary>
        /// Load loose XAML, creating object graph, then dump that graph's logical
        ///   tree to a TreeView.
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="filename"></param>
        public static void LoadAndAddXAMLFile(TreeView tv, string filename)
        {
            try
            {
                // Load loose XAML file
                DependencyObject root = (DependencyObject)LoadXAMLObjectGraphFromFile(filename);

                // Descend through logical tree, adding items to TreeView
                DumpLogicalTreeToTreeView(root, tv.Items);

                // If root object is Window, we need to call Close method to avoid process from
                //   running indefinitely.  ??
                Window win = root as Window;
                if (win != null)
                    win.Close();
            }
            catch (Exception xx)
            {
                MessageBox.Show(string.Format("Error while trying to load .xaml: {0}", xx.Message));
            }
        }

        /// <summary>
        /// Given filename, use XamlReader to construct XAML objects by reading the file
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        private static object LoadXAMLObjectGraphFromFile(string filename)
        {
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                return System.Windows.Markup.XamlReader.Load(fs);
            }
        }

        /// <summary>
        /// Add children of specified parent to TreeView, under specified node
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="lvi"></param>
        private static void DumpLogicalTreeToTreeView(object parent, ItemCollection tvItems)
        {
            TreeViewItem tvi = new TreeViewItem();
            tvi.Header = XamlElementAsString(parent);
            tvItems.Add(tvi);

            if (!(parent is DependencyObject))
                return;

            foreach (object child in LogicalTreeHelper.GetChildren(parent as DependencyObject))
            {
                DumpLogicalTreeToTreeView(child, tvi.Items);
            }
        }

        /// <summary>
        /// Render a XAML element as a string that contains full type name and optional
        ///   element Name.
        /// </summary>
        /// <param name="theElement"></param>
        /// <returns></returns>
        private static string XamlElementAsString(object theElement)
        {
            string asString;

            // Simple elements (e.g. text content), just convert to string
            if (!(theElement is DependencyObject))
                asString = theElement.ToString();

            else
            {
                // Get full type name
                Type objType = theElement.GetType();
                asString = objType.ToString();

                // Optionally, if the element has a name, append it
                PropertyInfo pi = objType.GetProperty("Name");
                if (pi != null)
                {
                    string name = (string)pi.GetValue(theElement, null);
                    if ((name != null) && (name != ""))
                        asString = string.Format("{0}: ({1})", asString, name);
                }
            }

            return asString;
        }
    }
}

Next Steps

This is all pretty clunky, but it works in a limited fashion.  Obvious next steps include:

  • Data bind the TreeView using HierarchicalDataTemplate, rather than building it up manually
  • Helper class should just build up an object model without having any knowledge of GUI elements (like the TreeView)
  • Automatically strip out x:Class attributes so that files can contain them
  • Better understanding of why process runs indefinitely if you don’t invoke Window.Close
  • Add support for also displaying the visual tree

30 September, 2010

MDC 2010 Takeaways

Filed under: Miscellaneous — Sean @ 4:51 pm
Tags: , , , , ,

I attended the Minnesota Developers Conference (MDC 2010) yesterday in Bloomington, MN.  A nice dose of conference-motivation–some good speakers talking about great technologies.  In the FWIW category, here are my lists of takeaways for the talks that I attended.

1.       Keynote – Rocky Lhotka (Magenic)

General overview of development landscape today, especially focused on cloud computing and the use of Silverlight.  Takeaways:

  • We’re finally getting to a point where we can keep stuff in “the cloud”, access anywhere, from any device
  • Desire to access application data in the cloud, from any device, applies not just to consumer-focused stuff, but also to business applications
  • Smart client apps, as opposed to just web-based, are important/desired – intuitive GUI is how you differentiate your product and what users now expect
  • HTML5 is on the way, will enable smart client for web apps
  • Silverlight here today, enables smart clients on most devices (not iPhone/IOS)
  • Silverlight/WPF is ideal solution.  You write .NET code, reuse most GUI elements on both thick clients (WPF) running on Windows, and thin clients (Silverlight) running web-based or on mobile devices
  • I didn’t realize that I have in common with Rocky: working on teletypes, DEC VAX development, Amiga development. :O)
  • http://www.lhotka.net/weblog/ , @RockyLhotka (Twitter)

2.       WPF with MVVM From the Trenches – Brent Edwards (Magenic)

Practical tips for building WPF applications based on MVVM architecture.  What is the most important stuff to know?  Excellent talk.  Takeaways:

  • MVVM excellent pattern for separating UI from behavior.  Benefits: easier testing, clean architecture, reducing dependencies
  • MVVM is perfect fit for WPF apps, very often used for WPF/Silverlight
  • MVVM perfect fit for WPF/Silverlight, makes heavy use of data binding
  • Details of how to do data binding in MVVM, for both data and even for command launching
  • How to use: data binding, DataContext, Commanding, data templates, data triggers, value converters.  (Most often used aspects of WPF)
  • Showed use of message bus, centralized routing of messages in typical MVVM application.  Reduces coupling between modules.  (aka Event Aggregator).   Used Prism version.
  • Slide deck – http://www.slideshare.net/brentledwards/wpf-with-mvvm-from-the-trenches
  • http://blog.edwardsdigital.com/, @brentledwards (Twitter)

3.       Developer’s Guide to Expression Blend – Jon von Gillern (Nitriq)

Demoing use of Expression Blend for authoring UI of WPF/Silverlight apps.  Also demoed Nitriq/Atomiq tools.  Takeaways:

  • Blend not just for designers; developers should make it primary tool for editing GUI—more powerful than VStudio
  • Lots of tricks/tips/shortcuts – he handed out nice cheatsheet – http://blog.nitriq.com/content/binary/DevelopersGuidetoBlend.pdf
  • Very easy to add simple effects (e.g. UI animations) to app elements to improve look/feel, just drag/drop
  • Nitriq – tool for doing basic code metrics, summaries, visualize code, queries that look for style stuff.  (Free for single assembly, $40 for full )
  • Atomiq – find/eliminate duplicate code, $30
  • http://blog.nitriq.com/, @vongillern (Twitter)

4.       Introduction to iPhone Development – Damon Allison (Recursive Awesome)

Basic intro to creating iPhone app, showing the tools/language/etc.  From a .NET developer’s perspective.  Takeaways:

  • You have to do the dev work on a Mac—no tools for doing the work on Windows
  • The tools are archaic, hard to work with, much lower level than .NET.  (E.g. no memory management)
  • In many cases, consider creating web-baesd mobile app, rather than native iPhone.  But then you wrestle with CSS/browser issues
  • Worth considering creation of native iPhone app for the best user experience
  • Lots of crestfallen-looking .NET developers in the audience
  • http://www.recursiveawesome.com/blog/ , damonallison (Twitter)

5.       A Lap Around Prism 4.0 – Todd Van Nurden (Microsoft)

Showing Prism—a free architectural framework written by Microsoft, came out Patterns and Practices group.  Good for creating extensible apps, with plug-in model.  Takeaways:

  • Leverages MEF (Microsoft Extensibility Framework)
  • Good for apps where you have the idea of a lot of “tools” that plug into main application architecture.  Or for applications made up of various building blocks.
  • You write application modules that are decoupled from main app framework, loaded on demand.
  • Prism on Codeplex – http://compositewpf.codeplex.com/
  • http://www.spoke.com/info/p5rAVze/ToddVanNurden

28 September, 2010

Building A List of Types That Have Content Properties

Filed under: WPF — Sean @ 1:55 am
Tags:

For future reference, here’s a little code snippet that iterates through all types in a Silverlight/WPF DLL and generates a list of types that have a XAML content property.  The list is written out to a file.

As an example, we generate the list for PresentationFramework.dll, which is where the Button type resides.

 // Click handler for a System.Windows.Controls.Button
 private void button1_Click(object sender, RoutedEventArgs e)
 {
     ContentPropsInAssembly(button1.GetType().Assembly, "PresentationFramework.txt");
 }

 private void ContentPropsInAssembly(Assembly assem, string filename)
 {
     SortedDictionary<string, string> dictContentProps = new SortedDictionary<string, string>();

     // Iterate through every type in the assembly, recording those
     // that have content properties.
     foreach (Type nextType in assem.GetTypes())
     {
         ContentPropertyOfType(nextType, ref dictContentProps);
     }

     // Serialize
     using (StreamWriter sw = new StreamWriter(filename))
     {
         foreach (KeyValuePair<string, string> entry in dictContentProps)
             sw.WriteLine(string.Format("{0},{1}", entry.Key, entry.Value));
     }
 }

 // For a given type, determine if it has a content property.  If so, add the name
 // of the type and its content property to a dictionary.
 private void ContentPropertyOfType(Type t, ref SortedDictionary<string, string> dict)
 {
     foreach (object att in t.GetCustomAttributes(true))
     {
         Type attType = att.GetType();
         if (string.Equals(attType.Name, "ContentPropertyAttribute"))
         {
             ContentPropertyAttribute cpa = (ContentPropertyAttribute)att;
             dict.Add(t.FullName, cpa.Name);
             break;
         }
     }
 }

Also for the record, here is the full list of types in PresentationFramework.dll that have content properties, of the format [typename],[propertyname]

MS.Internal.Annotations.Component.HighlightComponent,Children
MS.Internal.Annotations.Component.MarkedHighlightComponent,Children
MS.Internal.AppModel.RootBrowserWindow,
MS.Internal.Controls.InkCanvasInnerCanvas,Children
MS.Internal.Documents.DocumentGridContextMenu+EditorMenuItem,Items
MS.Internal.Documents.DocumentGridContextMenu+ViewerContextMenu,Items
MS.Internal.Documents.ReaderPageViewer,Document
MS.Internal.Documents.ReaderScrollViewer,Document
MS.Internal.Documents.ReaderTwoPageViewer,Document
System.Windows.Controls.AccessText,Text
System.Windows.Controls.AdornedElementPlaceholder,Child
System.Windows.Controls.AlternationConverter,Values
System.Windows.Controls.Border,Child
System.Windows.Controls.Button,Content
System.Windows.Controls.Canvas,Children
System.Windows.Controls.CheckBox,Content
System.Windows.Controls.ComboBox,Items
System.Windows.Controls.ComboBoxItem,Content
System.Windows.Controls.ContentControl,Content
System.Windows.Controls.ContentPresenter+DefaultTemplate,VisualTree
System.Windows.Controls.ContentPresenter+UseContentTemplate,VisualTree
System.Windows.Controls.ContextMenu,Items
System.Windows.Controls.ControlTemplate,VisualTree
System.Windows.Controls.DataGrid,Items
System.Windows.Controls.DataGridCell,Content
System.Windows.Controls.DataGridCellsPanel,Children
System.Windows.Controls.DataGridComboBoxColumn+TextBlockComboBox,Items
System.Windows.Controls.Decorator,Child
System.Windows.Controls.DockPanel,Children
System.Windows.Controls.DocumentViewer,Document
System.Windows.Controls.Expander,Content
System.Windows.Controls.FlowDocumentPageViewer,Document
System.Windows.Controls.FlowDocumentReader,Document
System.Windows.Controls.FlowDocumentScrollViewer,Document
System.Windows.Controls.Frame,
System.Windows.Controls.Grid,Children
System.Windows.Controls.GridView,Columns
System.Windows.Controls.GridViewColumn,Header
System.Windows.Controls.GridViewColumnHeader,Content
System.Windows.Controls.GroupBox,Content
System.Windows.Controls.GroupItem,Content
System.Windows.Controls.HeaderedContentControl,Content
System.Windows.Controls.HeaderedItemsControl,Items
System.Windows.Controls.InkCanvas,Children
System.Windows.Controls.InkPresenter,Child
System.Windows.Controls.ItemContainerGenerator+EmptyGroupItem,Content
System.Windows.Controls.ItemsControl,Items
System.Windows.Controls.ItemsPanelTemplate,VisualTree
System.Windows.Controls.Label,Content
System.Windows.Controls.ListBox,Items
System.Windows.Controls.ListBoxItem,Content
System.Windows.Controls.ListView,Items
System.Windows.Controls.ListViewItem,Content
System.Windows.Controls.Menu,Items
System.Windows.Controls.MenuItem,Items
System.Windows.Controls.Page,Content
System.Windows.Controls.Panel,Children
System.Windows.Controls.Primitives.BulletDecorator,Child
System.Windows.Controls.Primitives.ButtonBase,Content
System.Windows.Controls.Primitives.CalendarButton,Content
System.Windows.Controls.Primitives.CalendarDayButton,Content
System.Windows.Controls.Primitives.DataGridCellsPresenter,Items
System.Windows.Controls.Primitives.DataGridColumnHeader,Content
System.Windows.Controls.Primitives.DataGridColumnHeadersPresenter,Items
System.Windows.Controls.Primitives.DataGridRowHeader,Content
System.Windows.Controls.Primitives.DataGridRowsPresenter,Children
System.Windows.Controls.Primitives.DatePickerTextBox,Text
System.Windows.Controls.Primitives.DocumentViewerBase,Document
System.Windows.Controls.Primitives.MenuBase,Items
System.Windows.Controls.Primitives.MultiSelector,Items
System.Windows.Controls.Primitives.Popup,Child
System.Windows.Controls.Primitives.RepeatButton,Content
System.Windows.Controls.Primitives.SelectiveScrollingGrid,Children
System.Windows.Controls.Primitives.Selector,Items
System.Windows.Controls.Primitives.StatusBar,Items
System.Windows.Controls.Primitives.StatusBarItem,Content
System.Windows.Controls.Primitives.TabPanel,Children
System.Windows.Controls.Primitives.ToggleButton,Content
System.Windows.Controls.Primitives.ToolBarOverflowPanel,Children
System.Windows.Controls.Primitives.ToolBarPanel,Children
System.Windows.Controls.Primitives.UniformGrid,Children
System.Windows.Controls.RadioButton,Content
System.Windows.Controls.RichTextBox,Document
System.Windows.Controls.ScrollViewer,Content
System.Windows.Controls.StackPanel,Children
System.Windows.Controls.TabControl,Items
System.Windows.Controls.TabItem,Content
System.Windows.Controls.TextBlock,Inlines
System.Windows.Controls.TextBox,Text
System.Windows.Controls.ToolBar,Items
System.Windows.Controls.ToolBarTray,ToolBars
System.Windows.Controls.ToolTip,Content
System.Windows.Controls.TreeView,Items
System.Windows.Controls.TreeViewItem,Items
System.Windows.Controls.UserControl,Content
System.Windows.Controls.Viewbox,Child
System.Windows.Controls.Viewport3D,Children
System.Windows.Controls.VirtualizingPanel,Children
System.Windows.Controls.VirtualizingStackPanel,Children
System.Windows.Controls.WrapPanel,Children
System.Windows.Data.MultiBinding,Bindings
System.Windows.Data.PriorityBinding,Bindings
System.Windows.Data.XmlDataProvider,XmlSerializer
System.Windows.DataTemplate,VisualTree
System.Windows.DataTrigger,Setters
System.Windows.Documents.AdornerDecorator,Child
System.Windows.Documents.AnchoredBlock,Blocks
System.Windows.Documents.BlockUIContainer,Child
System.Windows.Documents.Bold,Inlines
System.Windows.Documents.DocumentStructures.StoryFragment,BlockElementList
System.Windows.Documents.DocumentStructures.StoryFragments,StoryFragmentList
System.Windows.Documents.Figure,Blocks
System.Windows.Documents.FixedDocument,Pages
System.Windows.Documents.FixedDocumentSequence,References
System.Windows.Documents.FixedPage,Children
System.Windows.Documents.Floater,Blocks
System.Windows.Documents.FlowDocument,Blocks
System.Windows.Documents.Hyperlink,Inlines
System.Windows.Documents.InlineUIContainer,Child
System.Windows.Documents.Italic,Inlines
System.Windows.Documents.List,ListItems
System.Windows.Documents.ListItem,Blocks
System.Windows.Documents.NonLogicalAdornerDecorator,Child
System.Windows.Documents.PageContent,Child
System.Windows.Documents.Paragraph,Inlines
System.Windows.Documents.Run,Text
System.Windows.Documents.Section,Blocks
System.Windows.Documents.Span,Inlines
System.Windows.Documents.Table,RowGroups
System.Windows.Documents.TableCell,Blocks
System.Windows.Documents.TableRow,Cells
System.Windows.Documents.TableRowGroup,Rows
System.Windows.Documents.TextEditorContextMenu+EditorContextMenu,Items
System.Windows.Documents.TextEditorContextMenu+EditorMenuItem,Items
System.Windows.Documents.TextEditorContextMenu+ReconversionMenuItem,Items
System.Windows.Documents.Underline,Inlines
System.Windows.EventTrigger,Actions
System.Windows.FrameworkTemplate,VisualTree
System.Windows.HierarchicalDataTemplate,VisualTree
System.Windows.Media.Animation.BeginStoryboard,Storyboard
System.Windows.Media.Animation.Storyboard,Children
System.Windows.Media.Animation.ThicknessAnimationUsingKeyFrames,KeyFrames
System.Windows.MultiDataTrigger,Setters
System.Windows.MultiTrigger,Setters
System.Windows.Navigation.NavigationWindow,
System.Windows.Navigation.PageFunction`1,Content
System.Windows.Navigation.PageFunctionBase,Content
System.Windows.Shell.JumpList,JumpItems
System.Windows.Style,Setters
System.Windows.Trigger,Setters
System.Windows.VisualState,Storyboard
System.Windows.VisualStateGroup,States
System.Windows.VisualTransition,Storyboard
System.Windows.Window,Content

9 June, 2010

Generate From Usage in Visual Studio 2010

Visual Studio 2010 comes with the new Generate From Usage feature.  Let’s take a quick look at how it works.

The basic idea is simple.  You can use classes and their methods and properties before you’ve actually implemented them.  This helps support test-driven development, in which you normally write your test cases first and get them to run by stubbing out all of the actual production code.

Top-Down Design

You might also use the Generate From Usage feature as you implement your code, writing the code in a top-down fashion.  The idea of top-down design is that you start writing your application at the highest level, creating abstractions for all lower-level constructs that are too complex to implement at the highest level.

Generate From Usage Example

Let’s look at an example.  In this example, I have a function that takes some basic info about a book as input and then expects to persist that information in a Book object in a database.  Let’s assume that we haven’t yet created the Book class, or any of its methods or properties.  Then my function might look something like this in Visual Studio:

Notice that since we haven’t yet defined the Book class or any of its methods, Visual Studio underlines the Book identifier with a little red squiggle.

If I hover the mouse over the squiggle, I get a nice error message telling me that Book is not defined.

Now let’s just left-click on the squiggle.  A little blue underline shows up at the start of the unknown identifier.

If you now hover over the blue underline, you’ll see a little smart tag show up.

If you click on the smart tag, you’ll see two options: Generate class for ‘Book’ and Generate new type…

The simplest thing to do at this point is to select the first option, to generate a new Book class.  If we pick that option, a Book.cs file will be automatically added to our project, with a skeleton implementation of the Book class.

namespace WpfApplication3
{
    class Book
    {
    }
}

Notice, however, that focus stays in the original code editor window, so you can continue working in the same place.  At this point, the red squiggle on the Book class has disappeared, since we now have a basic implementation of the class.  Also notice that we see a whole bunch of new squiggles.  Now that Book is a valid class, Visual Studio knows that it does not contain any of the properties or methods that we are referencing.

Detour–Generate New Type

Let’s go back a step.  What would have happened if we’d selected the Generate new type… option?  Let’s try it.  If you pick this option, you’ll get a dialog asking you to enter some more details on the class that you want to create.

Basically, you can choose this option if you want to specify some additional details about the class that you want to create, including the file name, which project to create it in, and the access modifier for the class.  You can also have Visual Studio create other constructs, like a struct or an interface.

Return From Detour

Now let’s go back to the EnterBook() method that we were working on.  Remember that after we generated the Book class, we got a bunch more squiggles.  As before, if you hover over the squiggle, you’ll see what the error is.  For example, we didn’t add a non-default constructor to the Book class, so we’re seeing an error when we try to construct the object.

Once again, we can use the Generate From Usage feature to generate some code for us.  As before, click on the squiggle and then click on the smart tag.  Now we see an option to generate the constructor.

Once again, if you click on this option, nothing will appear to happen in the code window where you are working.  But if you open the Book class, you’ll see that it now has a new constructor.

class Book
{
    private string Title;

    public Book(string Title)
    {
        // TODO: Complete member initialization
        this.Title = Title;
    }
}

But notice that Visual Studio went even one step further.  It also created a private field named Title for us and set the value of the field to the book title that we passed into the constructor.  This is (almost) exactly what we want.  (Likely, we’ll want to convert the private field into a property).

Encapsulating a Field

Actually, since I mentioned it, let’s go ahead and convert this field to a property.  First, I’ll rename the field, from “Title” to “_title”.  I do this because I’m going to want my property to be named Title.  So I want my backing variable (the existing field) to be named something else.  Now just right-click on the field, select Refactor and then select Encapsulate Field.

You’ll then get a dialog asking you to confirm the name of the field.

Click OK and then go back to look at your new code in the Book class.

class Book
{
    private string _title;

    public string Title
    {
        get { return _title; }
        set { _title = value; }
    }

    public Book(string Title)
    {
        // TODO: Complete member initialization
        this._title = Title;
    }
}

Perfect!

Generating a Property Stub

Now let’s go back to our EnterBook function again and once again click on a smart tag.  This time, click on the tag for the line where we’re trying to set the LastName property.  You’ll see the following:

Notice that we’re always seeing options that are appropriate for the type of object that is undefined.  In this case, Visual Studio sees that we are using LastName as a property, so it offers to create it for us.

If you select the option to generate a property stub, rather than a field stub, you’ll get what you expect in your Book class:

    public string LastName { get; set; }

Visual Studio created a new property named LastName and automatically generated the get and set accessors for the property.  Also notice that it figured out the correct type for the property, based on the variable that we were assigning to it.

Generating a Method

We’ll do just one more example.  As expected, if you click on the smart tag at the point where we’re trying to call a Save method, Visual Studio will offer to generate the method.

As you’d expect, Visual Studio once again generates a stub in the Book class for us:

    internal void Save()
    {
        throw new NotImplementedException();
    }

Wrapping Up

There you have it–a quick tour through the new Generate From Usage feature in Visual Studio 2010.  Once you get into the habit of using it, you can be quite a bit more productive when coding in a top-down fashion.

4 June, 2010

Silverlight 4 Project Types part III – Silverlight Class Library

Last time, I looked at the Silverlight Navigation Application choice in Silverlight’s New Project wizard.  Next, I’d like to look at the Silverlight Class Library choice.  This is next on the list, out of the six different project types that are listed in the New Project wizard when you pick Silverlight as a project type.

Creating a Class Library

What exactly is a class library?  Well, simply put, it’s a library containing the implementation of one or more classes, implemented as a .NET DLL.  The basic idea is to move basic functionality that you’d likely use in more than one place out to a common library that one or more applications can use.

Silverlight lets us easily create a class library that we can then deploy with our actual Silverlight application.  The class library would contain code that we could invoke from our Silverlight application.

Let’s create a basic Silverlight Class Library using the New Project wizard.  Here’s what the dialog looks like:

Once you enter your project name and click OK, you see the dialog shown below.  This is where you get to decide which version of Silverlight you’re targeting. We saw something similar when creating a Silverlight Navigation Application.

For this project, we’ll stick with version 4 of Silverlight.  Keep in mind that if you author a Silverlight 4 project, the client will need to download Silverlight 4.  If you’re curious about what specific changes were made between Silverlight 3 and Silverlight 4, you can take a look at the article:  Ensuring that Your Silverlight Applications Work with Silverlight 4.  Note the “quirks” mode, in which the Silverlight 4 runtime can behave like Silverlight 3, to avoid breaking applications that targeted version 3.

Here’s what the solution looks like, after the wizard creates it.  Pretty simple.

The obvious question is: how is this different from a standard class library, that you might use with Win Forms or a WPF application?  If we just create a standard class library and then compare the project that we get with our Silverlight Class Library,we see basically the same thing–an empty DLL containing a single class.

One real difference that you’ll notice is related to which assembly references are included in the project by default.  Take a look at the projects shown below.  On the left is a standard C# class library.  On the right is a Silverlight Class Library.  (Nevermind that I’ve changed the default class from “Class1″ to “Cat”.

You’ll see some similarities and some differences.  The main thing to remember is that the Silverlight project is built against the Silverlight versions of all of these libraries, rather than the standard .NET Framework versions.  You can convince yourself that there is more than one set installed one your machine by looking at the directory “C:\Program Files\Reference Assemblies\Microsoft\Framework”.  Make note of the .NET Framework and Silverlight sub-directories, with various version numbers under each sub-directory.  If you drill down into the sub-directories, you’ll see the actual .NET Framework or Silverlight DLLs.  There is a completely different set of DLLs for each platform.  As an example of the differences, note that there is a System.Windows.Forms.dll in the .NET Framework directories, but not in the Silverlight directories.

One other thing to remember is that even when you see the same file in both .NET Framework and Silverlight directories, the content of the file may be different.  For example, the Silverlight version of System.Core doesn’t include the System.Diagnostics namespace, because for Silverlight, it’s implemented in mscorlib instead.

There is another important difference between the different versions of the framework–the Silverlight versions are much smaller than their full .NET Framework counterparts.  Remember that Silverlight needs to be deployed over the web, so its copy of the Framework is considerably smaller than the full .NET Framework.  If you just look on a system that has both and compare total size of the files in each directory, you’ll see:

  • Version 3.0 of the .NET Framework = 84.4MB
  • Version 4.0 of the .NET Framework = 189MB
  • v3.0 of Silverlight framework = 20.6MB
  • v4.0 of Silverlight framework = 24.6MB

So the Silverlight runtime is only about 13% of the size of the full .NET 4.0 Framework.  Pretty amazing.

Adding Some Code

Now let’s add some functionality to our Silverlight class library.  We’ll create a Cat class that we can later use in our Silverlight application.  Here’s the implementation:

public class Cat
{
    public string Name { get; set; }
    public string Motto { get; set; }
    public uint NumLives { get; set; }

    public Cat() { NumLives = 9; }

    public void Die()
    {
        if (NumLives > 0)
            NumLives--;
        else
            throw new Exception("This cat is already dead");

        return;
    }
}

Building the Library

What do we get when we build the library that contains an implementation of our Cat class?  As it turns out, we just get a regular .NET DLL.  Let’s take a look at what shows up in our \bin directory:

Take a look at what’s in this directory.  Using the IL DASM tool (Intermediate Language Disassembler, which can be found in Windows 7 at C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin), crack open the DLL and you’ll see:

We could also look at the manifest for our Silverlight class library and compare it with manifest for a .NET 4.0 version.  If you did this, you’d see that the main difference is the version of mscorlib that they reference.  .NET 4.0 class libraries reference version 4.0.30319 of mscorlib and Silverlight 4 class libraries reference version 2.0.50727.  This could be because of the timing of the Silverlight and .NET 4.0 releases–Silverlight 4 just ended up using the version of mscorlib that shipped with .NET 3.5.  Or maybe it’s the case that Silverlight doesn’t make use of any of the new functionality added to .NET 4.0.

The bottom line here is that both class libraries (.NET 4.0 and Silverlight) are structurally the same–just .NET DLLs.  But they are not interchangeable, because they depend on different versions of various .NET DLLs.

Using Our Class

Now let’s actually use the class that we just created.  We’ll go back to our SilverlightClassLibrary1 solution and add a Silverlight Application project.  We leave the option turned on that automatically generates an ASP.NET Web Application project.

The solution now looks like this:

So we have a web project that loads our Silverlight application and we now want to change the application to make use of our class library.  Specifically, we’ll add some code that makes use of our Cat class.

On the MainPage control in the Silverlight application, we switch to the Events tab in the Properties window and double-click to the right of the Loaded event, to generate an event handler for Loaded.

Next, we add a reference to SilverlightClassLibrary1 in the Silverlight application.  In the Solution Explorer, we right-click the References folder in the SilverlightApplication1 project and select Add Reference.  Then we just click on the Project tab and select SilverlightClassLibrary1.  Now we see the class library show up as a reference in the Silverlight application.

Next, we open MainPage.xaml.cs in the code editor and add a using statement at the top for our class library.   Then we add code to the Loaded event to create a new instance of a Cat.  MainPage.xaml.cs now looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverlightClassLibrary1;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        Cat _garfield;

        public MainPage()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            _garfield = new Cat();
            _garfield.Name = "Garfield Arbuckle";
            _garfield.Motto = "Carpe Catnip";
        }
    }
}

Now let’s do something with our cat.  We go back to the design surface for the main window, add a new button, change the Content property to “Kill” and then double-click on the button to create an instance of the button’s Click event.  The code for the Click event is pretty simple–we just tell Garfield to die.

private void button1_Click(object sender, RoutedEventArgs e)
{
    _garfield.Die();
}

Now we’ve created a Cat and we have a button that lets us kill the cat (repeatedly).  As a next step, let’s just add a label on the main page that indicates how many lives the cat has left.  After you drag the label onto the design surface, it will look like this:

Let’s think about the best way to display the number of lives.  One way would be to add a line in button1_Click() that resets the label’s Content property every time we invoke the Die method.  But the drawback of this is that if we have other places in our code that cause our cats # lives to decrement (or increment), we’d have to remember to add code to all of those places to also update the label.  Better than manually updating the label would be to just “bind” it to Garfield’s NumLives property.  We’d like the label to change automatically whenever Garfield’s NumLives property changes.

Doing the data binding involves two main steps.  The first is to specify the binding of the label’s Content property.  We can set up the binding in XAML, specifying the binding Path, which indicates which property of the Cat object we want to bind this label to.  Below is the XAML for our main page, showing both the Button and the Label.  Note the value of the label’s Content property, with the binding path specified.

<Grid x:Name="LayoutRoot" Background="White">
    <Button Content="Kill" Height="23" HorizontalAlignment="Left" Margin="153,69,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    <sdk:Label Height="28" HorizontalAlignment="Left" Margin="165,26,0,0" Name="label1" VerticalAlignment="Top" Width="63" Content="{Binding Path=NumLives}" />
</Grid>

(For more info on data binding in Silverlight, see this Silverlight Data Binding article in MSDN).

There’s one more thing that we have to do to get the binding to work.  We need to also specify the object that we’re binding to.  In our case, the object is the instance of the Cat that we created in the Load event–Garfield.  We do this by setting the DataContext property of our main page.  Really, we want to set the DataContext property of the Label.  But we can just set the data context for the whole page and then that data context will automatically get used for all controls on the page (if they don’t set their own data context).  This would be handy if we plan on adding other controls later that are also bound to Garfield.  We do this in our Loaded event:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    _garfield = new Cat();
    _garfield.Name = "Garfield Arbuckle";
    _garfield.Motto = "Carpe Catnip";

    // Set data context of main grid to be our Cat object
    LayoutRoot.DataContext = _garfield;
}

Now let’s try running our application.  When the Silverlight application starts up in a web browser, it looks like this:

Hey, that looks like success.  Our Label appears to have been bound to the NumLives property, because it’s showing that Garfield has 9 lives.

But what happens when we press the Kill button?  When I try it, nothing happens.  Inside the Cat object, the NumLives property should be decrementing.  And our Label should reflect the new value, since we set up the data binding.  But the label doesn’t appear to be changing.  Why not?

As it turns out, the NumLives property is changing internally whenever we kill Garfield.  But our client–the MainPage–is not being told that the property changed.  So the data binding isn’t fully functional and the label does not update.

We missed one small step when we set up data binding on our Cat object.  To properly bind to an object’s property, we need our Cat class to implement the INotifyPropertyChanged interface and to fire the PropertyChanged event whenever the NumLives property changes.  (For more info on INotifyPropertyChanged, see the MSDN documentation for INotifyPropertyChanged Interface).

To start with, we change our Cat class definition to indicate that we plan to implement the INotifyPropertyChanged interface.

public class Cat : INotifyPropertyChanged

If you try to build the project now, you’ll get an error telling you that you haven’t implemented the PropertyChanged event.  This is because when we inherit from INotifyPropertyChanged, we’re agreeing to a contract that says we’ll implement the interface’s methods.  In this case, it means that we’ll implement the PropertyChanged event.

The easiest way to implement the event is to right-click on INotifyPropertyChanged and select “Implement Interface”.  Then select “Implement Interface” again.

When you do that, you’ll get the following event declaration added to your code:

public event PropertyChangedEventHandler PropertyChanged;

Next, we need some code that will fire this event.  So we create a little method that we can use throughout our class.  I added the following code after the event declaration:

public void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if (PropertyChanged != null)
        PropertyChanged(this, e);
}

Finally, we need to fire this event whenever the value of NumLives property changes.  We do this by invoking the OnPropertyChanged method that we just implemented.  We also have to pass the name of the property that is changing when we fire the event.  Here is the updated code for the NumLives property:

private uint _numLives;
public uint NumLives {
    get { return _numLives; }
    set
    {
        _numLives = value;
        OnPropertyChanged(new PropertyChangedEventArgs("NumLives"));
    }
}

That should be everything that we need to get the data binding to work.

For reference, here is the full source code listing for our Cat class:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace SilverlightClassLibrary1
{
    public class Cat : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

        public string Name { get; set; }
        public string Motto { get; set; }

        private uint _numLives;
        public uint NumLives {
            get { return _numLives; }
            set
            {
                _numLives = value;
                OnPropertyChanged(new PropertyChangedEventArgs("NumLives"));
            }
        }

        public Cat() { NumLives = 9; }

        public void Die()
        {
            if (NumLives > 0)
                NumLives--;
            else
                throw new Exception("This cat is already dead");

            return;
        }
    }
}

Killing the Cat

Finally, let’s run our application.  Now when we start up the application and run it in browser, we see the # lives indicator decrement whenever we click the Kill button.  Success!

Deployment

Let’s look at one more thing.  When we create and use a Silverlight class library and then deploy and run our Silverlight application, what is really going on?  We saw earlier that we’re creating a DLL.  But what actually happens to that DLL when some client hits the web page that hosts our Silverlight Application?

In Windows Explorer, let’s find the project directory and drill down until we see the ClientBin directory under the SilverlightApplication1.Web project.

In ClientBin dir, we see just one file: SilverlightApplication1.xap.  This is the XAP file that represents our Silverlight application and which gets deployed by the web server whenever a client loads the hosting ASP.NET page.

Let’s take a look inside the .xap file.  (Just rename the extension to .zip and double-click to open the .zip archive).  Here’s what we see:

The important components to notice are SilverlightApplication1.dll and SilverlightClassLibrary1.dll.  SilverlightApplication1.dll is the main DLL that contains our Silverlight application (MainPage class, derived from Silverlight UserControl).  SilverlightClassLibrary1.dll is the output of our SilverlightClassLibrary1 project–a DLL that contains our Cat object.  So we see that when our Silverlight application is deployed, the referenced class library is also deployed to the client, since it is included in the .xap file.

Finally

Now we’ve seen the main purpose of the Silverlight Class Library.  You can create a separate DLL that contains one or more classes that your Silverlight application is going to make use of, when running on the client.  Since the Silverlight application makes use of the class library, the class library is deployed to the client along with the main Silverlight application.

7 May, 2010

Silverlight 4 Project Types part II – Silverlight Navigation Application

Last time, I took a look at what gets created when you create a new Silverlight project and choose Silverlight Application as your project type in the New Project wizard.  Now I’d like to look at the Silverlight Navigation Application project type that is new for Silverlight 4.

As usual, I’d like to walk through the process of creating a new project and then take a quick peek at what’s under the covers.  There are a number of pieces here that are complex enough for their own blog post.  So I’ll probably use the phrase “cover this later” a lot.  My goal right not is to just get a high-level view of the Silverlight Navigation Application.

Just a quick note on the tooling: I’m currently still using the Beta 2 build of Visual Studio 2010.  So some of the behavior or layout might be different from the final release.

Below is an image of the New Project dialog in Visual Studio, showing the new Silverlight Navigation Application choice.  This is the type of project that I’ll be creating.

If you pay attention to the text describing each template, displayed over on the right, you’ll see a slight difference between the Silverlight Application and the Silverlight Navigation Application.

  • Silverlight Application – A blank project for creating a rich internet application using Silverlight
  • Silverlight Navigation Application – A project for creating a rich internet application using Silverlight

So with the Silverlight Navigation Application, you get just a bit more of the framework for an actual production Silverlight application.

If we click OK to continue, we get the familiar dialog for creating a sample web project in which to host the Silverlight application.  As before, we can choose between a Web Application, a Web Site, or an MVC Web Site.  I’ll just pick a Web Application project type.

Note the new checkbox on this dialog labeled Enable .NET RIA Services.  RIA Services (now called WCF RIA Services) is an n-tier design pattern in which you have Silverlight on the client, ASP.NET as the middle tier and then some sort of data tier.  More on this later.  For now, you can get an introduction at the WCF RIA Services home page.  I first heard about RIA Services at Microsoft’s PDC 2008 conference and remembering that it sounded very similar in its goals to Rocky Lhotka’s CSLA.NET for Silverlight framework.

Let’s compare the Silverlight Application and Silverlight Navigation Application projects side by side.  Here’s the high-level view.  (The Silverlight Navigation Application is on the right).

The first difference you’ll notice are the Assets and Views folders in the Silverlight Navigation Application.  Taking a quick peek at these folders, you get an idea of what they contain.

The navigation application adds a Resource Dictionary, Styles.xaml, which serves as a sort of stylesheet for the application.  In the Views folder, we get a new control for displaying errors, ErrorWindow.xaml, and a couple pages where we’ll show our actual web site content, About.xaml and Home.xaml.

We’ll find the biggest changes in the MainPage.xaml file and its code-behind.  But before we take a look at the code, let’s just run our application to see what it looks like so far.

Wow.  That’s slick.  Instead of the blank page that we got with the Silverlight Application, it looks like we get a small, but fully functional web site, implemented entirely in Silverlight.

If you move the mouse around a little bit, you’ll discover that you can click on the home and about labels in the upper right corner of the page to navigate between a Home page and an About page.  When the Silverlight application first starts, we get the Home page.  If you click on the about label, you navigate to the About page.

This highlights that there are two fundamentally different ways to use Silverlight:

  • Silverlight controls embedded in ASP.NET web pages
  • Silverlight as the entire application

In the first case, you create individual Silverlight controls for the areas of your web site where you need a richer user experience and embed them in ASP.NET (or plain old HTML) web pages.  You can think of the Silverlight as little islands of interaction embedded in a traditional ASP.NET web site.

The other basic way to use Silverlight, highlight by the Silverlight Navigation Application, is to make Silverlight handle the entire user experience.  Instead of a web page, you have Silverlight running in the browser as a true RIA (Rich Internet Application).

Which is a better way to use Silverlight?  Neither.  You might consider creating your entire web application in Silverlight, to give your users a richer experience.  But doing that also means that you’re hiding your content in a Silverlight black box that search engines might not be able to crack open to get at the content.  It also means that you’re out of luck for users who haven’t downloaded and installed the Silverlight plug-in.

The Main Page

Ok, let’s go back to the XAML for the main page and figure out how this page navigation is working.

If we’re curious about how things get started, we can go back to the project and note that the App object is listed as the startup object for our application.  If we look at its code behind, we see that it sets the main object to be displayed as an instance of MainPage, just like the standard Silverlight Application.

Before we look in any detail at the MainPage object, let’s take a quick look at how it looked for our standard Silverlight Application–the template that Visual Studio calls a “blank” Silverlight project.  Here’s the XAML:

MainPage is just a UserControl that contains a white grid, onto which you can put anything that you like.  This is the tabla rasa for Silverlight controls.

Now let’s take a look at the same XAML, for the MainPage object, in our Silverlight Navigation Application.  We find that it also derives from UserControl and the XAML consists of a UserControl tag, which contains a Grid.  But this time, the grid is far from empty.

There’s a lot of junk in the XAML for the MainPage control.  But if we strip it down to the main elements, we get the following basic outline (starting with the outer Grid, which is contained in the UserControl):

<pre><Grid Name="LayoutRoot">
    <Border Name="ContentBorder">
        <navigation:Frame Name="ContentFrame">
    </Border>
    <Grid Name="NavigationGrid">
        <Border Name="BrandingBorder">
            <StackPanel Name="BrandingStackPanel"/>
        </Border>
        <Border Name="LinksBorder">
            <StackPanel Name="LinksStackpanel"/>
        </Border>
    </Grid>
</Grid>

This looks a bit busy, but it’s pretty straightforward.  The two main objects in the XAML match the two main areas of the screen that we saw when we ran our Silverlight application–a navigation area at the top of the window that contains the “home” and “about” navigation buttons and then our main content area.  This content area is a container (a Frame object) that will contain our actual content (individual Page objects).

In this XAML fragment, ContentFrame is the container where we put all of our main web page content.  It’s contained, in turn, in a Border object that will add some basic formatting to the frame.

The NavigationGrid object, which contains the navigation buttons, is a little less interesting.  So let’s look first at the ContentBorder and the ContentFrame.

Here’s the full XAML fragment for these guys:

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

The ContentBorder is just a wrapper around the ContentFrame that adds:

  • A margin at the top of the page, making room for the navigation controls
  • A gradient brush for the frame’s background

You can see the details by opening the Styles.xaml file and looking at the ContentBorderStyle style.

The Navigation Frame

The frame object (System.Windows.Controls.Frame) is where all of the magic happens.  MSDN says that this control is a “content control that supports navigation”.

The basic idea of a Frame is that you can tell it the URI of the content that you want to have it display.  You normally do this by setting its Source property or by calling its Navigate method.

When our application first starts up, the Source property of the ContentFrame gets set to “/Home”, since it’s set in the XAML.  This causes the /Views/Home.xaml page to get loaded by default.

But we also load content into the frame when we click on the home and about buttons in the navigation grid at the top of the screen.  These two buttons are actually HyperlinkButton objects.  Here’s the XAML for our about button (you can find this in MainPage.xaml):

<HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
                 NavigateUri="/About" TargetName="ContentFrame" Content="about"/>

The HyperlinkButton lets us navigate to a new web page by specifying a URI and the target control where that URI should get loaded.  In our case, we tell it to load “/About” as the URI in our ContentFrame.  This will have the same effect as if we’d set the Source property of the ContentFrame to “/About”.

So we change the content in the ContentFrame object at three different points:

  • At startup, we navigate to Home.xaml
  • When user clicks on the about button, we navigate to /Views/About.xaml
  • When user clicks on the home button, we navigate to /Views/Home.xaml

URI Mapping

But how is it that we specified “/About” as a URI and we end up at the page /Views/About.xaml”?  When we just specify “/About”, how does the Frame get the exact URI that describes how to find the actual .xaml file?

This happens through something called URI Mapping.  URI mapping simply means that you can map one URI to another, using a simple lookup table.  In general, this is used to map longer URIs to shorter, or internal, URIs.  In our case, when we pass the URI “/About” to our Frame, it uses its UriMapper object to map this URI to “/Views/About.xaml”–the true path to the page that we want to load.

You can see the rule that does this mapping in the XAML fragment above that contains the ContentFrame and XAML elements that specify the UriMapper property of the Frame.  We basically have two rules:

  • Map an empty URI to “/Views/Home.xaml”  (the default/home page)
  • Map “/something” to “/Views/something.xaml”

The second rule is the interesting one.  In the individual UriMapping objects, we can do some basic pattern matching, using one or more variables, denoted by braces.  So the rule lets a user enter just a page name and our mapping fills in the rest.  The mapping rule looks like this:

    <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/></pre>

The whole point here, when we’re talking about user-entered URIs, is that we can hide the details of the URI path from the user and give them something easier to remember and easier to enter.

In the Silverlight Navigation Application example, users aren’t directly entering URIs.  But it still helps to simplify the URIs that we need to specify when setting up the HyperlinkButton objects.

By the way, it’s interesting to note that the Frame class in the main .NET Framework does not support URI mapping, while the Frame class in the Silverlight version of the framework does.

More Fun With Frames

One other very interesting thing about the Frame control is that not only can you tell it to navigate to various pages, but that it remembers its navigation history.  We could then tap into that history and tell the Frame to navigate forward or backward through its history.  For example, I could add a couple of buttons, label them Forward and Back and then add the following code behind.

    private void btnBack_Click(object sender, RoutedEventArgs e)
    {
        if (ContentFrame.CanGoBack)
            ContentFrame.GoBack();
    }

    private void btnForward_Click(object sender, RoutedEventArgs e)
    {
        if (ContentFrame.CanGoForward)
            ContentFrame.GoForward();
    }

We check the CanGoBack and CanGoForward properties before navigating, because if you try to navigate past either the beginning or end of the history, Silverlight will throw an exception.

Even better, the Frame’s navigation history is automatically integrated to the web browser’s history itself (the journal), using the JournalOwnership property.

You can prove this to yourself by running the application generated by the wizard, clicking on the home and about buttons several times and then using the browser’s Back button to see that you can navigate through the pages that you’ve just visited.

This is actually pretty important.  One of the drawbacks of implementing a Rich Internet Application in a black-box technology like Flash is that if you’re navigating between pages, the user loses the ability to use the browser’s navigation buttons to move back/forward through these pages.  Using a Silverlight Frame control addresses this because it ties directly in with the browser’s navigation history.

Wrapping Up

That’s about it for the Silverlight Navigation Application.  The one remaining thing that you can look at is the ContentFrame_Navigated code, in MainPage.xaml.cs. This function is responsible for changing the visual look of the navigation buttons after you click on one of them, to show which content is currently being shown.

The other thing that’s worth doing is opening one of the pages from this project in Expression Blend(As of May, 2010, there is currently a Release Candidate of Blend 4 out that includes support for Silverlight 4).

The easiest way to pop over to Blend from Visual Studio is to just right-click on one of the pages and selected the Open in Expression Blend menu option.

You just click on this option and Blend 4 fires up, opens your project, and then opens the same page in Blend.  Wow.

It’s a good idea to get into the habit of being just as comfortable editing your pages in Blend as you are in Visual Studio.  And that little shortcut in the context menu helps with that quite a bit.

That’s all for now.  Next time I’ll take a look at the next Silverlight project type–the Silverlight Class Library.

7 April, 2010

Project Intro – YAMTS

Filed under: Project YAMTS — Sean @ 5:51 pm
Tags: , , ,

I talked last time about coming up with my own sample application to use as a framework for learning various Microsoft technologies like Silverlight, WPF and WCF.  I ended up deciding on a book tracking web site, books being one of my great passions.  I spent the rest of the post in describing the mission objectives for the yabts.com web site.

Actually, it wasn’t quite a slam dunk to pick book tracking as my sample application.  My second choice, representing another great passion of mine, was to do a web site to track movies and DVDs.  I’m hugely passionate about movies and DVDs and I’ve always wanted a killer app that helped me keep track of DVDs that I own and movies that I’ve seen or want to see.

Since I’m a glutton for punishment, I figure that I don’t have to actually pick just one of these two applications.  Why not build both?

So, with that, here’s my 2nd sample application, also already registered with godaddy.com as a bona fide domain:

yamts.com – Yet Another Movie Tracking Site

Another obviously lovely name.

Mission Statement

As with the book tracking site, the first thing to do is to state what this little movie application is going to do:

The purpose of the movies web site is to keep track of the movies that I own, movies that I’ve seen and the movies that I want to see.

Perfect.  A nice parallel to a book web site.

Mission Objectives

And, just like before, we also need to lay out some “mission objectives”.  This will be a short list of things that my little movie application is going to let a user do:

  • Keep track of all DVDs that I own
  • Keep track of all movies that I’ve seen
  • For the movies that I own, keep track of whether I’ve seen them or not
  • Access a list of all my movies from the web
  • Access all my movie lists from the web
  • Keep track of all movies that I want to see
  • Record my impressions/thoughts, for movies that I’ve seen
  • Keep track of recommended lists of movies to see (e.g. AFI movie lists)
  • Track my progress as I try to see all movies in the lists
  • Share my movie lists with other people
  • Let other people track their own DVDs
  • Let other people track their own lists of movies that they’ve seen or want to see
  • Keep track of movies-seen and movies-to-see for various family members
  • Browse through movies by genre or actor
  • Browse through lists of award-winning movies
  • Organize my DVDs by genre and topic
  • Organize my list of movies to see by genre and topic

Once again, this got a little bit out of control at the end.  But you get the idea.

Where Are We?

There you have it, a second candidate for a sample application.  Next time, we’ll also do some data modeling for this guy, too.

Project Intro – YABTS

As I play around more and more with new technologies like Silverlight, WPF and WCF, I create a lot of little sample applications. Invariably, I start off with little hello-world and click-the-button applications. But Hello World gets old quickly and I’m tired of all the usual suspects when it comes to Microsoft’s lineup of sample applications. (Do you remember these old favorites: Northwind, Fitch & Mather, Duwamish and Adventureworks)? Given how bored I am with these samples, I’d rather just create something that’s closer to a real-world application.

Besides, there’s really no better way to learn a new technology than to try to use it to build something real. Tiny sample apps can only go so far. At some point, you have to roll your sleeves up and actually build something if you want to become really familiar with the technology.

I’m not looking to come up with some big plan for a brilliant new web site here. I just want to pick a problem/domain area that’s sufficiently interesting to me that I’ll be motivated to build something cool.

It also wouldn’t hurt if what I build will be at least marginally useful.

So I have the following requirements:

  • Domain area should be something I’m very interested in
  • Application should be something that I can really use
  • Data model should be sufficiently rich to be interesting

Books

There’s really no contest.  I’m a lifelong bibliophile and I’ve taken many stabs at trying to catalog and organize my book collection over the years.  I’m guessing that I’ve started scratching out a database schema for a Books-I-Own database at least a dozen times in the past 20 years.  Just give me a boring corporate meeting and a sheet of paper with a little whitespace on it and I’ll invariably start sketching out an entity relationship diagram.

So that’s my choice for a sample real-world application: a book tracking application/site.

Mission Statement

Let’s start off by at least defining what this thing is going to do. For the moment, let’s assume that this is going to be some sort of database-backed web site.

Here’s my mission statement:

The purpose of the books web site is to keep track of the books that I own, books that I’ve read and the books that I want to read.

Short but sweet and even a little bit ambitious in its scope.

How About a Name

I’ll get tired pretty quickly of calling this thing “the books database” or “the books web site”.  So we need an honest to God site name with an associated domain name.

This is the point in a new project, even a sample project, when you can easily lose many hours on the godaddy.com site, trying to find a domain name that doesn’t suck and has at least a couple of vowels.

I won’t waste my time trying to find the holy grail of domain names for my little book database project.  Instead, I’ll just pick something sort of short that I think I can remember.  After 10-15 mins of godaddy’ing, here’s what I came up with:

yabts.com – Yet Another Book Tracking Site

That’s perfect:  an honest-to-God 5-letter domain name that I can actually remember.

Mission Objectives

The next step is to define some basic “mission objectives”.  These are the very high-level statements of what my little application is going to do.  I’ll try to stay very firmly in the realm of What, rather than How.  I’m also allowing myself to be a little bit ambitious or even grandiose–this is my “dream list” for the book tracking site that I’ve always wanted.

YABTS Mission Objectives:

  • Keep track of all the books that I own
  • Keep track of books that I want to buy
  • Keep track of all books that I’ve ever read
  • Keep track of recommended reading lists
  • Keep track of specific books that I’d like to read
  • For the books that I own, track whether I’ve read them or not
  • Record my personal thoughts (review) for the books that I’ve read
  • Store specific notes on some of the books that I’ve read
  • Track book lists and collections for other people, too
  • Publish my book collection information to the web
  • Keep track of books that people have borrowed from me
  • Share reviews of books that I’ve read with other people
  • Find other readers who share similar book interests
  • Track my progress as I work through “great book” lists
  • Let people browse the “great book” lists all in one place
  • Let people create their own recommended reading book lists
  • Organize my reading lists by subject
  • Organize my book collection by subject

Okay, I had to pull the plug on the idea-generating fairy after about 5 minutes.  What started out as a simple list of books that I own just kept growing and growing as I thought of more and more “must have” features.  But this list will do fine for now as a starting point.

Where Are We?

That should do for the time being.  I now have a vision for a sample application that I can actually get sort of excited about.  I’ve made a list of all the stuff that my application should do and I’ve payed my  money to godaddy.com to get my domain name.

Next time, I’ll continue by diving into some actual data modeling.

20 March, 2010

Silverlight 4 Project Types part I – Silverlight Application

Ok, let’s take a look at the different types of Silverlight applications that you can create out-of-the-box with Visual Studio 2010.  Now that I’ve installed Visual Studio 2010 and Silverlight 4, I want to take a quick spin through each of the different project types that the New Project wizard makes available.

After firing up Visual Studio 2010, I click on the New Project link and then select the Silverlight project type under C#.  Here’s the default list that I see:

  • Silverlight Application
  • Silverlight Navigation Application
  • Silverlight Class Library
  • Silverlight Business Application
  • WCF RIA Services Class Library
  • Silverlight Unit Test Application

I’d like to take a quick look at each project type, looking at the pieces that make up the project and then thinking a little bit about when to use that particular project type.  As I walk through the various project types, I’d also like to think a little bit about the ecosystem in which the Silverlight application lives.  In other words, what other components might you typically create when designing a solution of that type?

I also want to think a little bit about the tooling.  What tools would you typically use to work on the project that you’re creating?  Would Visual Studio 2010 alone be sufficient?  Or would you spend a lot of time working in Blend?  What about SQL Server 2008?

The Silverlight Application

The first project type—the Silverlight Application—looks like it might be the same thing that I created with Visual Studio 2008 and Silverlight 2, back in the Hello Silverlight World, Part 1 post.

The New Application dialog that we see next is very similar to what I saw with Visual Studio 2008 and Silverlight 2.  As before, we have to host our Silverlight application somewhere.

Notice that this time we have one additional project type that we didn’t have before—an ASP.NET MVC Web Project.  So we can basically go with a “classic” ASP.NET web site or an MVC web site.

The default is to host Silverlight in a new ASP.NET web application project.  But if I uncheck the first checkbox, I get a simple Silverlight project with no containing web site:

If you go this route and then press F5 to “run” your Silverlight application, Visual Studio will just create a test .html page in which to host your Silverlight control.

If you take a look at this page, you’ll see a simple HTML page with a familiar <object> tag hosting the Silverlight control.  (See my post on the Lifecycle of a Silverlight Control for more details on how this is done).

If we instead go with the defaults on the New Silverlight Application dialog (host the Silverlight Application in a new ASP.NET Web Application project), we end up with a simple ASP.NET project that contains both .html and .aspx pages hosting the new Silverlight control.

In either case, .html or .aspx, your Silverlight application is embedded in the web page

<div id="silverlightControlHost">
 <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
 <param name="source" value="ClientBin/SLApp1.xap"/>
 <param name="onError" value="onSilverlightError" />
 <param name="background" value="white" />
 <param name="minRuntimeVersion" value="4.0.41108.0" />
 <param name="autoUpgrade" value="true" />
 <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.41108.0" style="text-decoration:none">
 <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
 </a>
 </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>

As I describedin The Lifecycle of a Silverlight Control, this <div> tag embeds your Silverlight application (control) into a web page using the application/x-silverlight-2 MIME type.  This MIME type now maps to the AgControl.AgControl.4.0 class, implemented in npctrl.dll, which can be found in C:\Program Files\Microsoft Silverlight\4.0.41108.0.

Visually, the pieces of the puzzle look like this (from MSDN article on Silverlight 4.0 Application Services):

So as before, a Silverlight application is managed code that runs in the context of a browser plugin.  Here’s how things work when your browser renders a page containing a Silverlight control:

  • Browser renders HTML  from .html page (or generated HTML from ASP.NET page)
  • Browser sees <object> tag for application/x-silverlight-2 MIME type and fires up the Silverlight plug-in
  • Silverlight plug-in loads the Silverlight core services
  • Silverlight plug-in loads the Silverlight CLR, which creates an AppDomain for your application
  • .xap file containing your Silverlight application is downloaded from the server
  • Your application manifest is loaded/read (from AppManifest.xaml, in .xap)
  • Your main Silverlight application DLL is loaded (from .xap)
  • Silverlight CLR instantiates your Application object and fires its Startup event
  • Your application’s Startup event creates a new instance of your main page (a Silverlight UserControl)
  • Your main page (e.g. MainPage in wizard-generated project) renders itself by reading/loading its .xaml file

Voila.  At the end of all this, you get a Silverlight Application rendered in an ASP.NET web page.  In our case, having generated everything using the Project Wizard, we can just press F5 to run the application–launching a browser window and loading your auto-generated ASP.NET page.  It looks like this (the Silverlight application has the green background):

The XAP Payload

One final topic to cover quickly is–what exactly does the downloaded .xap file contain?  In our wizard-generated test project, you’ll find a ClientBin directory, which contains the compiled Silverlight application in a .xap file.  In our case, it’s named SLApp1.xap.

If you just rename the .xap file as SLApp1.zip and double-click on it, you can see what it contains:

The main pieces here are the application manifest, which tells the Silverlight runtime what object to start up first, and the assembly in which that object lives.  The .xap file also contains the assembly (SLApp1.dll) that contains our actual code.

The .xap file also contains some dependent DLLs, which are sent down to the client as part of the .xap package.

Wrapping Up

That’s all there is to a basic Silverlight Application.  Next time, I’ll take a look at the Silverlight Navigation Application, which lets us create a complete Silverlight application with multiple pages, rather than a single user control.

9 January, 2010

Creating a Silverlight 4 Development Machine

Filed under: Blend,Silverlight,Visual Studio — Sean @ 5:11 am
Tags: ,

Now that a Silverlight 4 beta is available, it’s time for me to create a new VM where I can develop Silverlight 4 applications.  This development machine will be based on Windows 7 and include:

  • Visual Studio 2010 Beta 2
  • .NET Framework 4 Beta 2
  • Silverlight 4 Beta
  • Expression Blend for .NET 4 Preview

As of January, 2010, this represents the most complete development environment possible for Silverlight 4 applications.

Operating System

I’ll be installing into a virtual machine environment, using VMware Workstation 6.5.1, running on top of Windows 7 (the host operating system).  The guest operating system, where I’ll be installing the development tools, will be Windows 7 Ultimate.

Both my host and guest machines are 32-bit (x86).

Here’s our “clean slate”–a fresh install of Windows 7 Ultimate with nothing else yet installed:

Fresh Install of Windows 7

It’s a beautiful sight.

Overview

Here’s a complete list of what I’ll be installing in the Windows 7 virtual machine:

  1. Visual Studio 2010 Ultimate Beta 2 (x86)    (19 Oct 2009)
  2. Silverlight 4 Beta Tools for Visual Studio 2010    (2 Dec 2009)
  3. Microsoft for Expression Blend for .NET 4 Preview    (16 Nov 2009)
  4. Silverlight Toolkit    (18 Nov 2009)
  5. WCF RIA Services for Visual Studio 2010 Beta 2    (3 Dec 2009)

I’ll include a link to the location of each tool in the sections below.

Install Visual Studio 2010

I got my copy of Visual Studio 2010 through my MSDN subscription, but you can get a free copy (“Go Live” license) here:

Download Visual Studio 2010 Beta 2

I haven’t tried downloading Visual Studio 2010 from this location, so I’m not sure what edition you get.  But even if it’s one of the Express editions, it ought to be fine for developing Silverlight 4 applications.

We start by launching the VS 2010 installation.

Visual Studio 2010 Installation

The installation begins.

Loading Components

We agree to the license, after carefully reading it.

License Agreement

Next, we choose either a Full or Custom installation.  I always go with Custom, so that I can turn off stuff that I don’t want.  Notice that the default installation takes up 6.4 GB.

Custom Installation

The next screen lets me select individual components to install.  It looks like everything is selected by default.

Select Features to Install

Here are my preferred choices.  I have no interest in VB, VC++ or F#.  For now, I’ll just stick with C#.  I do include the Office Development tools, but don’t need the Dotfuscator feature or SharePoint development tools.  I also uncheck SQL Server 2008 Express, since I’ll later install a full version of SQL Server 2008 when I need it.  This brings the install footprint down to 3.6 GB.

My Selected=

The installation process now starts.  It will take a while, since we have a lot of different components to install.

Installation Begins

A reboot is required after installation of the .NET Framework.

Reboot Required

By the way, it’s interesting to note that version 4 of the .NET Framework actually updates the core components of the .NET Framework.  This was not true of version 3.0 or 3.5, which were both just releases that added to existing functionality.  So 4.0 represents the first time that core libraries have been updated since the 2.0 release in Nov, 2005–just over four years ago.

New Core Libraries

Nearly done now..

Installation Nearly Complete

And the installation is now complete.

Installation Complete

Install Silverlight 4 Beta Tools for Visual Studio 2010

Visual Studio 2010 includes support for Silverlight 3, rather than Silverlight 4.  Because Visual Studio 2010 ships a bit earlier than Silverlight 4 (Visual Studio 2010 shipping in March, 2010 and Silverlight 4 shipping sometime in the first half of 2010), Visual Studio 2010 will support Silverlight 3 rather than Silverlight 4.

You can download the Silverlight 4 Tools for Visual Studio from the link below.  Note that this version of the Silverlight 4 tools works only with Beta 2–not Beta 1.

Download Silverlight 4 Beta Tools for Visual Studio 2010 Beta 2

The install starts:

Silverlight 4 Tools Install

There’s another license agreement to read and accept.

License Agreement

The install begins.

Install Begins

And we’re done..

Install Expression Blend Preview for .NET 4

There is a free preview download of Expression Blend that supports targeting both Silverlight 4 Beta and .NET 4 Beta 2.  It is listed as being compatible with Visual Studio 2010 Beta 2 and can be found at:

Download Expression Blend Preview for .NET 4

This is version 3.1.11111.0 of Expression Blend.  It supports creation of both Silverlight 4 Beta and .NET 4 Beta 2 content, but does not support creation of Silverlight 3 or .NET 3.5 content.  It also does not include SketchFlow.

Note: If you are installing the tools to a virtual machine running in VMware Workstation, you may need to make a change in your display settings for the virtual machine before launching the Expression Blend install.  If the 3D graphics setting is enabled for the VM, the Blend install program may not display properly.  Under VMware Workstation 6.5.1, I’ve seen this problem consistently.  The fix is to disabled the 3D graphics setting for the VM.

3D Graphics Setting

One you disable 3D graphics, the first dialog in the install program will display properly.

Blend Install Starts

The Blend install dialogs are certainly beautiful.

Blend Install

The installation starts:

Installation in Progress

And the installation finishes quite politely.

Thank You

Install Silverlight Toolkit

Next, we install the Silverlight Toolkit, which includes a number of additional Silverlight Controls.  You can find the toolkit on CodePlex.

Download Silverlight Toolkit

The install says that this is the toolkit for Silverlight 3, but the Nov, 2009 release has been updated to include support for Silverlight 4.

Toolkit Install Starts

Yet another license agreement.

Toolkit License Agreement

You next get a chance to decide which components of the toolkit to install.

Silverlight Toolkit Features

Ready to start the install now.

Ready to Install

The Silverlight Toolkit install in action:

Install in Progress

And we’re done.

Install Finishes

Install WCF RIA Services

Next, we install the WCF RIA services, which is a framework that allows writing n-tier ASP.NET/Silverlight applications.

You can find the WCF RIA Services install at:

Install WCF RIA Services for Visual Studio 2010 Beta 2

The link above allows you to download and install the WCF RIA Services.  However, I noticed that when I got to this point, it was already installed.  As it turns out, the install for the Silverlight 4 Beta also installed the WCF RIA Services preview.

Documentation

We’ve now downloaded everything that we need for creating Silverlight 4 applications.  One remaining piece of information that will be helpful is that the Silverlight 4 documentation can be found online at:

Silverlight 4 Documentation

Wrapping Up

There we go.  I now have a clean virtual machine that has everything on it that is needed for creating Silverlight 4 applications.  My one last remaining task is to go and save a snapshot of the VM, so that I preserve the “clean” Silverlight 4 development environment.

2 July, 2009

Silverlight Gets Full-Fledged Designer Support in Visual Studio 2010

Filed under: Silverlight,Visual Studio — Sean @ 5:55 pm
Tags: ,

Trying to wrap my head around the current situation with Silverlight 2 and 3 support in Visual Studio 2008 and 2010, I’m confused enough that I feel like shouting out a line from my daughter’s favorite Dr. Suess book, Fox in Socks:  “Now wait a minute, Mr. Socks Fox”!!

It is a little confusing.  But I think I now understand who supports what and I’ll take a stab at jotting it down, for future reference.

Visual Studio 2008 SP1

Visual Studio 2010

  • Supports both Silverlight 2 and Silverlight 3
  • Can install both on the same development machine
  • Each Silverlight project targets one of the two Silverlight versions
  • Silverlight 2 — need to install the Silverlight 2 SDK manually
  • Silverlight 3 — install manually

Ok, as far as I can tell, that’s the current situation.

This basically boils down to two questions:

  • Do I want to develop in Silverlight 2 or Silverlight 3?
    • Silverlight 2 is more stable and is officially released
    • Silverlight 3 (beta) — new controls, navigation framework, out-of-browser support
  • Which version of Visual Studio do I want to use?
    • VS 2008 — easier install experience, stable/released
    • VS 2010 — improved tooling for Silverlight & WPF

The last point is what I want to talk about.  Notice that improved tooling for Silverlight is a feature of Visual Studio, not of Silverlight itself.  Visual Studio 2010 finally gives us full design-time drag-and-drop support for Silverlight.

Let’s see what this looks like.  But first, let’s go back and take a look at the Silverlight design-time experience in Visual Studio 2008.  (I’m using Silverlight 3 here).

The Bad Old Days – Visual Studio 2008 SP1

Until now, Silverlight developers haven’t had the most basic tooling enjoyed by even the lowliest VB6 developers.  Namely — the ability to drag and drop controls onto a design surface and set their properties right in the designer.

Specifically, here’s what you couldn’t do.  If you look at the split window for Silverlight controls in the designer, you’ll notice that the upper pane is labeled “Preview”.

Preview Pane

This was a “Preview” pane because all it could do was to render your XAML on the screen as a preview of how it would eventually look in your Silverlight application.  You couldn’t drag controls onto this surface.  You also couldn’t select any controls in order to reposition them or to set their properties.

In Visual Studio 2008, if you try dragging Silverlight controls onto this Preview window, you just get a big fat “don’t do this” icon.  Even sadder, you can’t select any controls.  If you look at the properties window in Visual Studio, you just see the following sad message:

No Property Editing

Thankfully, you could at least drag and drop controls down into your XAML.  This would at least insert the proper XAML tags for the control that you’d selected.  But you just got an empty tag.  (In the picture below, I’ve just dragged a Button into my XAML).

Drag Into XAML

And, although we weren’t able to set property values in the property editor, there was some consolation in that Intellisense worked in the XAML code.

Intellisense in XAML

So the Silverlight development environment was workable, but not ideal.  Also, you could always author/edit your UIs in Expression Blend.  But then there was a big learning curve to tackle.

Enter Visual Studio 2010

In Visual Studio 2010, we finally have full designer support for Silverlight applications.  In the picture below, I’ve just dragged a Button from the toolbox onto the design surface.

Silverlight Design Surface

It makes me want to weep.  (Who would have thought that a developer would be so happy with being able to drag a button onto a form)?

Not only did the designer let me drag the button onto a design surface, but now it actually gives me a little more than an empty/default Button tag in my XAML.  I actually get a sensibly configured button object, with a reasonable size and a preset label.  Also notice that the upper pane is now labeled “Design”, rather than “Preview”.

But don’t weep yet.  It gets better.  You can actually left-click to select the button in the designer.  When you do this, you’ll see that you can now actually set properties for the button in the property window.

Property Window

Now you may weep or cheer, depending on your particular emotional reaction.

You’ll also notice that you can now click on the little event icon and then double-click to generate event handlers in your code-behind.  (As opposed to using Intellisense in the XAML to discover relevant events).

Event Properties

This is great, although I still don’t understand why there is no dropdown in the properties window to select the individual controls.  Is there a good reason why neither WPF or Silverlight applications allow selecting individual controls from the property window?

Also note that all of the above is possible in both Silverlight 2 and Silverlight 3.

Where Are We?

So clearly, Silverlight is now a full-fledged citizen in Visual Studio, with full tooling.  This may not seem like much, but for anyone who works with Silverlight a lot, it will make a huge difference.  Not to mention a much shallower learning curve for developers coming up to speed with Silverlight.

Mr. Socks Fox wasn’t spouting blibber blubber after all.

30 June, 2009

Installing Silverlight 3 with Visual Studio 2010 – Step by Step

Filed under: Silverlight,Visual Studio — Sean @ 6:01 pm
Tags: ,

[Note, 21-May-2010.  Silverlight 4 has been released.  For a step-by-step guide to installing Silverlight 4 with Visual Studio 2010, see my post Creating a Silverlight 4 Development Machine].

A beta version of Silverlight 3 was released at MIX09 in March.  Since a beta version of Visual Studio 2010 was also just released–in May–it makes sense to set up a Silverlight 3 and Visual Studio 2010 development environment.  My last post included screenshots of the installation process for Visual Studio 2010.  This post will cover installing the remaining bits needed for a Silverlight 3 development environment.

Note: Also take a look at the official Getting Started page for Silverlight 3.

This post will describe installing Silverlight 3 bits on top of a clean Windows 7 / Visual Studio 2010 environment.  I won’t install the Silverlight 2 components, so the resulting environment will be targeted exclusively at Silverlight 3.

At the moment, the Silverlight 3 beta is targeted at Visual Studio 2008 SP1, rather than Visual Studio 2010.  (See Tim Heuer’s blog post explaining this).  What this means is that we can’t just run the Silverlight 3 Tools installer.  If you try, you’ll get the following error.

Can't Install on VS 2010

Installing the Silverlight 3 Beta SDK

Instead, you’ll need to just install the Silverlight 3 Beta SDK manually.  Once you download the SDK installer and launch it, you’ll get the following screen:

SDK Welcome

Then you get a license dialog.  Note the comment about this beta license expiring 30 days after the commercial release of Silverlight 3, but no later than 30 Sep, 2009.  Does this imply that we’ll see a final release of Silverlight 3 by 30 Aug, 2009?

License Dialog

If you do a custom install, you’ll see the following features and components listed:

Custom Install

Here’s a quick summary of what is being installed:

  • Silverlight Tools – Components needed for building Silverlight applications
    • The core Silverlight DLLs, e.g. agcore.dll, coreclr.dll, et al
  • Build Components – Components used to build Silverlight projects
    • Microsoft.Silverlight.Build.Tasks.dll,  et al
  • Client Libraries – Silverlight Client Libraries and Controls
    • System.Xml.Serialization.dll, System.Xml.Linq.dll, System.Windows.Controls.Navigation, et al
  • Server Libraries – Silverlight Server Libraries and Controls
    • System.Web.Silverlight.dll, et al

Now we’re ready to install:

Ready to Install

Install continues:

Installing

The install completes, and a dialog reminds us that the actual Silverlight 3 Beta runtime is not yet present.  (Actually, there is an error in this dialog — it’s reminding us that the Silverlight 2 runtime is not present).

SDK Done

Installing the Silverlight 3 Developer Runtime

Now we need to install the actual Silverlight 3 runtime, which you can download from here.

We start with the familiar Silverlight install splash screen (now branded as Silverlight 3 for Developers).

For Devs

Off we go..

Installing Runtime

The runtime install completes quickly.

Runtime Installed

Pretty simple.  You now have all of the important stuff that you need for developing Silverlight 3 applications with Visual Studio.

Building a Silverlight Application with Visual Studio 2010

When you bring up the New Project wizard in Visual Studio, you’ll see two types of Silverlight projects listed:

  • Silverlight Application
  • Silverlight Class Library

New Project

If you create a new Silverlight Application, you’ll see the Add Silverlight Application dialog.  But notice that there is now a dropdown labeled Silverlight Version.  This defaults to Silverlight 2.0, but you can select Silverlight v3.0 to create a Silverlight 3 application.

Create Silverlight 3 Application

You’ll see a similar dialog if you try to create a Silverlight Class Library.

Create Silverlight Class Library

The Silverlight Navigation Application

But notice that there is one Visual Studio template that shows up if you install Silverlight 3 Beta in Visual Studio 2008 SP1 that does not show up in Visual Studio 2010 — the Silverlight Navigation Application.  This is installed as part of the Silverlight 3 Tools installer, which we were unable to run.

We need to pull this particular template from Visual Studio 2008 SP1 into Visual Studio 2010.  To do this, install the Silverlight 3 Tools installer on a machine that is running Visual Studio 2008 SP1.  Then fire up Visual Studio 2008, create a Silverlight Navigation Application project, and select Export Template from the File menu.

Export Template

You’ll see a dialog asking you to select the project to export a template for.  We’ll select the main navigation application.

Export Template

You can also give the new template a description and select an icon.

Template Part II

When you’re done, a new Windows Explorer window will pop up, containing a .zip file for your new template.  Now copy this .zip file to the following directory on your Visual Studio 2010 machine:

C:\Users\myname\Documents\Visual Studio 10\Templates\ProjectTemplates\Visual C#

Now when you bring up the New Project wizard in Visual Studio 2010, you’ll see a new template that you can use to create a Silverlight Navigation Application.

New Template in Action

Wrapping Up

That should do it — you now have a fully functional Silverlight 3 / Visual Studio 2010 environment.

Technorati tags: Silverlight, Silverlight 3, Visual Studio 2010

29 June, 2009

Visual Studio 2010 Install Screenshots

Filed under: Visual Studio — Sean @ 5:57 pm
Tags: , ,

Beta 1 of Visual Studio is now available on MSDN.  (If you have the appropriate MSDN subscription).  Here is a complete set of screenshots, outlining the installation experience.

Note: I installed VS 2010 Beta 1 on a clean virtual machine running Windows 7 Build 7100 (RC).

We start with the familiar install startup menu:

First screen

Then we get a banner page, as things start up.

Install Banner

Next, we get a license page, as well as an overview of what is going to be installed.  The key components are:

  • VC 9.0 and 10.0 runtime libraries
  • .NET Framework 4 Beta 1    (more info)
  • Help 3.0 Beta 1    (more info)
  • Visual Studio Macro Tools
  • Visual Studio 2010 Professional Beta 1    (more info)

License Page

Next up is an options page:

Options Page

Now the actual installation begins and we can see a more complete list of all the components that will be installed.  For completeness, here’s the full list:

  • VC 9.0 Runtime
  • VC 10.0 Runtime
  • Microsoft .NET Framework 4 Beta 1
  • Microsoft Help 3.0 Beta 1
  • Microsoft Visual Studio Macro Tools
  • Microsoft Visual Studio 2010 Professional Beta 1
  • Microsoft Web Deployment Tool
  • Visual Studio Tools for the Office System 4.0 Runtime
  • Microsoft Office Development Tools for Visual Studio 2010
  • Dotfuscator Software Services – Community Edition
  • Microsoft SQL Server Compact 3.5 SP1
  • SQL Server Compact Tools for Visual Studio 2010 Beta 1
  • Microsoft Sync Framework Runtime v1.0
  • Microsoft Sync Services for ADO.NET v2.0
  • Microsoft Sync Framework Services v1.0
  • Microsoft Sync Framework SDK v1.0
  • Microsoft SQL Publishing Wizard 1.4
  • SQL Server System CLR Types
  • Shared Management Objects
  • Microsoft SQL Server 2008 Express Edition

Wow.  This is going to take a while.

Installation Begins

You’ll have to reboot after the .NET Framework 4 installation.

Reboot Required

Go get a cup of coffee while the remaining components install..

Coffee Break

You’ll get a warning dialog, indicating that SQL Server 2008 has compatibility issues on Windows 7 and suggesting that you install SP1.

Compatibility

I just clicked the Run Program button and proceeded with the install.  A little bit later, I got a second compatibility warning dialog, also mentioning SQL Server 2008.  An external DOS window was also spawned, running a setup.exe command.

Compatibility #2

Finally, everything finishes up and we’re done!

Installation Complete

After the install completes, we get the main autorun window again and the link for checking for service releases is now active.

Autorun #2

If you click the Check for Service Releases link, you’ll be redirected to an update web page, which in turn allows firing up the Windows Update applet.  When I tried this (29 Jun 2009), no updates were found.

Finally, we bring up Visual Studio 2010 for the first time.

Splash Screen

As with earlier versions, when you start Visual Studio for the first time, you’re asked to choose a language, which dictates how the environment is set up.  I’m a C# guy.

When things finally start up, we see the new Start Page for the first time.

Start Page

The New Project dialog also gets a fresh look.

New Project

Finally, we create an empty WPF Application.

WPF Application

8 June, 2009

Quick Tip – Making Windows on 2nd Monitor Visible

Filed under: Windows — Sean @ 5:00 pm
Tags: , ,

I’m a big believer in using two (or even three) monitors on my main development machine.  I have two monitors on my home development machine (24″ Dell and 22″ off-brand) and having the extra real estate of that second monitor is invaluable.  I use it often, putting different applications over on the 2nd monitor and then dragging-dropping work/files between the monitors.

But I have a slight problem when I remote into my home machine from work.  Windows 7 supports mapping multiple monitors on the remote machine to multiple monitors on the local machine.  But at work, I just use a single monitor.  So I only see the windows that are being shown on the main monitor of my home machine.

The problem arises when I click on an icon in the taskbar to see a window and it doesn’t show up–because it exists on my second monitor.  Because I’m only seeing my main monitor, I don’t see the application’s window and can’t click on it.

The fix is simple.  Do the following:

  • Left-click on the application’s icon in the taskbar, to make it active
  • Right-click on the icon in the taskbar and select Move
  • Click one of the arrow keys once (it doesn’t matter which)
  • Now move your mouse–you’ll see an outline of the application appear on the screen and you can place it where you like

This works on both Windows XP and Windows Vista.  Windows placement in Windows 7 works a bit differently, so I’m not exactly sure the best way to do this in 7.

21 May, 2009

.NET Basics – Do Work in Background Thread to Keep GUI Responsive

One of the most important things that differentiates a “quick and dirty” application from one that has been designed well is how the application’s user interface behaves during lengthy operations.  The quick-and-dirty approach is to just do all of your work in a button’s Click event handler and not worry about the user interface.  The problem with this is that the GUI will freeze up while the application does whatever work it needs to do.

A well designed application, on the other hand, is one that is careful to do as much work as possible in background threads, keeping the GUI responsive and making sure that it makes it obvious to the user that work is going on in the background and adjusts the GUI to disallow any user actions that don’t apply until after the work finishes.

Under .NET 2.0, doing work on a background thread has become a lot easier, with the introduction of the BackgroundWorker class.  You no longer have to worry about cross-threading exceptions and checking a control’s InvokeRequired property.

A Simple Example of Using the BackgroundWorker Class

In this post, I’ll create a simple example of how you might use the BackgroundWorker class to do some work on a background thread and keep your GUI responsive.  We’ll start with a simple example that demonstrates how the GUI can become blocked and then evolve the application to make full use of the capabilities of the BackgroundWorker class.

Here are the basic players. We’ll have a FileReader class/object that reads text from a text file. And a Win Forms form with a button to initiate the file read operation and some GUI elements to display the status/results of the read operation.

Note: All code samples presented here can be found in CodePlex, at threadsafepubsub.codeplex.com

Iteration #1 – The Simplest Possible Solution

Let’s say that we just want to read a text file and return/display the number of lines found in the file. We can just make a call to our FileReader object, which returns the number of lines, and then display that number in our UI. Super simple.

This iteration is implemented in the files Form1.cs and FileReader1.cs.

Here’s what the GUI looks like.  If you click on the Read File button, you get a File Open dialog where you can select a file to read.  The file is read in and then we write out the # lines read, below the button.

001-Iter1Client

So far, so good.  This is how most simple user interfaces are written–you click on a button, which launches a Click callback, which does some work, and then returns to the caller.

Here’s what the FileReader1 class looks like, with a simple ReadTheFile method:

using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ThreadSafePubSubUI
{
    public class FileReader1
    {
        // Read specified text file & return # lines
        public int ReadTheFile(string fileName)
        {
            int numLines = 0;

            using (StreamReader sr = new StreamReader(fileName))
            {
                string nextLine;
                while ((nextLine = sr.ReadLine()) != null)
                {
                    numLines++;
                }
            }

            return numLines;
        }
    }
}

And here’s the click event handler for the form: the guy that invokes ReadTheFile.

        private void btnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                FileReader1 fr = new FileReader1();
                int numLines = fr.ReadTheFile(ofd.FileName);

                lblResults.Text = string.Format("We read {0} lines", numLines.ToString());
            }
        }

But what if the function that does the work takes a longer amount of time?  It’s pretty common for some action initiated by the user to take a little time.  What happens to the GUI while they are waiting?  We can simulate this by just adding a Thread.Sleep call in the ReadTheFile method.

            Thread.Sleep(3000);     // Simulate lengthy operation

Let’s also add a line in the btnSelect_Click method, to write a “busy” message to the GUI while we are processing.  Here is the updated click event handler:

        private void btnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                lblResults.Text = " ... reading the file ...";
                FileReader1 fr = new FileReader1();
                int numLines = fr.ReadTheFile(ofd.FileName);

                lblResults.Text = string.Format("We read {0} lines", numLines.ToString());
            }
        }

What happens is not good.  Two bad things happen, from a user’s point of view:

  • The user interface is completely unresponsive during the file read operation
  • Our “reading the file” message is not displayed

What happened?  Well, because everything is on one thread, our user interface thread doesn’t respond to mouse clicks until ReadTheFile finishes.  Worse, even though we set the label’s Text property before we call ReadTheFile, the message loop doesn’t get a chance to process that change, and update the text, before we go out to lunch in ReadTheFile.

What we need to do to fix this is: do the file read operation on a different thread

The easiest way to do some work on a background thread, keeping the GUI responsive, is to use the BackgroundWorker class.

Iteration #2 – Using the BackgroundWorker Class

You should be doing very little actual work in GUI control event handlers like the Button.Click method.  It’s a good idea to:

  • Move code that does actual work outside of the user interface class
  • Do all work on a background thread.

We want to move code into a separate library or class, rather than having it in our Click event handler, to keep our user interface code separate from our functional code.  This is just a cleaner architecture and makes our code more maintainable, easier to test, and more extensible.

We also want to do as much work as possible on a different thread from the main thread handling the GUI.  If you do your work on the same thread, you risk locking up the user interface.  (As we saw in Iteration #1).

If you’re using the .NET Framework version 2.0 or later, the best way to do work on a background thread is to use the BackgroundWorker class.  This class gives us the ability to do some work on a background thread, provides progress and completed events “out of the box” and also ensures that these callbacks execute on the correct (GUI thread).

What do I mean by “execute on the correct thread”?  Here’s how it works.  To ensure that the GUI stays responsive, we want to do any non-trivial work on a background thread.  This thread can run in parallel to the GUI thread, so the user will still be able to interact with the GUI while the work is being done.

When the work finishes, we likely want to update something in the GUI to indicate this.  (E.g. change the text on a label to indicate that the operation is done).  Our GUI object will be notified by handling an event that the worker object fires.  But since we need to update the GUI, this event handler must be executing on the same thread as the user interface.

This last point is very important.  The core rule in Windows UI programming to remember is: the only thread that can update/change a user interface control is the thread that created it.  (This is true for Windows Forms applications, which use the Single Threaded Apartment model).

The beauty of the BackgroundWorker class is that it automatically handles all of this thread logic:

  • It does work on a background thread
  • It ensures that completed/progress events are fired on the original GUI thread

Let’s change our earlier file-reading example to use the BackgroundWorker.  This example can be found in the threadsafepubsub.codeplex.com project in the Form2/FileWorker2 classes.

Here’s the new Click event handler, where we create the background worker, attach our event handlers, and then tell it to go do some work.

private void btnSelect_Click(object sender, EventArgs e)
        private void btnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                lblResults.Text = " ... reading the file ...";

                // Set up background worker object & hook up handlers
                BackgroundWorker bgWorker;
                bgWorker = new BackgroundWorker();
                bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
                bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);

                // Launch background thread to do the work of reading the file.  This will
                // trigger BackgroundWorker.DoWork().  Note that we pass the filename to
                // process as a parameter.
                bgWorker.RunWorkerAsync(ofd.FileName);
            }
        }

We first create an instance of the BackgroundWorker class and then wire up the DoWork and RunWorkerCompleted methods.  DoWork is the event that will fire when we call the RunWorkerAsync method.  And it will run asynchronously, in a background thread, freeing up the user interface.  Because RunWorkerAsync is launched in a background thread, control returns from the btnSelect_Click method quickly, and the UI is responsive, even while the file-read work is going on.

We also hook a handler to the RunWorkerCompleted event, which will fire when our bgWorker_DoWork method has finished doing the work.  This event, however, will execute on the original GUI thread–allowing is to update GUI elements directly within our gbWorker_RunWorkerCompleted handler.

Here’s the body of our DoWork handler.

        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            FileReader2 fr = new FileReader2();

            // Filename to process was passed to RunWorkerAsync(), so it's available
            // here in DoWorkEventArgs object.
            string sFileToRead = (string)e.Argument;
            e.Result = fr.ReadTheFile(sFileToRead);
        }

Notice that we just use our earlier FileReader class to do the actual work of reading the file.  But there are two additions.

First, because this method is invoked from the BackgroundWorker object, we need to somehow get the name of the file to process.  We knew this filename back in the btnSelect_Click method and we hand it off by passing it as a parameter to RunWorkerAsync and then reading it out of the DoWorkEventArgs parameter.

Similarly, when we finish doing our work (reading the file), we need to make sure the result (# lines read) gets passed back to our RunWorkerCompleted handler.  We do this by setting the Result properly of the DoWorkEventArgs parameter.

Here’s the code for our RunWorkerCompleted event handler:

        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                int numLines = (int)e.Result;
                lblResults.Text = string.Format("We read {0} lines", numLines.ToString());
            }
        }

Here we see the other side of the e.Result handoff–we read the FileReader.ReadTheFile return value out of the RunWorkerCompletedEventArgs parameter.  We also check this parameter to see if an error occurred.

If you now run this example, you’ll see a couple of important things that work better than they did in iteration #1:

  • We now correctly see the “reading the file” label, indicating that work is in progress
  • While the file is being read, we can interact with the GUI normally

You can demonstrate the second part of this by clicking on the “Tell Me a Joke” button.  You’ll get a message box with a clever joke and you can then dismiss the dialog–all while the file read operation is still going on.

Iteration #3 – Application State and Cancel Logic

You might be tempted at this point to think that we’re done and our application has everything that it needs.  But we’re missing a few critical things.  Any time that you do work in a background worker thread, you should also consider:

  • Busy indicator – making it easy for the user to know when work is being done in the background
  • Application state – what can/can’t the user do while the work is in progress?
  • Progress indicator – give the user a visual sense of how much work is left to be done
  • Cancel logic – optionally, give the user a method to cancel the background work

Busy Indicator

Let’s start with the busy indicator.  It’s important to make it obvious to your users that something is happening in the background, and what that something is.

Application State

We have some subtle behavior in our current implementation that is probably not desirable.  Try the following:

  • Click on the Read File button and select a file, to initiate a file read operation
  • Before the read has completed, click on the button again and select a new file

You now have two file read operations running in parallel.  Is this really what we want?  Do we want to prohibit it?  If not, how do we handle the results of two different file read operations, when the operations complete?  How do we avoid mixing up the results?  How do we know which operation the results are coming from?  Is there a chance that the two operations will attempt to work on/with the same data?

For our purposes, let’s agree that we really only want to allow the user to do one operation at a time.  While one operation is in progress, a user cannot initiate another one.  We’ll modify the GUI to enforce this.

Progress Indicator

More than just indicating that some work is going on in the background, it would be nice to indicate how much work we’ve already done and how much work is left to do.  This lets a user judge how long the entire process will take.

Cancel Logic

Whenever you support doing some work on a background thread, you also need to consider whether a user might want to cancel this background activity.  Unless it’s something that happens quite quickly, it’s probably a good idea to allow a user to cancel the operation and return to the original state (no file is being read and they are able to select a new file to be read).

At this point, it’s probably a good idea to do a rough sketch of a state diagram, showing what a user can do and during what state:

Application State Diagram

Notice that we enter the “reading file” state when the user clicks the “Read File” button.  But while in this state, the user cannot press that button again–they either press the “Cancel” button, or we return to the original state when the file read operation completes.

Also note that we should be able to display a joke while in either state.  This confirms what we said earlier–the GUI won’t lock up during the file read operation.

Our Modified Example

Here’s how our file reader example works, after adding a progress indicator, cancel logic, and the ability to keep track of application state.  Here’s the new GUI during a file read operation:

Progress

Note that we now tell the user what file we’re reading and we display a progress indicator, showing how far into the read operation we are.  We also give them a Cancel button, allowing them to Cancel the operation before it completes normally.  Also notice that the Read File button is greyed out—the user can’t initiate another operation until the first one completes.

If the user lets the file read operation complete normally, they’ll see the following:

Success

Notice that when we finish reading the file, returning to the Idle state, we hide all of the progress/cancel widgets.  The Read File button is also enabled again.

If the user cancels the file read operation, they’ll see the following:

Cancelled

Again, all of the progress/cancel widgets are gone, since we’re back in the Idle state.  And the Read File button is available again.  But this time, we tell the user that they cancelled the operation.

The code for this iteration can be found in threadsafepubsub.codeplex.com, as Form3.cs and FileReader3.cs.

We added a couple of things at the top of the class–an enumeration to keep track of our state, and a class-level BackgroundWorker instance.  (We move this variable into class scope because our Cancel button will need access to the BackgroundWorker object.

    private enum AppStates { Idle, ReadingFile };

    private BackgroundWorker _worker;

Here’s our new Form3 constructor, where we now call a method to set the initial application state:

        public Form3()
        {
            InitializeComponent();

            // Set up initial state
            SetAppState(AppStates.Idle, null);
        }

Here’s the actual code for the new SetAppState function, as well as a helper function that sets visibility for several controls.

        // Set new application state, handling button sensitivity, labels, etc.
        private void SetAppState(AppStates newState, string filename)
        {
            switch (newState)
            {
                case AppStates.Idle:
                    // Hide progress widgets
                    SetFileReadWidgetsVisible(false);
                    btnSelect.Enabled = true;
                    break;

                case AppStates.ReadingFile:
                    // Display progress widgets & file info
                    SetFileReadWidgetsVisible(true);
                    lblProgress.Text = string.Format("Reading file: {0}", filename);
                    pbProgress.Value = 0;
                    lblResults.Text = "";
                    btnSelect.Enabled = false;
                    break;
            }
        }

        private void SetFileReadWidgetsVisible(bool visible)
        {
            lblProgress.Visible = visible;
            pbProgress.Visible = visible;
            btnCancel.Visible = visible;
        }

We’re basically just changing the visibility of the various progress widgets in the StatusStrip at the bottom of the form.  We also handle enabling/disabling the File Read button here.

The Click event handler for our File Read button is also slightly different. We add a line that sets the application state to indicate that a file is being read, we attach a handler to track progress, and we add an exception handler to ensure that the application state is set back to idle if anything goes wrong.

        private void btnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                FileInfo fi = new FileInfo(ofd.FileName);
                SetAppState(AppStates.ReadingFile, fi.Name);

                try
                {
                    // Set up background worker object & hook up handlers
                    _worker = new BackgroundWorker();
                    _worker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
                    _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
                    _worker.WorkerReportsProgress = true;
                    _worker.WorkerSupportsCancellation = true;
                    _worker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged);

                    // Launch background thread to do the work of reading the file.  This will
                    // trigger BackgroundWorker.DoWork().  Note that we pass the filename to
                    // process as a parameter.
                    _worker.RunWorkerAsync(ofd.FileName);
                }
                catch
                {
                    SetAppState(AppStates.Idle, null);
                    throw;
                }
            }
        }

Note also that we have to explicitly tell the BackgroundWorker that it should support both progress and cancellation functionality.

We also now have a new event handler for the ProgressChanged event, which looks like this:

        // Get info on progress of file-read operation (% complete)
        void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Just update progress bar with % complete
            pbProgress.Value = e.ProgressPercentage;
        }

This one is pretty simple—we just set the value of the progress bar, which runs from 0 to 100, to the reported % complete value.

Our DoWork handler has just a few changes.  Here is the new version:

        // Do work--runs on a background thread
        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Note about exceptions:  If an exception originates anywhere in
            // this method, or methods that it calls, the BackgroundWorker will
            // automatically populate the Error property of the RunWorkerCompletedEventArgs
            // parameter that gets passed into the RunWorkerCompleted event handler.
            // So we can handle the exception in that method.

            FileReader3 fr = new FileReader3();

            // Filename to process was passed to RunWorkerAsync(), so it's available
            // here in DoWorkEventArgs object.
            BackgroundWorker bw = sender as BackgroundWorker;
            string sFileToRead = (string)e.Argument;

            e.Result = fr.ReadTheFile(bw, sFileToRead);

            // If operation was cancelled (triggered by CancellationPending),
            // we bailed out of ReadTheFile() early.  But still need to set
            // Cancel flag, because RunWorkerCompleted event will still fire.
            if (bw.CancellationPending)
                e.Cancel = true;
        }

I added a note to remind us that exceptions originating in this chunk of code (or on this thread) are automatically made available to us in the RunWorkerCompleted handler.

Notice also that we’re now passing the BackgroundWorker object into the ReadTheFile method.  We do this because we need access to it, within this message, to check for user cancellation and to report progress.

Finally, we see a piece of the cancellation infrastructure here.  Below is another code chunk to help us understand how the cancel operation works—the click handler for the Cancel button.

        private void btnCancel_Click(object sender, EventArgs e)
        {
            _worker.CancelAsync();
        }

This is pretty simple.  When the user clicks the Cancel button, we tell the BackgroundWorker object to initiate a cancel operation.  Here’s a summary of the entire cancel operation (what happens when):

  • User clicks Cancel button
  • btnCancel_Click handler invokes BackgroundWorker.CancelAsync on active worker object
  • Method doing actual work (reading file) periodically checks BackgroundWorker.CancellationPending and aborts if it sees this property set
  • Control returns to bgWorker_DoWork method
  • DoWork method checks CancellationPending property and sets DoWorkEventArgs.Cancel to true if operation was cancelled
  • BackgroundWorker.RunWorkerCompleted fires
  • We can check RunWorkerCompletedEventArgs.Cancelled, in our RunWorkerCompleted handler, to detect whether operation was cancelled

This is a little involved, but if you walk through the code, you’ll see how things work.

Finally, here is our RunWorkerCompleted event handler:

        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message, "Error During File Read");
                }
                else if (e.Cancelled)
                {
                    lblResults.Text = "** Cancelled **";
                }
                else
                {
                    int numLines = (int)e.Result;
                    lblResults.Text = string.Format("We read {0} lines", numLines.ToString());
                }
            }
            finally
            {
                // State now goes back to idle
                SetAppState(AppStates.Idle, null);
            }
        }

There are just a couple of new things here.  We now check the Cancelled property and display a message if the operation was cancelled.  We also add a finally block, where we ensure that we transition back to the Idle state, whether things completed normally, the user cancelled, or there was an error.

I have one final block of code to share—the ReadTheFile method that does the actual work:

        public int ReadTheFile(BackgroundWorker bw, string fileName)
        {
            int numLines = 0;
            FileInfo fi = new FileInfo(fileName);
            long totalBytes = fi.Length;
            long bytesRead = 0;

            using (StreamReader sr = new StreamReader(fileName))
            {
                // Note: When BackgroundWorker has CancellationPending set, we bail
                // out and fall back to the _DoWork method that called us.
                string nextLine;
                while (((nextLine = sr.ReadLine()) != null) &&
                       !bw.CancellationPending)
                {
                    bytesRead += sr.CurrentEncoding.GetByteCount(nextLine);
                    numLines++;
                    int pctComplete = (int)(((double)bytesRead / (double)totalBytes)* 100);
                    bw.ReportProgress(pctComplete);
                    Thread.Sleep(10);  // ms
                }
            }

            return numLines;
        }

We’ve basically added two things here: support for cancellation and for progress reporting.

To support user-initiated cancellation, we just check to see if the operation has been cancelled, after each line in the file that we read.  The frequency with which you check for cancellation is important.  If you don’t check often enough, the application will appear to not be responding to the cancel request and the user may become frustrated.

We report progress (% complete) by invoking the ReportProgress method on the background worker.  We do this after calculating the actual progress, in terms of # bytes read so far.

23 April, 2009

How Do I Bring Up Task Manager from a Remote Desktop Session?

Filed under: Windows — Sean @ 2:31 pm
Tags: , , ,

Here’s another little trick that I assume most people know, but perhaps not.

When you’re connected using Remote Desktop and you need to kill a task, or to check on CPU or memory performance, how do you bring up Task Manager?  If you press Ctrl-Alt-Delete, you’ll get the Windows Security dialog in the host machine–not on the remote machine.

To bring up Task Manager in a remote session, just use the keyboard shortcut: Ctrl-Shift-ESC.  This will directly open the Windows Task Manager on the machine that you’re connected to.  Voila.

22 April, 2009

After Signing My Assembly, Why Do I Get Errors About Signing Referenced Assemblies?

Filed under: .NET — Sean @ 3:11 pm
Tags: , , ,

This is a note-to-self quickie blog post.

I’m in the process of deploying a VSTO solution that includes two DLLs–a data access layer DLL and an Excel Workbook (VSTO) project that contains that code-behind for the actual Excel workbook.  In my case, my Excel code creates controls that live on the Action Pane in Excel and allow the user to interact with pre-created graphs that are fed data from a database.

When you deploy a VSTO solution, you need to grant full trust to the class library associated with the Excel Workbook (or other Office document).  This in turn means that you need to sign your assembly, i.e. attach a strong name to it.

When I sign my main assembly (e.g. ExcelWorkbook1.dll), and try to build it, I now get the following error:

Error    1    Assembly generation failed — Referenced assembly ‘MyDataAccessLayer’ does not have a strong name

What’s going on here is that when you sign an assembly, all referenced assemblies must now also have strong names.  Let’s say that again, the rule to remember is:

All assemblies referenced by a strong-named assembly must also have a strong name.

This makes sense, when you think about security concerns.  The purpose of signing an assembly is to prevent someone from replacing your assembly with one that has the same API, but does something bad–i.e. spoofing it.  Signing your main assembly helps, but if it then references a weakly-named (not signed) assembly, someone could spoof that assembly and still make your assembly behave badly.  That’s a security hole.

So when you think about signing your assemblies, giving them strong names, remember that it’s a domino effect–you’ll need to (and want to) sign all of your assemblies.  And any third-party assemblies that you use/reference need to also have strong names.

4 April, 2009

A Simple .NET Twitter API Wrapper Using LINQ

Filed under: LINQ — Sean @ 6:06 am
Tags: , , , ,

In the world of software demos, doing something with Twitter has replaced Hello World as the most common target of a demo.  At the risk of polluting the world with yet another chunk of code that does something with Twitter–I’d like to play around a bit with Silverlight charting and Twitter seems a great context for demoing what is possible.

But before I can start creating a Silverlight demo, I need a basic Twitter API wrapper in .NET.  So here’s a starting point–a simple example that uses LINQ to get a list of people that you follow.  This is a good starting point for later demos.

Twitter provides a simple REST API that lets you do basically everything you’d want to do using simple HTTP GET, POST and DELETE requests.

You can learn everything you need to know about the Twitter API at the Twitter API Wiki.

Basic Concepts

I’ll assume that you generally know how Twitter works–you follow some folks, some folks follow you, and you all post status messages–which your followers can read.  That’s the beauty of Twitter–pretty simple.

But here are some things that you should know about the Twitter API.

  • How it works
    • You post an HTTP request to a URL
    • You get XML data back in the HTTP response
  • Authentication
    • Some API method calls require authentication, using HTTP Basic Authentication.
    • Any app invoking calls that require authentication will need to supply the proper credentials.
  • Rate limits
    • Your app is limited to 100 requests per hour.    (whether you’re authenticating or not)
    • You can receive a special dispensation from the Twitter gurus to be allowed up to 20,000 requests/hr.
  • Paging
    • Many API methods requires multiple requests, retrieving a page of data at a time
    • The page parameter allows you to specify which page of data to retrieve
    • The count parameter allows specifying # items per page

What happens when you hit your rate limit?  Well, basically your application (your IP address, actually) can no longer make requests of Twitter–until the rate limit resets.

The API Calls That I Use

Here are the two Twitter API calls (URLs) that I use in this example:

You can see how these work by just entering the above URLs into your browser and looking at the XML data stream that comes back.

Here’s an example of the data returned by the friends call:

Output of Friends Request

An here’s an example of the data returned from the users call:

Data Returned from Users Request

The Peep Class

Let’s start building a simple Twitter API wrapper in .NET with a very simple class to encapsulate information about a single user–either yourself, a follower, or someone that you follow.  This doesn’t cover absolutely everything that we can find out about a Twitter user, but encapsulates some of the basic stuff that we care about.

(For these examples, I’m using Visual Studio 2008 — C# 3.0).

Here’s the code for the Peep class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace TwitterLibGUI
{
    public class Peep
    {
        public string ScreenName { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public string Description { get; set; }
        public Uri ProfileImageURL { get; set; }
        public Uri URL { get; set; }
        public int ID { get; set; }

        public int NumFollowers { get; set; }
        public int NumFollowing { get; set; }
        public int NumUpdates { get; set; }

        public string LastUpdateText { get; set; }
        public DateTime LastUpdateDateTime { get; set; }

        public new string ToString()
        {
            return string.Format("{0} - {1}", ScreenName, Name);
        }
    }
}

Super simple class, made much easier through the user of C#’s automatic properties.  As an example, using me as a Twitter user, my ScreenName would be “spsexton” and my Name would be “Sean Sexton”.

The Peeps Class

Now that we have an object that wraps a “peep”, let’s create a special class that represents a collection of Peep instances–or “peeps”.  For example, an instances of Peeps could be used to store a list of everyone that we follow (or everyone that follows us).

We’ll use our old friend, the List(T) class, from System.Collections.Generic, which implements a strongly typed collection.

Basically, a collection of Peep objects will look like this:  List<Peep>.  But we’ll create a subclass so that we can add a static method for building up a list of everyone that we follow.

Here’s the full code for Peeps.cs, followed by an explanation of how we do things.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace TwitterLibGUI
{
    /// <summary>
    /// Peep collection class
    /// </summary>
    public class Peeps : List<Peep>
    {
        // Partial Twitter API
        private const string getFriendsURI = "http://twitter.com/statuses/friends/{0}.xml?page={1}";

        /// <summary>
        /// Return list of Peeps followed by a specified person
        /// </summary>
        ///
<param name="ScreenName">The Twitter username, e.g. spsexton</param>
        /// <returns></returns>
        public static Peeps PeopleFollowedBy(string ScreenName, out int RateLimit, out int LimitRemaining)
        {
            if ((ScreenName == null) || (ScreenName == ""))
                throw new ArgumentException("PeopleFollowedBy: Invalid ScreenName");

            int nPageNum = 1;
            int userCount = 0;      // # users read on last call

            int rateLimit = 0;          // Max # API calls per hour
            int limitRemaining = 0;     // # API calls remaining

            XDocument docFriends;
            Peeps peeps = new Peeps();

            // Retrieve people I'm following, 100 people at a time
            // (each call to Twitter API results in one "page" of results--up to 100 users)
            try
            {
                do
                {
                    // Example of constituting XDocument directly from the URI
                    // docFriends = XDocument.Load(string.Format(getFriendsURI, ScreenName, nPageNum));

                    // Manually create an HTTP request, so that we can pull information out of the
                    // headers in the response.  (Then later constitute the XDocument).
                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(string.Format(getFriendsURI, ScreenName, nPageNum));
                    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                    TwitterUtility.GetInfoFromResponse(resp, out rateLimit, out limitRemaining);
                    XmlReader reader = XmlReader.Create(resp.GetResponseStream());
                    docFriends = XDocument.Load(reader);

                    IEnumerable<XElement> users = docFriends.Elements("users").Elements("user");

                    userCount = users.Count();
                    if (userCount > 0)
                    {
                        List<Peep> nextPage = (from user in users
                                               orderby (string)user.Element("screen_name")
                                               select new Peep
                                               {
                                                   ID = (int)user.Element("id"),
                                                   ScreenName = (string)user.Element("screen_name"),
                                                   Name = (string)user.Element("name"),
                                                   Location = (string)user.Element("location"),
                                                   Description = (string)user.Element("description"),
                                                   ProfileImageURL = TwitterUtility.UriFromString((string)user.Element("profile_image_url")),
                                                   URL = TwitterUtility.UriFromString((string)user.Element("url")),
                                                   NumFollowers = (int)user.Element("followers_count"),
                                                   LastUpdateDateTime = TwitterUtility.SafeUpdateDateTime(user.Element("status")),
                                                   LastUpdateText = TwitterUtility.SafeUpdateText(user.Element("status"))
                                               }).ToList();

                        peeps.AddRange(nextPage);
                    }
                    nPageNum++;
                } while (userCount > 0);
            }
            catch (WebException xcp)
            {
                throw new ApplicationException(
                    string.Format("Twitter rate limit exceeded, max of {0}/hr allowed. Remaining = {1}",
                        rateLimit,
                        limitRemaining),
                    xcp);
            }
            finally
            {
                RateLimit = rateLimit;
                LimitRemaining = limitRemaining;
            }

            return peeps;
        }
    }
}

Notice that all we have in the Peeps class at this point is a static method, PeopleFollowedBy, that returns a collection of Peep objects, one for each person that the specified screen name follows.

The first thing that you’ll notice about the code is a loop where we get consecutive pages from the Twitter \statuses\friends\screenname.xml page.  By default, you get only 100  users at a time when invoking this URL.  So the easiest way to get all people that someone follows (their “friends”), is to request consecutive pages until you get one back that contains no users.

At each step through the loop, we construct a List<Peep> object from the XML results and then add that collection to a master collection (which this function will return).

Before we look at the code at the top of the loop that constructs an HTTP request to get the next page, take a look at the commented out line at the top of the loop:

                    // Example of constituting XDocument directly from the URI
                    // docFriends = XDocument.Load(string.Format(getFriendsURI, ScreenName, nPageNum));

This is actually the simplest way to get the results of the Twitter API calll into an XDocument, and ready for querying.  Using this single line, you could replace the next five lines of code that end with another XDocument.Load.  What’s going on here is the core of what we want to do–load up an XDocument from the URI that represents the Twitter API call.

But in my code, I go to a little more effort to create an HttpWebRequest and then get the HttpWebResponse for that request.  I do this solely for the purpose of getting Twitter rate limit information out of the header of the response.  If you’ll recall, Twitter has a 100 calls per hour rate limit by default.  The nice thing is that the API tells us the rate limit, as well as the # calls remaining, after each request.  So we read that from the header and keep track of it.

For now, this rate limit information is just returned to the caller.  But my intent is to use it in a future example to actually slow down my Twitter calls, as needed.  This will be helpful when we want to batch up a large # of Twitter calls, but we don’t want to risk maxing out our rate limit.  More on this later.

I get the rate limit info from the header in the TwitterUtility.GetInfoFromResponse method, described below.

Here’s Where LINQ Comes In

Now for the LINQ part.  Once we load up the XDocument from Twitter’s response, we can build up a collection of XElement objects corresponding to the list of users in the XML stream.  But this isn’t quite what we want..  To get the data from the XElement objects into our List<Peep> collection, we need to do a simple LINQ query.

(Thanks to a post by Wally McClure on the basic idea for the LINQ query: Calling the Twitter API in C#).

The LINQ query is pretty simple–we grab each user element from the XML stream and create a Peep object for that user.  We initialize all the fields of the new Peep object for which we can get data from this XML stream.  (We can’t get NumFollowing or NumUpdates–we’ll have to make a different API call to get that information).

In most cases, we’re asking for the value of an XML element that is a child of the <user> element.  E.g. the <id> element.  And we call helper methods in some cases, since the elements that we’re trying to read might by null.  (Actually, I haven’t tested this thoroughly–some of the other elements might occasionally be null and so it wouldn’t be a bad idea to use a “safe” accessor method on all of the elements).

Finally, we need to convert the result of our query–which is IEnumerable<Peep>–to a List<Peep> by calling the ToList() method.  Then we add this new list to the master list that we are building.

Handling the Rate Limit Exception

One final thing remains for this function–handling the case when we exceed our rate limit.  I added a simple handler, to make it a little more obvious to the client that we’ve exceeded our rate limit, rather than letting the underlying WebException bubble up.  This is a little bit sloppy, since there are other things that might throw a WebException.  But this is a good start at giving the caller a little info on the rate limit issue.

The Helper Class

Here is the full code for the TwitterUtility class, which just contains a handful of helper methods that we make use of in the Peeps and Peep (see below) classes.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace TwitterLibGUI
{
    /// <summary>
    /// Various global utility methods for Twitter library
    /// </summary>
    public class TwitterUtility
    {
        /// <summary>
        /// Convert a string to a valid Uri object (or null)
        /// </summary>
        ///
<param name="sUri">String represent Uri, e.g. http://blahblah.com</param>
        /// <returns></returns>
        public static Uri UriFromString(string sUri)
        {
            return ((sUri != null) && (sUri.Length > 0)) ? new Uri(sUri) : null;
        }

        /// <summary>
        /// Pull a couple fields out of the header--specifically, the Twitter API rate limit info.
        /// </summary>
        ///
<param name="resp"></param>
        ///
<param name="rateLimit"></param>
        ///
<param name="limitRemaining"></param>
        public static void GetInfoFromResponse(WebResponse resp, out int rateLimit, out int limitRemaining)
        {
            rateLimit = 0;
            limitRemaining = 0;

            for (int i = 0; i < resp.Headers.Keys.Count; i++)
            {
                string s = resp.Headers.GetKey(i);
                if (s == "X-RateLimit-Limit")
                {
                    rateLimit = int.Parse(resp.Headers.GetValues(i).First());
                }
                if (s == "X-RateLimit-Remaining")
                {
                    limitRemaining = int.Parse(resp.Headers.GetValues(i).First());
                }
            }
        }

        /// <summary>
        /// Parse twitter date string into .NET DateTime
        /// </summary>
        ///
<param name="dateString"></param>
        /// <returns></returns>
        public static DateTime ParseTwitterDate(string dateString)
        {
            return DateTime.ParseExact(dateString, "ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Return a valid DateTime for status.created_at and handle the case
        /// of the status element not being present.
        /// </summary>
        ///
<param name="user">Represents status element (child of user element)</param>
        /// <returns></returns>
        public static DateTime SafeUpdateDateTime(XElement user)
        {
            DateTime creAt = new DateTime();        // Default constructor is 1/1/0001 12AM

            if (user != null)
            {
                XElement elemCreAt = user.Element("created_at");
                if (elemCreAt != null)
                {
                    creAt = ParseTwitterDate((string)elemCreAt);
                }
            }

            return creAt;
        }

        /// <summary>
        /// Return a valid update text string, whether or not the <status> element
        /// was present.
        /// </summary>
        ///
<param name="user">Represents status element (child of user element)</param>
        /// <returns></returns>
        public static string SafeUpdateText(XElement user)
        {
            string sText = "";

            if (user != null)
            {
                XElement elemText = user.Element("text");
                if (elemText != null)
                {
                    sText = (string)elemText;
                }
            }

            return sText;
        }
    }
}

Here’s what’s in this class:

  • UriFromString — “Safe” assignment, creating either a valid Uri object, or null
  • GetInfoFromResponse — Read the Headers collection from the HTTP response to pull out the rate limit and # remaining API calls
  • ParseTwitterDate — Parse the funky Twitter date/time string into a DateTime object
  • SafeUpdateDateTime — Another “safe” method, filling in a DateTime object only if the created_at element exists
  • SafeUpdateText — And a “safe” assignment from the text element

(Note: Both the <created_at> and <text> elements are under the <status> element).

NumFollowing and NumUpdates

My goal when I started throwing together this example was to fully populate the Peep class that I listed at the top of the post.  This includes not just # of followers for everybody in my “friends” list, but the # of people that they follow, and their total updates.  I can get everything from the API call that we just saw–the “friends” call.  But to get # following and # updates, I need to make a different call:

http://twitter.com/users/show.xml?screen_name=screenname

This method returns a bunch of info about a particular user, including # following and # updates.  (See the XML output at the top of the post).

So the obvious thing to do would be to add an assignment in our LINQ query, calling a helper method to go off and call this other Twitter API method, right?  For each user, we could call show.xml and get the remaining two fields.

The problem with including this 2nd Twitter call in the LINQ is that we’ll blow out our Twitter rate limit.  We only get 100 requests per hour, so we’d run out of steam trying to flesh out the first 100 users.  (And any Twitter user worth his salt follows at least 100 people).

So what is to be done?  For now, I add code to the Peep class (see below) to get the remaining info on a “peep by peep” basis, rather than getting everything all at once.  This is a bit of a cop out, since we leave it up to the client to decide how often to call this method.

I’ll do a 2nd post where I actually add code to make these additional calls, but in a “rate limit safe” manner.  (Hint–we’ll use timers to slow down our use of the Twitter API).

So until we get some “rate limit smart” code, here’s the expanded code for Peep.cs, including a method that calls show.xml to get the additional info.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace TwitterLibGUI
{
    public class Peep
    {
        private const string userInfoURI = "http://twitter.com/users/show.xml?screen_name={0}";

        public string ScreenName { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public string Description { get; set; }
        public Uri ProfileImageURL { get; set; }
        public Uri URL { get; set; }
        public int ID { get; set; }

        public int NumFollowers { get; set; }
        public int NumFollowing { get; set; }
        public int NumUpdates { get; set; }

        public string LastUpdateText { get; set; }
        public DateTime LastUpdateDateTime { get; set; }

        public new string ToString()
        {
            return string.Format("{0} - {1}", ScreenName, Name);
        }

        /// <summary>
        /// Calculate NumFollowing & NumUpdates, since these two fields'
        /// data isn't available from an API call that gets a list of
        /// multiple users, but must be retrieve for each user individually.
        /// </summary>
        public void CalcAddlInfo()
        {
            if ((ScreenName == null) || (ScreenName == ""))
                throw new ArgumentException("CalcNumFollowing: Invalid ScreenName");

            int rateLimit = 0;          // Max # API calls per hour
            int limitRemaining = 0;     // # API calls remaining

            XDocument docUser;

            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(string.Format(userInfoURI, ScreenName));
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                TwitterUtility.GetInfoFromResponse(resp, out rateLimit, out limitRemaining);
                XmlReader reader = XmlReader.Create(resp.GetResponseStream());
                docUser = XDocument.Load(reader);

                XElement user = docUser.Element("user");

                NumFollowing = (int)user.Element("friends_count");
                NumUpdates = (int)user.Element("statuses_count");
            }
            catch (WebException xcp)
            {
                throw new ApplicationException(
                    string.Format("Twitter rate limit exceeded, max of {0}/hr allowed. Remaining = {1}",
                        rateLimit,
                        limitRemaining),
                    xcp);
            }

        }

        /// <summary>
        /// Variant that just takes screen name, rather than acting on existing
        /// instance.
        /// </summary>
        ///
<param name="ScreenName"></param>
        public void CalcAddlInfo(string screenName)
        {
            Peep p = new Peep { ScreenName = screenName };
            p.CalcAddlInfo();
        }
    }
}

The CalcAddlInfo method just invokes the show.xml API call and then reads the friends_count and statuses_count fields.

Hey, Where’s My GUI?

Ok, so at this point, we have the following code chunks:

  • Peep.cs — wraps data for a single user and gives us method to get a few additional fields
  • Peeps.cs — subclasses List<Peep> and gives us method to get list of people that we follow
  • TwitterUtility.cs — some miscellaneous helper functions

Now let’s throw a simple Win Forms GUI on top of these classes, so that we can test things out.  Here’s what the final result will look like, after calling our PeopleFollowedBy method:

ourgui

The code for this couldn’t be simpler.  I just call the Peeps.PeopleFollowedBy method, which returns an instance of the Peeps class (which is really a List<Peep>).  And then I bind the collection to a DataGridView.  Presto.

(If you’re paying attention, you’ll also notice that my rate limit is listed as 20,000/hr, rather than the default 100/hr.  This is because I requested “white list” status and the Twitter crew kindly consented to bump my rate limit.  This applies whenever I’m making API calls from my specific IP address).

For what it’s worth, here’s the event handler code for the Load Grid button in the GUI.  Notice that I also make a test call to the CalcAddlInfo method–so we can step through the call in the debugger and see how it works.

        private void btnLoadGrid_Click(object sender, EventArgs e)
        {
            int rateLimit;
            int limitRemaining;

            Cursor = Cursors.WaitCursor;
            Peeps peeps = Peeps.PeopleFollowedBy(txtScreenName.Text, out rateLimit, out limitRemaining);

            lblNumFollowing.Text = peeps.Count.ToString();
            lblRateLimit.Text = rateLimit.ToString();
            lblRemaining.Text = limitRemaining.ToString();

            peeps[5].CalcAddlInfo();

            dgvPeeps.DataSource = peeps;
            Cursor = Cursors.Default;
        }

Wrapping Up and Next Steps

That’s all there is to it–the process of making calls to the Twitter API from .NET code and consuming the resulting XML data using LINQ is pretty straightforward.

Where am I headed next, on my way to doing some Silverlight demos?  Here’s what I’ll cover in the next post:

  • Making my API methods smart about rate limits, using timers to acquire Twitter data quietly in the background–at a rate that is just slow enough to not trigger the rate limit.
  • Possibly caching the data on the client

If we were going to productize the code that I’ve presented, we’d also want to think about:

  • Moving the Twitter API stuff out of the data objects and into a separate class
  • Better exception handling
  • Wrapping the entire Twitter API, rather than just a couple methods

24 March, 2009

The Baby Has Two Eyeballs

Filed under: Miscellaneous — Sean @ 5:55 pm
Tags: , ,

eyeballs

Driving home the other night, I was teasing my 4-yr old daughter (as I often do).  We were talking about what sorts of games to play when we got home and I suggested that we could spend our time poking Lucy’s baby brother Daniel in the eye.  I also pointed out that we’d have to take turns and asked Lucy which of us should go first.

Lucy protested.  “Daddy”, she said excitedly, “we don’t have to take turns–Daniel has two eyeballs”!

After I stopped laughing at this, I realized that Lucy had seen something very important, which hadn’t even occurred to me:

Poking a baby in the eye is something that can be done in parallel!

Yes, yes, of course–you should never poke a baby in the eye.  And if you have a pre-schooler, you should never suggest eye-poking as a legitimate game to play, even jokingly.  Of course I did explain to Lucy that we really can’t poke Daniel in the eye(s).

But Lucy’s observation pointed out to me how limited I’d been in my thinking.  I’d just assumed that poking Daniel in the eye was something that we’d do serially.  First I would poke Dan in the eye.  And then, once finished, Lucy would step up and take her turn poking Dan in the eye.  Lucy hadn’t made this assumption.  She immediately realized that we could make use of both eyeballs at the same time.

There’s an obvious parallel here to how we think about writing software.  We’ve been programming on single-CPU systems for so long, that we automatically think of an algorithm as a series of steps to be performed one at a time.  We all remember the first programs that we wrote and how we learned about how computers work.  The computer takes our list of instructions and patiently executes one at a time, from top to bottom.

But, of course, we no longer program in a single-CPU environment.  Most of today’s desktop (and even laptop) machines come with dual-core CPUs.  We’re also seeing more and more quad-core machines appear on desktops, even in the office.  We’ll likely see an 8-core system from Intel in early 2010 and even 16-core machines before too long.

So what does this mean to the average software developer?

We need to stop thinking serially when writing new software.  It just doesn’t cut it anymore to write an application that does all of its work in a single thread, from start to finish.  Customers are going to be buying “faster” machines which are not technically faster, but have more processors.  And they’ll want to know why your software doesn’t run any faster.

As developers, we need to start thinking in parallel.  We have to learn how to decompose our algorithms into groups of related tasks, many of which can be done in parallel.

This is a paradigm shift in how we design software.  In the same way that we’ve been going through a multiprocessing hardware revolution, we need to embark on a similar revolution in the world of software design.

There are plenty of resources out there to help us dive into the world of parallel computing.  A quick search for books reveals:

Introduction to Parallel Computing – Grama, Karypis, Kumar & Gupta, 2003.

The Art of Multiprocessor Programming – Herlihy & Shavit, 2008.

Principles of Parallel Programming – Lin & Snyder, 2008.

Patterns for Parallel Programming – Mattson, Sanders & Massengill, 2004.

The following paper is also a good overview of hardware and software issues:

The Landscape of Parallel Computing Research: A View from Berkeley – Asanovic et al, 18 Dec 2006.

My point here is this:  As a software developer, it’s critical that you start thinking about parallel computing–not just as some specialized set of techniques that you might use someday, but as one of the primary tools in your toolbox.

After all, today’s two-eyed baby will be sporting 16 eyes before we know it.  Are you ready to do some serious eye-poking?

23 March, 2009

Hello Silverlight World, part 3 – The Lifecycle of a Silverlight Control

Ok, continuing with building a simple Wizard-generated Silverlight application and then staring at it to see how it works..  Last time, I talked about the Application object in Silverlight vs. WPF.  This time I’ll continue looking at the pieces in the sample Silverlight application, looking at the Page class that was generated and what happens to this control at runtime on a client machine.

Pages vs. Windows

I pointed out a couple of posts back the interesting difference here, just in the terminology.  In Silverlight, your main design surface is a “page”, which sort of comes from the fact that you’re serving up a series of web “pages” with some content in each.  (Nevermind that a Silverlight control can never be an entire page by itself, but must be hosted in an .html or .aspx page).  In WPF, the main design surface is a “window”, which seems appropriate because it runs in a bordered window.

Silverlight’s UserControl Class

In Silverlight, you render all of your content in a class that derives from System.Windows.Controls.UserControl.  When you use the wizard to generate a Silverlight application, it creates a class named Page, e.g.:

    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }
    }

One other quick thing to look at, is what else we’re doing in our child class at runtime, beyond what we get in the UserControl base class.  If you build your Silverlight application and then look at the other half of the partial class, i.e. the generated code in Page.g.cs, you’ll see:

    public partial class Page : System.Windows.Controls.UserControl {

        internal System.Windows.Controls.Grid LayoutRoot;

        private bool _contentLoaded;

        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
            if (_contentLoaded) {
                return;
            }
            _contentLoaded = true;
            System.Windows.Application.LoadComponent(this, new System.Uri("/SilverlightApplication2;component/Page.xaml", System.UriKind.Relative));
            this.LayoutRoot = ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
        }
    }

So, like our App class that derived from System.Windows.Application, the Page class defines an InitializeComponent method that just calls the static Application.LoadComponent method, which just constitutes an object in question, based on its .xaml.  So for both our App and our Page class, the class is getting instantiated and then InitializeComponent causes it to finish initializing by reading the associated .xaml file and then setting properties and creating child objects based on what is in the .xaml.  This is the magic fairy dust that allows .xaml to work–at runtime, the .xaml is just interpreted and associated objects are created.

The second half of this process is happening at the point where we are setting the LayoutRoot property.  The wizard generated some .xaml for our page that has a Grid as the topmost element, with the name “LayoutRoot”.  Then, at code generation time, we get a Grid object declared and then point it to the object that we loaded from the .xaml.  (Using the FindName method).

Where Are We?

Ok, so we’ve seen that there really isn’t much to our Page class, other than the fact that it constitutes itself from the .xaml.  But what is really going on at runtime, on the client where this control will be hosted?

The Lifecycle of a Silverlight Control

To answer that, let’s just walk through the entire lifecycle of our Silverlight control, starting from how the code is downloaded from the server and continuing on to how the Silverlight runtime on the client’s machine loads and renders the control.

It All Starts With a Web Page

plugin-model

Here’s a diagram from the MSDN documentation that gives us the big picture.  Your Silverlight control runs in a managed environment (the Silverlight Common Language Runtime), which in turn runs in the context of a browser plug-in.  And that plug-in runs in the context of a web page that is downloaded from a web server to the client machine.

Remember that when we created our Silverlight application using the Visual Studio wizard, it also generated an ASP.NET web application in which to host our control.  (e.g. SilverlightApplication1.Web).  If you look at the web application, you’ll see that we’ve been given a couple examples of pages hosting our Silverlight control.  Specifically, you’ll see an .aspx and an .html page.  For now, let’s look at the more basic of the two–the .html page.

If you open this test page, e.g. SilverlightApplication1TestPage.html, and scroll to the bottom, you’ll see an <object> tag that mentions Silverlight:

    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"><param name="source" value="ClientBin/SilverlightApplication1.xap"/><param name="onerror" value="onSilverlightError" /><param name="background" value="white" /><param name="minRuntimeVersion" value="2.0.31005.0" /><param name="autoUpgrade" value="true" /><a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
            <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
        </a>
    </object>

What we see here is a standard HTML <object> tag, which allows us to embed a 3rd party plug-in into the browser on the client’s machine.  When rendering the web page, the browser will set aside an area of the page and let the plug-in render directly to that area.  In this case, the 3rd party is Microsoft and the plug-in is Silverlight.

So here’s how things get rolling with our Silverlight control, on the client’s machine (whoever is pointing their browser at your .html page):

  • Client starts up their browser and points it at SilverlightApplication1TestPage.html (let’s assume that the test page is on a web server somewhere)
  • The .html page is downloaded from the web server to the client and the browser begins rendering the HTML content
  • The browser reaches the <object> tag, which indicates that a plugin should be loaded, started up, and allowed to render that part of the page
  • To figure out how to call the plugin, the browser uses the value of the type attribute on the object tag.
  • In our cases, this type is application/x-silverlight-2.  This is a MIME type, which maps to Silverlight 2
  • Using the MIME type, the browser loads the plugin
    • Under Windows, there is a registry entry that associates this MIME type with an ActiveX control named AgControl.AgControl, which in turn is implemented by a DLL npctrl.dll, located in C:\Program Files\Microsoft Silverlight\2.0.40115.0
    • So npctrl.dll is the actual plugin implementation–an unmanaged Windows DLL that implements the plugin API and, in turn, launches the Silverlight CLR–the execution environment in which your Silverlight control actually runs

Ok, if you were paying attention, you may have noticed something surprising in that last bullet point:  ActiveX??  Isn’t ActiveX dead and buried, now that we’re dealing with a managed environment?

Well, yes and no.  The code that we are authoring–our Silverlight control–does run in a managed environment on the client machine, in that it runs inside of the Silverlight CLR/runtime.  But the Silverlight plugin itself has to interact with the web browser and, as such, is unmanaged code that implements that standard browser plug-in API(s) that allow it to run within the browser.

So clearly, npctrl.dll is unmanaged code.  But ActiveX?  The MSDN documentation is not 100% clear on this point, but here’s what I think is going on.  npctrl.dll is both a classic Win32 DLL (non-COM), as well as an ActiveX control (COM server).  Which mode it runs in depends on the browser.   When running inside of Internet Explorer, the plug-in runs as an ActiveX control, implementing the IXcpControl COM interface.  However, when Silverlight is hosted in other browsers, like Mozilla, it implements the Netscape Plug-in API, running as a classic Win32 DLL.  (It implements functions like NP_Initialize and NP_GetEntryPoints).  [This paragraph is mostly conjecture].

Silverlight Presentation Core

silverlight-architecture

Within the Silverlight plug-in, the next layer to take control is the Silverlight Presentation Core.  You can see the Presentation Core as the bottom blue box in this diagram (also found in MSDN documentation).

The Presentation Core is responsible for rendering everything in the browser, handling user interaction, playing video, and parsing XAML.  It’s implemented in agcore.dll, which is a classic Win32 DLL.  (Not a COM server and not a .NET executable).

When your browser starts up (in Firefox, at least), both npctrl.dll (Plug-in) and agcore.dll (Presentation Core) are loaded.  The remaining Silverlight runtime libraries described below are only loaded when you actually load a page containing a Silverlight control.

Silverlight CoreCLR

After your browser has loaded the Silverlight plug-in, it does three basic things:

  • Starts up the Silverlight Common Language Runtime
  • Downloads the .xap file containing your Silverlight control and Application object from the server
  • Instantiates your Application object and loads it

The CoreCLR, or Silverlight Common Language Runtime, is the Silverlight version of the CLR that runs inside the Silverlight plug-in.  (Labeled CLR Execution Engine in the above diagram).  This is the managed environment that your Silverlight applications run inside, similar to the CLR that hosts thick-client .NET applications.

The CoreCLR is implemented in coreclr.dll, also in C:\Program Files\Microsoft Silverlight\2.0.xxxxx.0.  The CoreCLR is based on the same codebase as the desktop version of the CLR, but much smaller, and with features not required in a browser environment removed.  (In the desktop world, the equivalent DLLs are mscoree.dll and mscorwks.dll).

Note: coreclr.dll is also just a “plain old” unmanaged Win32 DLL.  It is the implementation of the .NET CLR, so it does not run in a managed environment itself.

The XAP File

Before Silverlight can run any of your code on the client machine, it has to download it from the server.  Your Silverlight application is packaged into a .xap file.  The .xap file is nothing more than a .zip file that has been renamed.  You can prove this to yourself by building your application and then renaming the resulting .xap file as a .zip file.

silverlight-application-structure

If you look at the files inside your .xap, for a typical wizard-generated Silverlight application, you’ll find two files:

  • AppManifest.xaml
  • SilverlightApplication1.dll

The AppManifest.xaml file is the application manifest, which tells the Silverlight runtime what DLLs are present in this package and which one contains the entry point, or startup object, for your Silverlight application.  For example, you might see something like the following:

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    EntryPointAssembly="SilverlightApplication1"
    EntryPointType="SilverlightApplication1.App"
    RuntimeVersion="2.0.31005.0">
  <Deployment.Parts>
    <AssemblyPart x:Name="SilverlightApplication1" Source="SilverlightApplication1.dll" />
  </Deployment.Parts>
</Deployment>

Note that the manifest tells Silverlight to load the assembly located in SilverlightApplication1.dll and that the startup object is SilverlightApplication1.App, which is the class that derives from System.Windows.Application.

Starting Up

Once the .xap file is downloaded, the CoreCLR can instantiate your object and get things started.  It does this by:

  • Instantiating an instance of your entry point type, e.g. SilverlightApplication1.App
  • Firing the Application.Startup event

Our wizard-generated Silverlight application included wizard-generated code to get everything up and running as follows:

  • During the App constructor
    • Wire a handler for the Application.Startup event
    • Call App.InitializeComponent
  • App.InitializeComponent, also wizard-generated :
  • The handler for the Application.Startup event
    • Instantiates a new Page object  (the actual Silverlight control to be displayed)
    • Sets the RootVisual property of the parent App object to point to the Page
  • During the Page constructor
    • Call Page.InitializeComponent
  • Page.InitializeComponent
    • Calls Application.LoadComponent, reconstituting the Page object from the associated XAML (BAML)

That’s really all there is to it.  At this point, through the magic of the browser plug-in architecture and the fact that the Silverlight CoreCLR is running on the client’s PC, you have a native .NET (Silverlight) application running on the client, hosted in the browser.

References

Debugging Silverlight Applications with windbg and sos.dll – 21 Aug 2008 – Tess Ferrandez
Debugging Tools and Symbols: Getting Started – Windows Hardware Developer Central
Dissecting Silverlight – 1 May 2007 – Ed Burnette
Setting a Silverlight 2 Startup Breakpoint Using WinDBG – 10 Jan 2009 – David Betz
Silverlight Application Services – MSDN
Silverlight Application Structure – MSDN
Silverlight Architecture – MSDN
Silverlight Plug-In Object Reference – MSDN

« Previous PageNext Page »

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 374 other followers