Delay's Blog

Silverlight, WPF, Windows Phone, Web Platform, .NET, and more...

Posts
  • Delay's Blog

    My new home page, rejuvenated [Updated collection of great Silverlight/WPF/Windows Phone Data Visualization resources!]

    • 23 Comments

    It's been a few months since I posted my previous collection of Silverlight/WPF Charting links. In the meantime, the April 2010 release of the Silverlight Toolkit was published with support for stacked series and significant performance improvements! And Windows Phone 7 has been steadily building momentum - it's handy that the Data Visualization assembly also works on Windows Phone!

    So there's lots of good stuff - here are all the links (FYI: previously published links are gray):

    Overviews (100 level)

    Scenarios (200 level)

    Internals (300 level)

    Team Member posts (Partner level)

    My posts (Ego level)

    Many thanks go out to everyone who has spent time helping people learn how to use Silverlight/WPF/Windows Phone Data Visualization!

    PS - If I've missed something useful, please send me a link - I'm always happy to find more great content! :)

    PPS - The most recent version of this collection will always be pointed to by http://cesso.org/r/DVLinks. If you're going to create a favorite or link to this post, please use that URL so your link will always be current.

  • Delay's Blog

    LB-SV-WHY [Three wacky uses for Silverlight 2's ListBox and ScrollViewer!]

    • 10 Comments

    In my Silverlight 2 ListBox/ScrollViewer FAQ I described some common scenarios and demonstrated how to implement them with sample XAML/code. In this post I demonstrate three UNcommon ListBox/ScrollViewer scenarios - again showing the XAML/code that makes them possible.

    Because sometimes the power of a thing only becomes clear when it's being abused. :)

     

    ListBox: Planets

    When I saw Beatriz Costa's "PlanetsListBox" WPF demo of a fully functioning ListBox that looked like the solar system, I was stunned and knew I had to port it to Silverlight.

    Planets shown smaller than actual size

    So I downloaded the WPF project, created a new Silverlight application, copied over the implementations of the classes SolarSystem, SolarSystemObject, and ConvertOrbit, and went to work migrating the XAML. With one small exception, the code had no changes for Silverlight. As you'd expect, the XAML got a variety of minor tweaks because Silverlight is a subset of WPF and I was moving in the "wrong" direction. In particular, I made the following changes to the original implementation:

    • Switched to inline styles because Silverlight does not support implicit styles
    • Switched from a Trigger-based selection indicator (the yellow circle) to one based on the Silverlight parts model
    • Manually created Canvas bindings in PrepareContainerForItemOverride because Silverlight wasn't creating the attached property bindings in XAML
    • Manually created ToolTip contents/bindings in a custom IValueConverter because bindings in the ToolTip XAML were unexpectedly seeing a null DataContext
    • Changed the type of SolarSystemObject.Image from Uri to string and changed the image resource paths so that binding to Silverlight's Image.Source worked
    • Switched to Canvas.Top because Silverlight does not support Canvas.Bottom
    • Converted all images to JPEG format because GIF is not supported by Silverlight

     

    ListBox: Slideshow

    One day I was working on a perfectly sensible ListBox sample with images when my teammate Ted suggested making a simple Slideshow with ListBox. It's not the craziest idea he's ever had, so I decided to humor him.

    It's not much of a list anymore...

    The basic idea is simple: Populate the ListBox with images and then size it so only one of them shows at a time. You can use the dedicated Previous/Next Buttons to change slides - or click on the ListBox and press the usual keys (arrow Up/Down, Home/End, Page Up/Down). Because the Button states are updated in the SelectionChanged handler, they're kept in sync. Here's the complete implementation:

    <UserControl x:Class="ListBoxSlideShow.Page"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls">
        <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    
            <!-- Column/row definitions -->
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
    
            <!-- ListBox slide display -->
            <ListBox
                x:Name="Display" Grid.ColumnSpan="2" Width="484" Height="364"
                controls:ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                controls:ScrollViewer.VerticalScrollBarVisibility="Hidden">
    
                <!-- Style to size all images to desired size -->
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="Width" Value="480"/>
                        <Setter Property="Height" Value="360"/>
                    </Style>
                </ListBox.ItemContainerStyle>
    
                <!-- Slide images -->
                <!-- Note: Sample images are from C:\Windows\Web\Wallpaper\*
                           Update that path if necessary for your machine -->
                <Image Source="img10.jpg"/>
                <Image Source="img7.jpg"/>
                <Image Source="img8.jpg"/>
                <Image Source="img9.jpg"/>
            </ListBox>
    
            <!-- Previous/Next buttons -->
            <Button x:Name="Previous" Grid.Column="0" Grid.Row="1" Content="Previous"/>
            <Button x:Name="Next" Grid.Column="1" Grid.Row="1" Content="Next"/>
        </Grid>
    </UserControl>
    
    using System;
    using System.Windows.Controls;
    
    namespace ListBoxSlideShow
    {
        public partial class Page : UserControl
        {
            public Page()
            {
                InitializeComponent();
    
                // Hook button event handlers to change slides
                Previous.Click += delegate { ChangeSlide(Display.SelectedIndex - 1); };
                Next.Click += delegate { ChangeSlide(Display.SelectedIndex + 1); };
    
                // Update button states if necessary
                Display.SelectionChanged += delegate
                {
                    Previous.IsEnabled = (0 < Display.SelectedIndex);
                    Next.IsEnabled = (Display.SelectedIndex < Display.Items.Count - 1);
                };
    
                // Change to first slide
                ChangeSlide(0);
            }
    
            private void ChangeSlide(int index)
            {
                // Select specified slide and bring it into view
                Display.SelectedIndex = Math.Max(0, Math.Min(Display.Items.Count - 1, index));
                Display.ScrollIntoView(Display.SelectedItem);
            }
        }
    }
    

     

    ScrollViewer: Marquee

    On a discussion list one day, someone innocently asked for a way to scroll text. I immediately thought: <MARQUEE>!

    Welcome back to Web 1.0!

    Again, the idea is simple: Put arbitrary content inside a ScrollViewer, hide its ScrollBars, and adjust its HorizontalOffset on a timer. I chose to have the content bounce at each end, but you could just as easily snap it back to the beginning. Here's the complete implementation:

    <UserControl x:Class="ScrollViewerMarquee.Page"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
    
            <!-- Marquee-like ScrollViewer -->
            <ScrollViewer x:Name="Marquee" Width="200"
                          VerticalAlignment="Center"
                          HorizontalScrollBarVisibility="Hidden"
                          VerticalScrollBarVisibility="Disabled">
    
                <!-- Arbitrary nested content -->
                <TextBlock Text=" This message bounces! "
                           FontFamily="Arial Black" FontSize="40"/>
            </ScrollViewer>
        </Grid>
    </UserControl>
    
    using System;
    using System.Windows.Controls;
    using System.Windows.Threading;
    
    namespace ScrollViewerMarquee
    {
        public partial class Page : UserControl
        {
            // Timer and direction variables
            private DispatcherTimer _timer;
            private int _delta = 1;
    
            public Page()
            {
                InitializeComponent();
    
                // Create timer to tick every 10ms
                _timer = new DispatcherTimer
                {
                    Interval = TimeSpan.FromMilliseconds(10)
                };
    
                // Attach a Tick handler to do the scrolling
                _timer.Tick += delegate
                {
                    // Adjust the horizontal offset
                    Marquee.ScrollToHorizontalOffset(Marquee.HorizontalOffset + _delta);
    
                    // Flip direction if necessary
                    if ((0 < Marquee.ViewportWidth) &&  // (NOOP if not visible yet)
                        ((Marquee.ScrollableWidth <= Marquee.HorizontalOffset) ||
                         (Marquee.HorizontalOffset <= 0)))
                    {
                        _delta = -_delta;
                    }
                };
    
                // Start the timer
                _timer.Start();
            }
        }
    }
    

     

    I've made the complete source code I used to build these samples available as an attachment to this post for anyone to play around with. If you come up with your own wacky use for ListBox or ScrollViewer, please let me know. It's always interesting to see the clever, creative ways people end up using stuff like this!

  • Delay's Blog

    If it walks like a duck and talks like a duck, it must be a ... TreeGrid! [A simple, XAML-only TreeGrid UI for WPF]

    • 6 Comments

    If you've done much work with WPF or Silverlight, chances are you already know what a TreeView is and what a DataGrid is. You know that a TreeView is good for showing hierarchical data and a DataGrid is good for showing tabular data. But you may not know about their hybrid love child, the TreeGrid - and that's what this post is about.

    Sometimes you've got data that's basically tabular in nature, yet also has a hierarchical aspect, and you'd like to leverage that to give people control over the level of detail they're seeing. Most commonly, you'll see a TreeGrid used when the tabular data can be nicely summarized (or "rolled up") into hierarchical groupings. For example, a list of people's name and address would not make a good TreeGrid, because there's no natural grouping that makes sense (you can't combine addresses). However, a list of people's company and salary might make a good TreeGrid because it's natural to group by job and the aggregated salary information could be informative (either as an average or as a sum).

    Aside: You might wonder if DataGrid's native support for grouping would be useful here. In my experience, DataGrids don't tend to summarize the grouped data like we want - but if you have examples to the contrary, I'd love to see them.

    So with all this talk about TreeGrid, you might expect to find one in the Silverlight or WPF framework, or perhaps as part of the Silverlight Toolkit or WPF Toolkit. But you won't - it's just not used frequently enough to have made it to the big leagues yet. The good news is that a bit of web searching will turn up some third-party TreeGrid options that definitely seem worth evaluating. But because I'm cheap and a show-off - and occasionally fall victim to a little NIH - I decided to craft a TreeGrid-like experience using only the WPF TreeView control, a couple of Grids, and some XAML.

    That's right - no code, just XAML! :)

     

    Here's how my SimpleTreeGridUX sample looks with some data I made up about the schedule of a fictional developer:

    SimpleTreeGridUX sample

    And here's the complete XAML:

    <!-- TreeGrid "Control" -->
    <Border BorderBrush="Black" BorderThickness="1">
    
        <!-- Resources -->
        <Border.Resources>
            <Style x:Key="TextBlockStyle" TargetType="{x:Type TextBlock}">
                <Setter Property="Margin" Value="3 0 3 0"/>
            </Style>
            <Style x:Key="TextBlockBoldStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle}">
                <Setter Property="FontWeight" Value="Bold"/>
            </Style>
        </Border.Resources>
    
        <!-- Content -->
        <Grid Grid.IsSharedSizeScope="True">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
    
            <!-- Column headers -->
            <TreeViewItem Grid.Row="0" BorderThickness="1">
                <TreeViewItem.Header>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition SharedSizeGroup="Task"/>
                            <!-- Placeholders for two columns of ToggleButton -->
                            <ColumnDefinition SharedSizeGroup="Toggle"/>
                            <ColumnDefinition SharedSizeGroup="Toggle"/>
                            <ColumnDefinition SharedSizeGroup="Duration"/>
                            <ColumnDefinition SharedSizeGroup="Notes"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="Task" Style="{StaticResource TextBlockBoldStyle}"/>
                        <!-- Empty TreeViewItem to measure the size of its ToggleButton into the "Toggle" group-->
                        <TreeViewItem Grid.Column="1" Padding="0"/>
                        <TextBlock Grid.Column="3" Text="Duration" Style="{StaticResource TextBlockBoldStyle}"/>
                        <TextBlock Grid.Column="4" Text="Notes" Style="{StaticResource TextBlockBoldStyle}"/>
                    </Grid>
                </TreeViewItem.Header>
            </TreeViewItem>
    
            <!-- Data rows -->
            <TreeView Grid.Row="1" ItemsSource="{Binding SubItems}" BorderBrush="Gray" BorderThickness="0 1 0 0">
                <TreeView.ItemTemplate>
    
                    <!-- Level 0 template leaves space for 2 child "Toggle" levels -->
                    <HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition SharedSizeGroup="Task"/>
                                <ColumnDefinition SharedSizeGroup="Toggle"/>
                                <ColumnDefinition SharedSizeGroup="Toggle"/>
                                <ColumnDefinition SharedSizeGroup="Duration"/>
                                <ColumnDefinition SharedSizeGroup="Notes"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Text="{Binding Task}" Style="{StaticResource TextBlockStyle}"/>
                            <TextBlock Grid.Column="3" Text="{Binding Duration}" Style="{StaticResource TextBlockStyle}"/>
                            <TextBlock Grid.Column="4" Text="{Binding Notes}" Style="{StaticResource TextBlockStyle}"/>
                        </Grid>
    
                        <!-- Level 1 template leaves space for 1 child "Toggle" level -->
                        <HierarchicalDataTemplate.ItemTemplate>
                            <HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition SharedSizeGroup="Task"/>
                                        <ColumnDefinition/>
                                        <ColumnDefinition SharedSizeGroup="Toggle"/>
                                        <ColumnDefinition SharedSizeGroup="Duration"/>
                                        <ColumnDefinition SharedSizeGroup="Notes"/>
                                    </Grid.ColumnDefinitions>
                                    <TextBlock Grid.Column="0" Text="{Binding Task}" Style="{StaticResource TextBlockStyle}"/>
                                    <TextBlock Grid.Column="3" Text="{Binding Duration}" Style="{StaticResource TextBlockStyle}"/>
                                    <TextBlock Grid.Column="4" Text="{Binding Notes}" Style="{StaticResource TextBlockStyle}"/>
                                </Grid>
    
                                <!-- Level 2 template has no children -->
                                <HierarchicalDataTemplate.ItemTemplate>
                                    <HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
                                        <Grid>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition SharedSizeGroup="Task"/>
                                                <ColumnDefinition/>
                                                <ColumnDefinition/>
                                                <ColumnDefinition SharedSizeGroup="Duration"/>
                                                <ColumnDefinition SharedSizeGroup="Notes"/>
                                            </Grid.ColumnDefinitions>
                                            <TextBlock Grid.Column="0" Text="{Binding Task}" Style="{StaticResource TextBlockStyle}"/>
                                            <TextBlock Grid.Column="3" Text="{Binding Duration}" Style="{StaticResource TextBlockStyle}"/>
                                            <TextBlock Grid.Column="4" Text="{Binding Notes}" Style="{StaticResource TextBlockStyle}"/>
                                        </Grid>
                                    </HierarchicalDataTemplate>
                                </HierarchicalDataTemplate.ItemTemplate>
                            </HierarchicalDataTemplate>
                        </HierarchicalDataTemplate.ItemTemplate>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
        </Grid>
    </Border>
    

     

    Notes:

    • There are two "tricks" I use to get DataGrid-like behavior from a TreeView. The first is the Grid.IsSharedSizeScope attached DependencyProperty and its partner-in-crime DefinitionBase.SharedSizeGroup. (Both available only on WPF for now.) By setting IsSharedSizeScope on a parent element and SharedSizeGroup on some of the column/row definitions of Grids within it, it's possible to "link" the sizes of cells across different Grids. In the scenario above, that sharing takes place across the separate Grids of the column headers and each TreeViewItem row of data. In this manner, same-width columns are created for the "Task", "Duration", and "Notes" fields so they all line up properly. Except that they wouldn't actually line up if it weren't for...
    • The "Toggle" shared size group which is used to offset TreeViewItem children to take into account the indent that TreeViewItem parents automatically impose on them. The following diagram of the default TreeViewItem layout should help explain what I mean:
      Header
      Children
      You see, each collection of children is offset to the right by exactly the width of the TreeViewItem's toggle element. So if all we did was make each column's cells the same width, things wouldn't actually line up because of this offset showing up in different amounts everywhere:
      Header
      Header
      Children
      So what I've done is add a special shared size group with exactly the same width as the toggle (this is what the empty TreeViewItem in the header section of the XAML is for). Having done that, the "Toggle" size group can be used to simulate the width of the actual toggle anywhere it's needed. Therefore, I'm able to insert the appropriate counter-offset for each level of the tree - and everything lines up beautifully!
    • You've probably noticed that there's an unfortunate amount of XAML duplication above - each of the three HierarchicalDataTemplates are very nearly identical. In fact, the only difference among them is whether the second and third ColumnDefinition have the SharedSizeGroup property or not. Now, I strive to stay as DRY as the next guy, and I tried to come up with a way to collapse the three templates into one. But while I could do so quite easily using a bit of code, I couldn't come up with a nice way that was pure XAML.
      Aside: Converting the template contents to a UserControl gets close, but there's still the problem of toggling that property based on external input. And while it would definitely be possible to decorate the (view) model with information about each element's level, I considered that to be "cheating" for the purposes of this exercise. :)

     

    [Click here to download the complete source code for the SimpleTreeGridUX sample.]

     

    Just in case it's not really obvious by now, what I describe here is not a true TreeGrid control! While I'll suggest that it looks like a real TreeGrid, behaves mostly like one, and is probably good enough for many scenarios, I'm also the first to acknowledge it's not a true TreeGrid. A true TreeGrid would probably have an extensive API for managing columns and rows, allow sorting and arbitrary nesting, and end up with an object model pretty similar to DataGrid's. So if you came here looking for a proper TreeGrid control, I'm sorry to disappoint you - but if you came here hoping to learn more about solving real-world problems with WPF, I hope this has been educational! :)

  • Delay's Blog

    Dynamic content made easy *redux* [How to: Use the new dynamic population support for Toolkit controls]

    • 23 Comments

    I previously blogged a sample demonstrating how to use the AJAX Control Toolkit's dynamic population functionality with a data-bound ModalPopup. That sample was well received, but some of the changes that happened as part of the ASP.NET AJAX Beta 1 and Beta 2 releases have rendered the sample code I originally posted un-runnable on current builds.

    No worries - it's a simple matter to update the sample and the exercise should serve as a good example of some of the things that need to be done as part of an upgrade. (For a far more in depth guide to upgrading, please refer to Shawn's AJAX Control Toolkit Migration Guide and follow-up about upgrading Web Services/Methods.)

    Referring to the sample code I posted earlier as a starting point, the 5 things we need to do to update it are:

    1. Change the tag prefix for ScriptManager from "atlas" to "asp" to point to the new location for ScriptManager
    2. Change the @Register tag to refer to the AjaxControlToolkit by its new name ("AtlasControlToolkit"->"AjaxControlToolkit" twice and "atlasToolkit"->"ajaxToolkit" once)
    3. Change the corresponding tag prefix for ModalPopupExtender from "atlasToolkit" to "ajaxToolkit"
    4. Copy the properties of the ModalPopupProperties element to the ModalPopupExtender element and remove the empty ModalPopupProperties element now that the XxxProperties elements are no longer used
    5. Update the web method definition by making the GetContent method static and adding the [Microsoft.Web.Script.Services.ScriptMethod] attribute

    That's it! As you can see, it's mostly simple "find-and-replace" naming changes that can easily be applied to an entire site at once. The XxxProperties change is slightly more involved, but requires very little effort since it's basically just a "cut-and-paste" operation. The web method changes are also a little bit of effort, but the changes themselves are simple and it's easy to find where to make them by searching for the pre-existing "WebMethod" attribute. Nothing here is risky or error-prone and - with the exception of the web method changes - the compiler will report all of them as errors until they're fixed correctly.

    For completeness, here's a reminder of what dynamic population looks like in action:

    Animated demonstration

    And here's the complete sample code after the changes discussed above have been applied. This sample runs fine on the ASP.NET AJAX Beta 2 and the AJAX Control Toolkit 61106 release:

    <%@ Page Language="C#" %>
    <%
    @ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
      TagPrefix="ajaxToolkit" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <
    script runat="server">
      [System.Web.Services.WebMethod]
      [Microsoft.Web.Script.Services.
    ScriptMethod]
      
    public static string GetContent(string contextKey)
      {
        
    // Create a random color
        string color = (new Random()).Next(0xffffff).ToString("x6");
        
    // Use the style specified by the page author
        string style = contextKey;
        
    // Display the current time
        string time = DateTime.Now.ToLongTimeString();
        
    // Compose the content to return
        return "<span style='color:#" + color + "; " + style + "'>" + time + "</span> ";
      }
    </script>

    <
    html xmlns="http://www.w3.org/1999/xhtml">
    <
    head id="Head1" runat="server">
      <title>Dynamic ModalPopup Demonstration</title>

      <%-- Style the page so it looks pretty --%>
      
    <style type="text/css">
        body { font-family:Verdana;     font-size:10pt; }
        
    .background { background-color:Gray; }
        
    .popup { width:200px;             padding:10px;        background-color:White;
                
    border-style:solid;      border-color:Black;  border-width:2px;
                
    vertical-align: middle;  text-align:center; }
      
    </style>
    </
    head>
    <
    body>
      <form id="form1" runat="server">

        <%-- Atlas pages need a ScriptManager --%>
        
    <asp:ScriptManager ID="ScriptManager1" runat="server" />

        <%-- A very simple data source to drive the demonstration --%>
        
    <asp:XmlDataSource ID="XmlDataSource1" runat="server">
          <Data>
            <items>
              <item style="font-weight:bold" />
              <item style="font-style:italic" />
              <item style="text-decoration:underline" />
            </items>
          </Data>
        </asp:XmlDataSource>

        <%-- A simple list of all the data items available --%>
        
    <asp:DataList ID="DataList1" runat="server" DataSourceID="XmlDataSource1">

          <HeaderTemplate>
            How would you like your dynamic content styled?
          
    </HeaderTemplate>

          <ItemTemplate>
            &bull; <asp:LinkButton ID="LinkButton" runat="server" Text='<%# Eval("style") %>' />

            <%-- The ModalPopupExtender, popping up Panel1 and dynamically populating Panel2 --%>
            
    <ajaxToolkit:ModalPopupExtender ID="ModalPopupExtender" runat="server"
                TargetControlID="LinkButton" PopupControlID="Panel1" OkControlID="Button1"
                BackgroundCssClass="background" DynamicControlID="Panel2"
                DynamicContextKey='<%# Eval("style") %>' DynamicServiceMethod="GetContent" />
          </ItemTemplate>

        </asp:DataList>

        <%-- All ModalPopups share the same popup --%>
        
    <asp:Panel ID="Panel1" runat="server" CssClass="popup" style="display:none;">
          <p>This popup popped at <asp:Label ID="Panel2" runat="server" /> and all was well.</p>
          <p><asp:Button ID="Button1" runat="server" Text="OK" /></p>
        </asp:Panel>

      </form>
    </
    body>
    </
    html>

    Enjoy!

  • Delay's Blog

    Pining for Windows Phone 7 controls? We got ya covered! [Announcing the first release of the Silverlight for Windows Phone Toolkit!]

    • 35 Comments
    Phone Toolkit Sample Application

    Today marks the official release of the Windows Phone Developer Tools. This free download enables anyone to create .NET applications for the Windows Phone 7 platform using the Silverlight framework (for traditional applications) or the XNA framework (for games). The Windows Phone 7 application development experience is fully integrated with Visual Studio 2010 and Blend 4 and also includes an emulator for running and testing applications without having a phone. It's really cool stuff, and I encourage everyone to learn more about Windows Phone 7 development!

    Congratulations to the Windows Phone 7 team on their accomplishment!

     

    To celebrate, there's a new download for the Silverlight Toolkit CodePlex project: the Silverlight for Windows Phone Toolkit September 2010 release! Yes, that's right - in addition to providing controls for Silverlight developers targeting the desktop, we're also providing controls for Silverlight developers targeting Windows Phone 7! As you might guess, the Windows Phone Toolkit is a lot like the Silverlight Toolkit: the goal is still to provide a set of controls that complement the platform's core offering and help developers/designers create more compelling, more platform-consistent user experiences simply and easily. Because we focus on writing solid, reusable controls that address common scenarios, you are free to focus on delivering an engaging, compelling application to your customers!

    As with the Silverlight Toolkit, the Windows Phone Toolkit comes with full source code (under the permissive OSI-approved Ms-PL license) to help people learn the techniques behind developing rich, platform-consistent controls, to see how we solved a particular problem, or to make tweaks and improvements to the controls themselves! The idea is to publish the Windows Phone Toolkit every few months or so; each release will include new controls, improvements to existing controls, and fixes for any bugs people run into. If you have a suggestion for something we should add or change, please search for that issue in the CodePlex issue tracker and vote for it (or create a new issue if your idea is unique). We pay attention to the number of votes an issue has when prioritizing our efforts - it helps ensure we're delivering what the community wants!

     

    Okay, after all that intro and background, you're probably wondering what's actually in the Phone Toolkit... :)

     

    What's in the Phone Toolkit?

    ContextMenu and ContextMenuService

    ContextMenu sample

    In desktop applications, ContextMenu is handy because it lets the second mouse button perform additional, contextually-relevant tasks; but on the phone, it's practically a requirement! Phone-sized UIs need to use every pixel to its fullest advantage, so being able to hide secondary commands behind a tap+hold gesture is a great way to keep the interface clean and easy to read.

    The Windows Phone Toolkit's ContextMenu control is a direct port of the Silverlight 4 Toolkit's ContextMenu (read more about what it does and how it works here) with additional Windows Phone-specific functionality added on top. So the Phone ContextMenu uses the same, great 100% Silverlight- and WPF-compatible ItemsControl-based API you know and love - plus it looks good on the phone and behaves just like the system's ContextMenu does! Which means ContextMenu (along with its helper ContextMenuService) is simple to use and makes it easy for Windows Phone applications to maintain platform-consistent appearance and behavior. (And for advanced scenarios, ContextMenu supports the ICommand interface, data-binding (of and to) items, Separator, and more!)

    Here's the XAML for the example above:

    <Border
        Background="{StaticResource PhoneChromeBrush}"
        Padding="20">
        <toolkit:ContextMenuService.ContextMenu>
            <toolkit:ContextMenu>
                <toolkit:MenuItem
                    Header="gray text"
                    Click="MenuGrayTextClick"/>
                <toolkit:MenuItem
                    Header="normal text"
                    Click="MenuNormalTextClick"/>
            </toolkit:ContextMenu>
        </toolkit:ContextMenuService.ContextMenu>
        <TextBlock
            x:Name="MenuTextBlock"
            Text="Tap and hold for ContextMenu"
            HorizontalAlignment="Center"/>
    </Border>

     

    DatePicker and TimePicker

    DatePicker and TimePicker sample buttons DatePicker and TimePicker sample picker

    Windows Phone 7 includes a cool, distinctive UI for choosing dates and times: three vertical spinners create a fun "endless looping" experience that people really enjoy using. The Phone Toolkit's DatePicker and TimePicker controls implement the exact same experience as the core controls, so it's easy to add date and time selection to your own application!

    What's more, these controls are both culture-aware and automatically configure themselves according to the settings on the user's phone (ex: d/m/y vs. m/d/y date formats and 12- vs. 24-hour time format). The API for DatePicker and TimePicker will be familiar to anyone who's used similar "picker" controls in the past. The Header convenience property simplifies the task of labeling either control - in a platform-consistent font and style!

    Here's the XAML for the example above and to the right:

    <toolkit:DatePicker
        Header="Date"
        Value="9/16/2010"
        ValueChanged="DatePickerValueChanged"/>
    <toolkit:TimePicker
        Header="Time"
        Value="12:34 pm"
        ValueChanged="TimePickerValueChanged"/>

     

    ToggleSwitch

    ToggleSwitch sample

    The Windows Phone UI for toggling settings on and off will be immediately familiar to anyone who's used a light switch (or an iDevice). Because there are subtleties to the core controls that are tricky to get right, the Toolkit includes the ToggleSwitch control! Continuing the theme of "make it easy to match the core behavior", ToggleSwitch looks, feels, and acts just like Windows Phone users will expect - including supporting flicks and swipes. In addition to subclassing ToggleButton for consistency and usability, ToggleSwitch supports the Header convenience property to make it easy to create properly-spaced settings pages. And if the need arises, you can also provide custom Content or pull the ToggleSwitchButton primitive control out and use it directly!

    Here's the XAML for the example above:

    <toolkit:ToggleSwitch
        Header="Some feature"
        IsChecked="true"
        Checked="ToggleSwitchChanged"
        Unchecked="ToggleSwitchChanged"/>

     

    GestureListener and GestureService

    GestureService and GestureListener sample

    Touch interfaces are a lot more interactive and engaging than the conventional mouse+keyboard UI most people are used to. One of the neatest things about touch UIs are their ability to translate natural human gestures into meaningful commands. Taking good advantage of touch and gestures can significantly improve the user experience and really help an application stand out from the crowd.

    To make gestures easy to work with, the Phone Toolkit includes the GestureService and GestureListener classes which provide events for the following gestures: tap, double-tap, hold, flick, drag (started/delta/completed), and pinch (started/delta/completed). All these gestures respect the relevant system parameters (ex: movement threshold, input timing, etc.), so applications that use GestureListener feel familiar and natural. All the developer needs to do is associate a GestureListener with the element(s) of interest and handle the corresponding gesture event(s) as they show up!

    For more background on gestures, here's a nice, easy to visualize overview for Windows 7 (not identical, but close) and here's a detailed document specific to windows Phone 7.

    Here's the XAML for the example above (note that typical applications will only hook up to the event(s) they care about):

    <Border
        Background="{StaticResource PhoneChromeBrush}"
        Padding="40">
        <toolkit:GestureService.GestureListener>
            <toolkit:GestureListener
                Tap="GestureListenerTap"
                DoubleTap="GestureListenerDoubleTap"
                Hold="GestureListenerHold"
                Flick="GestureListenerFlick"
                DragStarted="GestureListenerDragStarted"
                DragDelta="GestureListenerDragDelta"
                DragCompleted="GestureListenerDragCompleted"
                PinchStarted="GestureListenerPinchStarted"
                PinchDelta="GestureListenerPinchDelta"
                PinchCompleted="GestureListenerPinchCompleted"/>
        </toolkit:GestureService.GestureListener>
        <TextBlock
            x:Name="GestureTextBlock"
            Text="Perform any gesture here"
            HorizontalAlignment="Center"/>
    </Border>

     

    WrapPanel

    WrapPanel sample

    It may not be the sexiest of the Panel classes, but WrapPanel is a tremendously useful layout container! Lots of Windows Phone developers have been using this control from the Silverlight 3 Toolkit (either by referencing that assembly or by copying the code into their projects), but that can be a little tricky - so we thought we'd make it super easy by including WrapPanel in the Phone Toolkit! WrapPanel's "put as much stuff on a line as fits, then wrap to the next line" approach works particularly well on the phone - especially for scenarios where the sizes of things can vary (ex: during the transition from portrait orientation to landscape).

    Here's the XAML for the example above:

    <toolkit:WrapPanel>
        <Button Content="Here"/>
        <Button Content="is"/>
        <Button Content="some"/>
        <Button Content="simple"/>
        <Button Content="content"/>
        <Button Content="that"/>
        <Button Content="wraps"/>
        <Button Content="to"/>
        <Button Content="fit"/>
        <Button Content="the"/>
        <Button Content="screen"/>
    </toolkit:WrapPanel>

     

    [Click here to download the sample application used to create all the examples shown here.]

     

    Helpful Hints for Hopeful Heroes

    Here are a few tips and tidbits to help fledgling Windows Phone 7 developers make the most of the Phone Toolkit:

    • The examples I show here are from my own (deliberately simple) sample application, but there's also a more comprehensive sample application that shows off more sophisticated scenarios. The complete source code for the entire Phone Toolkit (including the sample application) can be downloaded from the CodePlex release page or the CodePlex source code page or by using any of the supported version control system clients (ex: TFS, SVN, etc.).

    • Some (but not all) of the ContextMenus used by the core phone applications get a little fancy when they show the menu: they shrink the UI of the rest of the application in the background. Because we strive to help developers create consistent applications, the Toolkit's ContextMenu does this by default as well.

      But because it's not part of the application itself, our ContextMenu's behavior needs to be as self-contained as possible - which means it can not modify the existing visuals in order to create this effect. (Otherwise it might make an unexpected change that crashes the developer's application!) Therefore, the "shrink" effect is implemented by capturing a "background" screen shot of the entire application, layering it over an opaque PhoneBackgroundBrush layer to avoid transparent areas leaking through, creating a "active element" screen shot capture of just the element that was tap+held, layering this over a correspondingly-sized opaque PhoneBackgroundBrush layer (to avoid transparency issues again), creating a "menu" layer for the actual menu items, layering everything over the running application by putting it in a Popup, and finally animating the scale of the "background" layers. Whew - if that sounds like a lot of effort, it is... :)

      The good news is this works pretty well in practice and duplicates the core effect fairly authentically - the less good news is that certain page designs poke little holes in the sleight-of-hand ContextMenu is doing. In many cases, such issues can be resolved by modifying the target element (the one to which the ContextMenu is attached) to have a non-transparent background. (ContextMenu's PhoneBackgroundBrush guess is the best it can do, but the application developer can sometimes do better.)

      But if you still can't get the effect you're looking for - or if you just don't like the default "shrink and grow" behavior (the core applications don't use it everywhere, either!) - then you can set the (Phone-specific) ContextMenu.IsZoomEnabled property to false in order to disable the custom animation and get rid of all this goofy complexity. In every case I know of so far, developers who resorted to IsZoomEnabled were quite happy with the results! :)

    • Icon configuration When you first add DatePicker or TimePicker to your application, you'll find that the "done" and "cancel" ApplicationBar icons shown when the pickers are opened are wrong. That's because the icons aren't actually being loaded - and that's because of a platform restriction. Specifically, the ApplicationBarButton.IconUri property will only load images that are part of the project and marked with Build Action=Content in the property editor. This means there's no good way for an assembly like the Phone Toolkit assembly to bundle such icons within itself (like there would be if the IconUri property supported the assembly-relative syntax "/assemblyShortName;component/resourceLocation").

      As a result, it's necessary for application developers to add these two icons to a well-known path in their project where DatePicker and TimePicker will automatically use them. For your convenience, we've bundled these two icons along with the Toolkit installer and they're already on your machine! :) To find them, open the Start Menu, expand the "Microsoft Silverlight for Windows Phone Toolkit" folder, and click on the "Binaries" item. This will open a Windows Explorer view of the install location of the Phone Toolkit (something like C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Toolkit\Sep10\Bin). The icons can be found in the "Icons" sub-folder within.

      To use these two icons in an application, right click the application's project node in the Visual Studio Solution Explorer, choose "Add", choose "New Folder", and rename it "Toolkit.Content". Then right-click on the new folder, choose "Add", choose "Existing Item...", navigate to the Phone Toolkit's install directory, select both icons, and hit "OK". Right-click each icon and change its "Build Action" to "Content"; re-run the application, and they'll show up just like you expect! (And if any of that seemed confusing, just look at how the sample application is configured - match that and you'll be fine.)

    • If you already know Windows Phone 7 supports different themes ("Light" and "Dark", AKA "white background" and "black background"), you might wonder why it's not necessary to provide "Light" and "Dark" versions of each icon... Well, the platform's a little clever here - it will automatically "Light"-ify "Dark" icons when the "Light" theme is active. Therefore, all we need to do is provide is "Dark" versions of the icons - the system converts them for us!

      Note: The reverse is not true; "Light" icons will not be "Dark"-ified for you. (So it seems like maybe the "Dark" side is more powerful?)
    • We've already discussed the reasons why it's good for controls to use the Popup control (because it keeps things isolated from the rest of the application), so DatePicker and TimePicker obviously use Popup too, right? Wrong! :)

      To be fair, DatePicker and TimePicker originally used a Popup for exactly those reasons. And life was good. Except when you tried to scroll the time/date spinners in the picker view... It worked okay, but the frame-rate was pretty low - almost as if the animations weren't happening on the composition (render) thread like they were supposed to... And, indeed, they weren't! It turns out the phone platform doesn't apply hardware acceleration to content in a Popup. :(

      Enough people were unhappy with the performance that DatePicker and TimePicker were modified to use a PhoneApplicationPage-based model instead. What this means is that instead of opening a Popup to hold the picker's spinner UI, these controls instead call NavigationService.Navigate("...") and point it to a Page subclass that's hosted in the same control assembly. The platform doesn't care where it loads pages from, so it happily navigates to the new Page, which then loads the spinners, which benefit from hardware acceleration, and therefore scroll smoothly!

      If this sounds like a wonderful solution, that's because it is - mostly. The big drawback to the Page-based approach is that it subtly breaks one of the guidelines of control development we discussed above: don't make changes that affect the application. In this case, if the application is already listening to the NavigationService's Navigating or Navigated events, then it will also see the "hidden" navigations that DatePicker and TimePicker are performing.

      Whether this is a problem or not depends on what the application is doing and how it's doing it. The good news is that most applications don't track navigations and won't need to worry about this at all; for applications that do track navigations, the good news is that this scenario is easy to detect. Specifically, if the object exposed by NavigationEventArgs.Content during a navigation implements IDateTimePickerPage, then the current navigation is part of DatePicker or TimePicker's behavior and should be ignored by the application. Applications that follow that simple guideline should be safe; applications that ignore it and play tricks like cancelling DatePicker and TimePicker navigations will most likely break stuff. :(

    • Now that I've thoroughly scared everyone away from ever using Page-based navigations, let me back-pedal a bit and say that there are some cool things you can do with them! In particular, DatePicker and TimePicker allow you to customize their destination Page which lets you completely change the picker experience for both of them. But I've already gone on long enough here; that'll be the topic of a subsequent blog post... :)

     

    We've had a lot of fun building the Silverlight for Windows Phone Toolkit - and we hope you have a lot of fun using it! Everything in the Phone Toolkit is there because there was strong customer demand. The Silverlight Toolkit team has heard you loud and clear, and we're doing our best to make your Windows Phone 7 development experience as pleasant and productive as possible!

    Okay, enough chatter for now - go download the developer tools and get busy building great applications! :)

  • Delay's Blog

    My new home page, enhanced [Updated collection of great Silverlight/WPF Data Visualization resources!]

    • 10 Comments

    In the time since posting my last collection of Silverlight/WPF Charting links, there's been some great activity! Of particular significance, the June 2009 WPF Toolkit includes the same Data Visualization goodness that was introduced for Silverlight and the July 2009 release of the Silverlight Toolkit added a TreeMap control. Without further ado, here are the latest links (FYI: previously published links are gray):

    Overviews (100 level)

    Scenarios (200 level)

    Internals (300 level)

    Team Member posts (Partner level)

    My posts (Ego level)

    Many, many thanks to everyone who's spent time helping others learn how to use Silverlight/WPF Data Visualization!

    PS - If I've missed any good resources, please leave a comment with a link - I'm always happy to find more good stuff! :)

  • Delay's Blog

    IValueConverter: The Swiss Army Knife of Bindings [PropertyViewer sample is a WPF/Silverlight visualization and debugging aid!]

    • 14 Comments

    If you've made much use of data binding in WPF or Silverlight, you've probably come across the IValueConverter interface. IValueConverter sits between the data source and destination and gives the developer a chance to examine/alter/replace the data as it flows through the converter. It's been my experience that IValueConverter is a powerful and versatile tool for application developers.

    As part of a recent project, I wanted to display some of an object's properties in a simple list. Specifically, I had an instance and I wanted to display a list of "Property Name: Property Value" entries for each property of that object. My background with ListBox led me to naturally think of using ItemsControl for the basis of my property viewer; the ItemsControl content model (with its support for DataTemplates) seemed like a natural fit.

    Aside: One of the key things XAML enables is a distinct separation of implementation from representation. By explicitly separating most aspects of how an application looks (XAML) from how it works (code) as part of the developer/designer workflow, WPF and Silverlight help to enforce a level of encapsulation (in the object-oriented programming sense) that makes programs easier to write and maintain. In the ideal world, a program's functionality is entirely expressed in its code - and so it's possible for others to completely change that application's appearance without knowing or caring how it's implemented. Just like the web has CSS restyling contests, WPF has reskinning competitions!

    So I knew I wanted to use ItemsControl and I knew I wanted to keep the UI aspects of the property viewer in XAML-space (what it looked like, what properties it displayed, etc.). I started looking at how IValueConverter might help and that led to the solution I describe here. PropertyViewer ends up being quite simple to use - and a good demonstration of the power of IValueConverter!

    Here's the comment header from the code:

    /// <summary>
    /// IValueConverter implementation that expands some/all of an object's
    /// public properties as a collection of bindable name/value instances.
    /// </summary>
    /// <remarks>
    /// * Bindable instances are of type PropertyDetails, a contained class
    ///   that exposes a property's Name and Value as properties.
    /// * All public properties are enumerated by default; ConverterParameter
    ///   can be used to specify which properties will be enumerated (and in
    ///   which order) by passing a space-delimited list of names.
    /// * If DisplayNameAttribute is associated with a property, DisplayName
    ///   will be used instead of the property name.
    /// * PropertyViewer can be used for simple data visualization, debugging
    ///   of Bindings, and more.
    /// </remarks>
    /// <example>
    /// For ItemsControl/ListBox (accessing the object via DataContext):
    ///   ItemsSource="{Binding Converter={StaticResource PropertyViewer}}"
    /// As above, but with a custom property list:
    ///   ItemsSource="{Binding Converter={StaticResource PropertyViewer},
    ///     ConverterParameter='PropertA PropertyB'}}"
    /// For ItemsControl/ListBox, but specifying the object via Source:
    ///   ItemsSource="{Binding Source={StaticResource ObjectInstance}
    ///     Converter={StaticResource PropertyViewer}}"
    /// </example>
    public class PropertyViewer : IValueConverter
    { ... }
    

    Like the comment says, it's easy to hook up a PropertyViewer:

    <ItemsControl ItemsSource="{Binding Converter={StaticResource PropertyViewer}}"/>

    Customizing the PropertyViewer is also easy:

    <ItemsControl ItemsSource="{Binding Converter={StaticResource PropertyViewer},
        ConverterParameter='Species EatsBugs RelativeMass'}">
    

    Because the end result is a collection of objects, all the existing ItemsControl knowledge and techniques can be used to completely customize the look and feel of the property viewer!

    The examples above came from a simple application I wrote to demonstrate PropertyViewer in action. By design, the exact same XAML and code work on both WPF and Silverlight. To prove it, I attached the complete source code for the combined Visual Studio 2008 solution to this blog (download it from the link at the bottom of this post). The sample displays a list of animals, one default PropertyViewer, and one customized PropertyViewer. Select any animal to find out more about it (note that the PropertyViewer updates automatically when the data source changes).

    Here's what it looks like on WPF:

    WPF Sample

    And on Silverlight:

    Silverlight Sample

    Thanks to the power of IValueConverter, it's easy to use PropertyViewer to display an object's properties in a customizable way. Additionally, PropertyViewer can help troubleshoot data bindings: just drop one in the target location and you can see the available properties along with their current values. I originally wrote this for my project - but now I hope you can use it in yours!

  • Delay's Blog

    Mo controls, mo controls, mo controls... [Announcing the second release of the Silverlight for Windows Phone Toolkit!]

    • 56 Comments

    I'm happy to report that we've just published the Silverlight for Windows Phone Toolkit November 2010 release! This is the second iteration of the Windows Phone Toolkit and effectively doubles the number of controls we've created to help developers and designers build more compelling, more platform-consistent user experiences with ease. The first Windows Phone Toolkit release has been a big hit and we've seen a lot of developers using it (in both binary and source forms) to build their Windows Phone 7 applications. But while we tried to address the most pressing needs with that release, there were still a couple of prominent controls missing...

    With today's update, we've tried to provide more of the fundamental controls customers have been asking for - as well as API documentation and fixes for some of the bugs people reported with the first release. Recall that the Windows Phone Toolkit is published on CodePlex under the Ms-PL open-source license so anyone who wants can look at the source code to learn how we've done things - or customize any control to suit their specific scenario. As always, if you have suggestions for things we should add or change, please search the CodePlex issue tracker and vote for the issue (or create a new one if the idea is unique). We use your input to help prioritize our efforts and ensure we're delivering the right things for the community!

     

    What's New?

     

    ListPicker

    ListPicker sample ListPicker popup sample
    <toolkit:ListPicker Header="background">
        <sys:String>dark</sys:String>
        <sys:String>light</sys:String>
        <sys:String>dazzle</sys:String>
    </toolkit:ListPicker>

    ListPicker is the Windows Phone 7 equivalent of the ComboBox control: give it a list of items and it will show the selected one and also allow the user to pick from a list if they want to change it. The core applications on Windows Phone 7 implement two kinds of list selection: an in-place expander for picking among five or fewer items, and a full-screen popup for picking among more. The Toolkit's ListPicker control combines both experiences into one handy package by automatically selecting the right UX based on the number of items in its list! It is a standard ItemsControl subclass with all the common elements of a Selector, so the API will be familiar to just about everyone. In fact, you can take most existing ListBoxes and convert them to ListPickers just by changing the control name in XAML!

     

    LongListSelector

    LongListSelector movies sample LongListSelector people sample LongListSelector jump-list sample
    <toolkit:LongListSelector
        ItemsSource="{StaticResource movies}"
        ListHeaderTemplate="{StaticResource movieListHeader}"
        GroupHeaderTemplate="{StaticResource movieGroupHeader}"
        GroupFooterTemplate="{StaticResource movieGroupFooter}"
        GroupItemTemplate="{StaticResource groupItemHeader}"
        ItemTemplate="{StaticResource movieItemTemplate}">
    </toolkit:LongListSelector>

    While ListPicker is about simple selection scenarios, LongListSelector is about advanced ones! Think of it as ListBox++--, it has everything you expect from ListBox plus a bunch of advanced capabilities and great on-device performance minus the levels of abstraction and generality that tend to slow ListBox down. LongListSelector supports full data and UI virtualization, flat lists, grouped lists (with headers!), and also implements the "jump list" header navigation UI that makes the "People" app so efficient! The theory behind LongListSelector is that it should be easy to fix a poorly-performing ListBox scenario by swapping in a LongListSelector instead: it handles all the tricky parts for you, so there's less to worry about and it "just works". Unless you've spent a lot of time fine-tuning your application's list behavior, you should see improved performance by switching to LongListSelector!

     

    TransitionFrame (and Transitions)

    TransitionFrame sample
    RootFrame = new TransitionFrame();
    <toolkit:TransitionService.NavigationInTransition>
        <toolkit:NavigationInTransition>
            <toolkit:NavigationInTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardIn"/>
            </toolkit:NavigationInTransition.Backward>
            <toolkit:NavigationInTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardIn"/>
            </toolkit:NavigationInTransition.Forward>
        </toolkit:NavigationInTransition>
    </toolkit:TransitionService.NavigationInTransition>
    <toolkit:TransitionService.NavigationOutTransition>
        <toolkit:NavigationOutTransition>
            <toolkit:NavigationOutTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardOut"/>
            </toolkit:NavigationOutTransition.Backward>
            <toolkit:NavigationOutTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardOut"/>
            </toolkit:NavigationOutTransition.Forward>
        </toolkit:NavigationOutTransition>
    </toolkit:TransitionService.NavigationOutTransition>

    The Windows Phone UI Guidelines encourage smooth, attractive page-to-page animations like the core applications show, but there has been little platform support for creating similar experiences in your own applications - until now! :) The new transition classes in the Windows Phone Toolkit aims to make it easy for application developers to add attractive, platform-consistent transitions to their applications. All that's necessary to enable transitions for an application's pages is tweak App.xaml.cs (shown above) and add a bit of XAML to each page to specify its transitions (also shown above). Everything else is done for you!

    Aside: This release includes support for multiple flavors of the following transitions: turnstile, slide, rotate, swivel, and roll. It's also possible to implement custom transitions using the same framework!

     

    AutoCompleteBox

    AutoCompleteBox sample
    <toolkit:AutoCompleteBox
        ItemsSource="{StaticResource words}"/>

    AutoCompleteBox first appeared in the Silverlight 2 Toolkit, then later graduated to the Silverlight 3 SDK. Now it's back in the Toolkit - this time for Windows Phone 7! Because phones are about being small and quick to use, simplifying tedious tasks like text input is an important goal. Toward that end, a number of the core applications (like Bing search) make use of auto-completion to predict what the user is typing and save time by allowing them to click on the completed word instead. AutoCompleteBox makes it easy to bring the same convenience to your own applications by taking advantage of a phone-friendly implementation of this popular Silverlight control. By providing a suitable completion list (in any of a variety of ways), users are automatically prompted with the relevant matches as they start typing!

     

    API Documentation

    CHM file example

    The source code for the Windows Phone Toolkit has included full XML Documentation Comments from the beginning, but now we've begun generating a separate CHM file with all the property/method/event comments in a single, easy-to-browse location. The documentation file is automatically installed by the Windows Phone Toolkit installer and a handy link is added to the "Silverlight for Windows Phone Toolkit" folder in the Start Menu. Because we don't have dedicated documentation writers on the Toolkit team, our documentation is a bit on the terse side - but the CHM file is still a great way to survey the Toolkit classes and get a feel for what's available. And because the sample syntax is available in both C# and VB, everyone should be comfortable with the examples!

     

    Bug fixes for existing controls

    The previous Toolkit release wasn't all that long ago and we've been quite busy since then, but we've still managed to squeeze in fixes for some of the more annoying bugs customers reported. That's not to say that we fixed them all or that we had a chance to squash your favorite bug, but we were fortunate to be able to fix a good number of customer-impacting issues and I hope everyone finds the new controls even more pleasant to use! :)

     

    [Click here to download the Silverlight for Windows Phone Toolkit November 2010 release.]

     

    The screen shots and XAML shown above are all from the sample application you can download along with the Toolkit. I encourage people to play around with the sample if they want to experiment with any of these controls (in the emulator or on the device) or if they want to learn more about how these controls work. I anticipate more in-depth coverage will show up in the coming weeks (I will be posting a detailed ListPicker overview tomorrow!), but for now the sample application is a great springboard to get folks started!

     

    In closing, I'm really glad we've been able to get this second round of controls out to the community in such a short time! While there are probably still some "nice to have" controls that could be added to further round-out the Windows Phone 7 control offering, I think that what we've included in the Windows Phone Toolkit represents nearly all the critical ones needed to unblock important scenarios. I hope people continue to enjoy their Windows Phone development experience and that the new Windows Phone Toolkit makes application development even easier! :)

  • Delay's Blog

    Click your way to great Silverlight charts [Live ChartBuilder sample and source code!]

    • 20 Comments

    Yesterday in my Introduction to Charting with the Silverlight Toolkit post, I included a teaser for my ChartBuilder application. The tease ends today, because I've just posted a live ChartBuilder for everyone to play with and am also making the source code available for download.

    What is ChartBuilder?

    In addition to driving the Silverlight Charting effort and being one of the primary developers, I was also the entire test team for Charting. (I told you we were resource constrained.) I decided pretty quickly that I needed to do what I could to make it easy for anyone to exercise the Charting implementation, find bugs, and report them. Additionally, I wanted an easy way for the developers to exercise what they'd written in strange and unusual ways. My task was somewhat complicated by the fact that Charting supports fully dynamic data sources - static XAML Charts simply aren't enough to cover all the scenarios we care about.

    I tried to capture a hint of this dynamic behavior in the samples project (I wrote all the samples, too - except for the two fantastic Scenarios which were contributed by Ted Glaza (Custom Series) and Ruurd Boeke (Series Zoom)). But the sample project isn't the most debugging-friendly environment because of all the different Chart instances it loads. Last - but certainly not least - I knew there would be a lot of customers looking at Charting with very little idea how our API and object model work.

    I had a vision for an interactive chart-building application that would expose the most common Charting concepts with some simple UI, show how those settings combined to create a chart, AND show the corresponding XAML code to build that chart. What's more, I wanted changes to the chart's settings to be made in real-time to the running instance of the chart so that users could see how the dynamic data support actually works. (And so developers could fix it when it didn't!) And because it was so easy, I enabled a live XAML editing experience (think XAMLPad) for folks who demand absolute control over their charts. :)

    What does it look like? How do I play with it?

    Below is a static image of ChartBuilder as it existed yesterday to give an idea of what I'm talking about.

    Better yet, you can click this text or the image below to run the latest ChartBuilder in your browser!

    ChartBuilder

    [Click here to download the complete ChartBuilder source code.]

    The left side of the application is where you go to customize your chart, the upper-right side of the application shows the current chart, and the lower-right side shows the complete XAML for that chart (wrapped in a Grid to keep the XAML clean).

    Changes you make to the settings are automatically applied to the running instance of the chart as well as the XAML for that chart - so if you're curious how the API and object model look, just set things up how you want them and look at the XAML! As a convenience, the XAML area supports copying to the clipboard (use Ctrl+C or whatever your platform's standard "copy" keystroke is). That means you can build a chart you like and then paste the XAML right into your own source code to help get started.

    If you ever do something that's not allowed - or hit a bug - and an exception is thrown, the complete exception details will appear in a red text box over the chart - which can also be copied to the clipboard. ChartBuilder will let you continue to change the settings and keep going after an exception, but please bear in mind that some exceptions may leave the chart with inconsistent internal state. At any time you can hit the green "Recreate Chart" button to completely recreate the chart instance from the current settings and get everything back in sync.

    Anything else I should know?

    • ChartBuilder is a dual-edged sword: the same power that lets you explore strange and creative new scenarios also lets you do things that are not supported. We've tried to throw informative exceptions whenever we detect something unusual, so please read the exception message for details about what went wrong.
    • Of course, if an exception message makes no sense, or a broken scenario seems like it should be supported, or things just seem to be flat-out wrong, please post a question in the Silverlight Controls forum or report a bug with the Silverlight Toolkit Issue Tracker. When reporting issues, please include as much detail as possible; ChartBuilder makes that easy by letting you copy the entire exception text. What's more, if you can reproduce the problem reliably, then you can report it by giving us a simple list of steps to follow in ChartBuilder! Problems that are demonstrated by ChartBuilder scenarios are usually a pleasure to debug because it's so easy to tell what's going on and so easy to isolate the problematic behavior. [Well, most of the time! :) ]
    • One thing I did not do with ChartBuilder is spend a lot of time designing or implementing a comprehensive architecture for the application. More often than not, the little bits of time I found for adding features were spent in a frenzy of coding with me trying to enable new testing scenario as quickly as possible. When forced to choose between refactoring and getting a new feature implemented, the new feature always won. I've made a quick pass over the code since PDC and it's not as bad as I feared - but I guarantee it won't be winning any beauty contests. :)
    • Because ChartBuilder was written to validate the functionality of Charting, it would be ideal if ChartBuilder itself were bug-free. While I've done what I can to try to make that so, I'm sure a few things have slipped by here and there - in no small part because of the hurried conditions under which I added features to ChartBuilder. If you see a strange behavior and don't think it's a bug in Charting, please let me know because it may be ChartBuilder that's at fault!

    Are there any good usability tricks worth sharing?

    • Not all series types support all axis combinations. Specifically, it's not possible to put a column series and a bar series in the same chart because they put their independent/dependent axes in different places. Similarly, column and line don't go together because column only supports a category-based independent axis while line only supports a value-based (numeric or date) independent axis. Here's a quick cheat-sheet:
      Series Independent axis Works with
      Column Category Column, Pie
      Bar Vertical Category Bar, Pie
      Pie N/A Everything
      Line Number/Date Line, Scatter, Pie
      Scatter Number/Date Line, Scatter, Pie
    • The text input boxes validate their contents and update the chart state after every key press. This can make it tricky to make certain changes because the intermediate states are invalid. If you run into this situation, there are two tricks to try. First, see if you can select part of the text field and then type over it (ex: "10/28/2008" can be change to "10/29/2008" in one step by selecting the '8' and typing a '9'). If that doesn't help, another option is to open a Notepad window, type what you want there, copy it to the clipboard, select the entire text box in ChartBuilder and paste over it with the intended value.
    • The "Number of Axes" slider is disabled whenever there are one or more series present. This is because as soon as a series is rendered, it automatically creates whatever axes it needs to display itself - so if the user tried to add another axis, there would be multiple horizontal/vertical axes. At this time, Charting supports only a single horizontal and a single vertical axis - though please note that this restriction will be removed in an upcoming release to support multiple horizontal and vertical axes on the same chart. So if you want to customize the axes for your chart, first remove all the series, then add the axes you want, then add the series back - assuming the axis configuration that's set is supported by the series that are added, they will automatically use the provided axes and you will be able to customize them dynamically.
    • When "Allow XAML Editing" is checked, the XAML is completely re-parsed and the chart re-created after every keystroke. Similarly, when unchecking that option, the state stored in the input controls on the left is re-applied and the text in the XAML editing box is lost. Basically, once the option to edit XAML is enabled, ChartBuilder has no idea what the user has done and no way of mapping that back to the subset of changes it supports. So feel free to experiment with XAML mode (it's great for stuff like adding a colored background or extra data), but know that you're completely on your own when you do so.
    • ChartBuilder makes use of two classes it exposes via the "utility" XML namespace: ObservableObjectCollection and Pair. ObservableObjectCollection is simply an ObservableCollection<object> and Pair is just an object that exposes two properties "First" and "Second" of type object. These are purely convenience classes that make the XAML easy to deal with; you're welcome to make use of them in your own application if you care to.
    • ChartBuilder does its best to capture all exceptions that occur and display them in its user interface. This is quite handy when running outside of Visual Studio, but in order for it to have a chance to work when running under a debugger, be sure to configure the debugger to ignore handled exceptions (or just hit F5 when one occurs to allow ChartBuilder to catch and handle the exception).

    What are examples of some issues I might encounter?

    • Removing and re-adding a series over and over gives that series a different color each time. This is an artifact of how the Chart.StylePalette collection works: each time a new style is needed, it is fetched from the palette and the "next style" index incremented. So as long as the same chart instance is being used, recreating a series over and over gradually cycles through all the different colors of the default style palette. As soon as a new chart instance is created, the style palette is reset and the colors start from the beginning. In other words, the "random" behavior is completely deterministic and will always be the same for a particular application. If you want to guarantee that a particular series will always have the same color no matter what, there is a DataPointStyle property on Column/Bar/Line/ScatterSeries and a dedicated StylePalette property on PieSeries that can be set in code (but is not exposed by ChartBuilder at this time).
    • Removing the Chart (or Legend) Title does not automatically recover the space used by the text of that control (until something like a resize causes another layout pass). This is actually a Silverlight bug with ContentControl (which is what Title is) and can be reproduced outside Charting by placing a ContentControl in a StackPanel between two other elements and setting its Content property to null. This bug has been reported to the Silverlight team and should be fixed in a future release.
    • The default appearance of the line and scatter charts in "Automatic Doubles" mode is always a straight line (with a slope of 1) and the points just slide along it. "Manual Pairs" mode is the only mode that really makes sense for line and scatter because they need numeric independent values - but just so that "Automatic Doubles" and "Manual Doubles" modes show something, ChartBuilder automatically sets their IndependentValueBinding to "{Binding}". This provides an independent value, but it's always the same as the dependent value and so the points always lie on the same line. To really exercise line and scatter, switch to "Manual Pairs" mode, click the "All Doubles" button for both columns, enable a couple of points, and then have fun changing values.
    • Adding a point to the middle of the collection for line, bar, and pie charts adds that point to the end of the visual series. ChartBuilder's "Manual Doubles" and "Manual Pairs" modes allow you to individually enable and disable points - and specifically to "insert" points at the beginning, middle, or end of the collection. This is what ChartBuilder does internally (verify by looking at the XAML or clicking "Recreate Chart"), but the aforementioned series add that point to the end of their internal collections, so the new point always shows up after the existing points. This is a known issue to be addressed in a future release of Charting; it can be worked around for now by clicking "Recreate Chart".
    • Multiple occurrences of the same data point instance in the collection can get their visual representations mixed up. This can be seen by starting from the default ChartBuilder configuration, then increasing the "Starting Value" twice (from 1 to 3) - the columns of the resulting chart should increase in height from left to right, but do not. What happens is that the collection goes from [2, 3, ...] to [3, 3.6, ...] when the starting value goes from 2 to 3. As soon as the first value of the collection changes from 2 to 3, there are two instances of the value 3 in the collection: [3, 3, ...]. When the second value changes from 3 to 3.6, the chart incorrectly updates the column corresponding to the first point. This is unfortunate behavior, but is actually also present in the WPF and Silverlight ListBox implementations (though it manifests itself differently there). The basic problem is that the chart tracks things by object identity and the presence of the same object multiple times creates ambiguity for the tracking code. The good news is that this problem is only really an issue when the data set contains raw doubles or integers - the far more common scenario (in practice) of using unique business objects is unaffected by this because each business object is a unique instance. To verify this, switch to "Manual Pairs" mode for the column series, enable three points, set all their values to 1, then change any of them to a different value and observe that the correct column is always updated.
    • Changing the independent value of a pie series data point (in "Manual Pairs" mode) does not automatically update the label for that data point in the legend. This is a known issue to be addressed in a future release of Charting; it can be worked around for now by clicking "Recreate Chart".
    • There are certain circumstances under which toggling "Show GridLines" and "Should Include Zero" for a custom axis cause the axis to disappear (and the chart not to render). This is a known issue to be addressed in a future release of Charting; it can be worked around for now by clicking "Recreate Chart".

    Any last words?

    I wrote ChartBuilder to help you learn about Charting as much as to help us develop Charting. If it provides everyone with a common language that helps make it easy to talk about Charting features, suggestions, and issues, I'll be delighted!

    And now... Enjoy! :)

  • Delay's Blog

    Script combining made better [Overview of improvements to the AJAX Control Toolkit's ToolkitScriptManager]

    • 14 Comments

    The 10606 release of the AJAX Control Toolkit introduced ToolkitScriptManager, a new class that extends the ASP.NET AJAX ScriptManager to perform automatic script combining. I blogged an overview of ToolkitScriptManager last week (including an explanation of what "script combining" is). This post will build on that overview to discuss some of the changes to ToolkitScriptManager in the 10618 release of the Toolkit.

    The most obvious change is the addition of an optional new property: CombineScriptsHandlerUrl. Left unset, ToolkitScriptManager works just like before; setting CombineScriptsHandlerUrl specifies the URL of an IHttpHandler (feel free to use @ WebHandler to implement it) that's used to serve the combined script files for that ToolkitScriptManager instance instead of piggybacking them on the host page itself. Implementing this handler is simple: just use the CombineScriptsHandler.ashx file that's part of the SampleWebSite that comes with the Toolkit! :) If you look at how that handler works, the ProcessRequest method simply calls through to the ToolkitScriptManager.OutputCombinedScriptFile(HttpContext context) method which is public and static for exactly this purpose. OutputCombinedScriptFile does all the work of generating the combined script file and outputting it via the supplied HttpContext - in fact, this is the same method that ToolkitScriptManager now uses internally to output a piggybacked combined script file. Because adding a handler in this manner doesn't require modifying the server configuration, CombineScriptsHandlerUrl can also be used by people in hosted and/or partial trust scenarios.

    At the end of my previous post, I mentioned two tradeoffs that were part of switching from ScriptManager to ToolkitScriptManager. Both of those tradeoffs are addressed by the 10618 ToolkitScriptManager - plus one more I didn't know about then and another that's implicit:

    • Using CombineScriptsHandlerUrl incurs no unnecessary load on the server. One of the tradeoffs of the piggyback method for generating combined script files is that it involves a little bit of extra processing as part of the host page's page lifecycle that's not strictly necessary for the purposes of generating the combined script file. ToolkitScriptManager manages the page lifecycle processing to minimize the impact of piggybacking, but can't eliminate it all. However, using CombineScriptsHandlerUrl with a dedicated IHttpHandler doesn't involve any such overhead and helps keep things as efficient and streamlined as possible. The host page doesn't get reinvoked and the dedicated IHttpHandler does no more than it needs to.
    • Using CombineScriptsHandlerUrl won't interfere with URL rewriting. Customers using URL rewriting with their web sites pointed out that the piggybacking approach to combined script generation might require them to revise their URL rewriting rules to account for the unexpected page requests with the special combined script request parameter. ToolkitScriptManager tries to be as easy to use as possible, so one of the nice things about setting the new CombineScriptsHandlerUrl property is that web site authors can choose whatever URL works best for them to be their combined script file handler, thereby avoiding conflict with existing URL rewriting rules.
    • Using CombineScriptsHandlerUrl makes it more likely that cached script files will be reused. When piggybacking combined script URLs, the presence of the host page's base URL in the combined script URL means that any cached script files generated by page A will not be usable by page B (which has a different base URL). Of course, once the user's browser caches the combined script files for pages A and B, the cached versions will be used and there is no server impact - but page B won't benefit from page A's cached file even if the combined script files are otherwise identical. When pages A and B both use the same set of extenders and CombineScriptsHandlerUrl is specified, the combined script file URL generated by pages A and B will be identical (because the combined script file handler base URL will be the same for both) and therefore the combined script file cached by the user's browser for page A will be automatically used for page B as well. For web sites with common extender usage patterns (such as a TextBoxWatermark'd search box in the corner of every page), the caching benefits of CombineScriptsHandlerUrl could be significant.
    • The URLs used to specify combined script files are considerably less verbose. Rather than including the full script name for every script in the combined script file (often upwards of 20 or 30 characters), the hexadecimal representation of their String.GetHashCode is used instead (8 or fewer characters). While the baseline combined script URL length has grown by a bit due to some other changes, by far the most significant source of URL length was the script names, so the new URLs are shorter and less likely to get long (even on pages with lots of extenders). This improvement applies whether CombineScriptsHandlerUrl is specified or not, so piggybacked URLs are shorter, too. Note: Because hash code collision is now possible (though extremely unlikely), there's a bit of code to detect that scenario and throw an informative exception. (Just change either of the script names slightly to resolve the collision.)

    A handful of other fixes and improvements were made to ToolkitScriptManager for the 10618 release. Notably:

    • The CurrentUICulture is now embedded in the combined script URL so that changing the browser's culture while viewing a site will properly update the culture of the site's extenders.
    • ToolkitScriptManager's check for a script's eligibility to participate in script combining now includes a check for the WebResource attribute which is one of the things that ASP.NET's ScriptResourceHandler requires in order to serve an embedded resource. Consequently, an assembly's embedded resources without a corresponding WebResource attribute are no longer eligible for script combining (without needing to use the ExcludeScripts to explicitly remove them). This makes ToolkitScriptManager's behavior more consistent with that of ScriptResourceHandler.
    • The "magic" request parameter for the combined script file changed from "_scriptcombiner_" to "_TSM_HiddenField_"/"_TSM_CombinedScripts_". _TSM_CombinedScripts_ is simply a rename of _scriptcombiner_, while _TSM_HiddenField_ now specifies the HiddenField that's used for tracking which scripts have already been loaded by the browser. This ID is implicitly available when piggybacking, but is not available in the CombineScriptsHandlerUrl case, so it has become part of the URL. For completeness, the new form of the combined script URL is now:
      .../[Page.aspx|Handler.ashx]?_TSM_HiddenField_=HiddenFieldID&_TSM_CombinedScripts_=;Assembly1.dll Version=1:Culture:MVID1:ScriptName1Hash:ScriptName2Hash;Assembly2.dll Version=2:Culture:MVID2:ScriptName3Hash

    If you're already using ToolkitScriptManager and want to start using CombineScriptsHandlerUrl, but don't want to have to modify a bunch of ASPX pages to add the new property, you can take advantage of the fact that ToolkitScriptManager is now decorated with the Themeable attribute and can be customized by a .skin file as part of ASP.NET's Theme/Skin support. Adding CombineScriptsHandlerUrl to all the pages of the Toolkit's SampleWebSite was easy - I just added a ToolkitScriptManager.skin file to the existing web site theme and used the code <ajaxToolkit:ToolkitScriptManager runat="server" CombineScriptsHandlerUrl="~/CombineScriptsHandler.ashx" /> to set CombineScriptsHandlerUrl for the entire site.

    ToolkitScriptManager is a handy way to enhance a web site with the AJAX Control Toolkit and it's gotten even better with the 10618 release of the Toolkit. We think ToolkitScriptManager offers some pretty compelling enhancements and we use it for all the AJAX Control Toolkit's sample content. We encourage anyone who's interested to give ToolkitScriptManager a try and see how well it works for them. As always, if there are any problems, please let us know by posting a detailed description of the problem to the AJAX Control Toolkit support forum.

    Happy script combining!!

Page 4 of 28 (277 items) «23456»