Delay's Blog

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

Posts
  • Delay's Blog

    Give your computer insomnia [Free tool and source code to temporarily prevent a machine from going to sleep!]

    • 111 Comments

    The default power settings for Windows are set up so a computer will go to sleep after 15 to 30 minutes of inactivity (i.e., no mouse or keyboard input). This is great because a computer that's not being used doesn't need to be running at full power. By letting an idle machine enter sleep mode, the user benefits from a significant reduction in electricity use, heat generation, component wear, etc.. And because sleep mode preserves the state of everything in memory, it's quick to enter, quick to exit, and doesn't affect the user's work-flow. All the same applications continue running, windows stay open and where they were, etc.. So sleep mode is a Good Thing and I'm a fan.

    However, sometimes a computer is busy even though someone isn't actively using the mouse and keyboard; common examples include playing a movie, burning a DVD, streaming music, etc.. In these cases, you don't want the machine to go to sleep because you're using it - even though you're not actually using it! So most media players and disc burners tell Windows not to go to sleep while they're running. In fact, there's a dedicated API for exactly this purpose: the SetThreadExecutionState Win32 Function.

    But what about those times when the computer is busy doing something and the relevant program doesn't suppress the default sleep behavior? For example, it might be downloading a large file, re-encoding a music collection, backing up the hard drive, or hashing the entire contents of the disk. You don't want the machine to go to sleep for now, but are otherwise happy with the default sleep behavior. Unfortunately, the easiest way I know of to temporarily suppress sleeping is to go to Control Panel, open the Power Options page, change the power plan settings, commit them - and then remember to undo everything once the task is finished. It's not hard; but it's kind of annoying...

     

    So here's a better way:

    Insomnia application

    Insomnia is a simple WPF application that calls the SetThreadExecutionState API to disable sleep mode for as long as it's running. (Note that the display can still power off during this time - it's just sleep for the computer that's blocked.) Closing the Insomnia window immediately restores whatever sleep mode was in effect before it was run. It couldn't be easier!

     

    [Click here to download the Insomnia application along with its complete source code.]

     

    Notes:

    • Insomnia basically boils down to a single function call - but to a function that's a Win32 API and is not part of the .NET Framework. This is where a very powerful feature saves the day: Platform Invoke. For those who aren't familiar with it, P/Invoke (as it's called) lets a managed application call into the APIs exposed by a native DLL. All it takes is a dash of the DllImport attribute and a little bit of translation from the Win32 types to their managed counterparts. The MSDN documentation goes into lots of detail here, and I encourage interested parties to go there.
    • One popular resource for P/Invoke assistance is PInvoke.net, where you can find managed definitions for hundreds of native APIs. But I usually just end up creating my own - if nothing else, it's a good learning exercise. :)
    • The Insomnia window has its Topmost property set to True so it's always visible and people will be less likely to accidentally leave their computers sleep-less. Other than taking up a small bit of screen space and memory, Insomnia consumes no system resources, so it won't get in the way of whatever else is running.
    • It is considered polite to leave things the way you found them, so Insomnia makes an extra call to SetThreadExecutionState when it's closed in order to restore things to how they were. However, this is really more for show than anything else, because the execution state is clearly per-thread and Insomnia's thread is about to die anyway.
    • I did a quick web search for similar tools before I wrote Insomnia and there are a few out there. Most of what I found was for Linux and Mac for some reason, but I'm sure Insomnia isn't the first of its kind for Windows. However, that doesn't stop it from being a nice introduction to P/Invoke - and besides, I'm always happier running my own code! :)

     

    Finally, here's the implementation:

    public partial class Window1 : Window
    {
        private uint m_previousExecutionState;
    
        public Window1()
        {
            InitializeComponent();
    
            // Set new state to prevent system sleep (note: still allows screen saver)
            m_previousExecutionState = NativeMethods.SetThreadExecutionState(
                NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED);
            if (0 == m_previousExecutionState)
            {
                MessageBox.Show("Call to SetThreadExecutionState failed unexpectedly.",
                    Title, MessageBoxButton.OK, MessageBoxImage.Error);
                // No way to recover; fail gracefully
                Close();
            }
        }
    
        protected override void OnClosed(System.EventArgs e)
        {
            base.OnClosed(e);
    
            // Restore previous state
            if (0 == NativeMethods.SetThreadExecutionState(m_previousExecutionState))
            {
                // No way to recover; already exiting
            }
        }
    
        private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            // Start an instance of the NavigateUri (in a browser window)
            Process.Start(((Hyperlink)sender).NavigateUri.ToString());
        }
    }
    
    internal static class NativeMethods
    {
        // Import SetThreadExecutionState Win32 API and necessary flags
        [DllImport("kernel32.dll")]
        public static extern uint SetThreadExecutionState(uint esFlags);
        public const uint ES_CONTINUOUS = 0x80000000;
        public const uint ES_SYSTEM_REQUIRED = 0x00000001;
    }
    
  • Delay's Blog

    WPF Charting: It's official! [June 2009 release of the WPF Toolkit is now available!]

    • 80 Comments

    The WPF Toolkit team just published the June 2009 release of the WPF Toolkit. Those of you who know I'm on the Silverlight Toolkit team are probably wondering why this is relevant - so let's get right to the release notes for the next version of Silverlight/WPF Charting because they'll clear things up:

     

    Notable Changes

    WPF is now an official platform for Charting! Today's release of the June 2009 WPF Toolkit includes the binaries for WPF Charting, the associated design-time assemblies for both Visual Studio 2008 and Blend 3, and the complete source code for everything (under the usual Ms-PL license). Prior to today, WPF Charting only existed informally because of a blog post I'd written and some bits I'd shared. As of today, that "do it yourself" approach is a thing of the past - customers can get signed binaries and ready-to-build source code for Charting as part of the WPF Toolkit. And, as always, Charting exposes the same API and supports the same XAML on both platforms - making application portability trivial!

    WPF Toolkit installer

    Improved performance of internal data structures for many common scenarios. Charting now makes use of left-leaning red-black trees to maintain properly balanced data structures. For more detail on this change, please refer to my post about the LeftLeaningRedBlackTree implementation.

    Numerous bug fixes for animation inconsistencies between Silverlight and WPF. Storyboards and Animations sometimes behave a little differently on Silverlight/WPF, and a good bit of effort was spent trying to ensure that Charting will behave the same way on both platforms. In most cases, this was a matter of finding an implementation both platforms agreed on - in some it meant resorting to small, localized #if blocks.

    Fixed handling of data objects with non-unique hash codes. When each data object had a unique hash code, things already worked fine. But data sets containing items sharing the same hash code could exhibit incorrect behavior in previous releases. Most typical data sets would not have encountered this problem because hash codes are nearly always unique - but there are certain classes that report quite UNunique hash codes and could trigger the problem fairly easily. This is no longer an issue.

    Corrected behavior of charts at very small sizes and during animations. Some third party controls offer so-called "fluid" layout in which size changes are all animated and elements can easily shrink to a size of 0x0. This kind of environment could previously trigger layout bugs that would result in an unhandled exception from the Chart control. These issues have been fixed and dynamic layout changes are now handled seamlessly.

    Breaking Changes

    IRequireGlobalSeriesIndex's GlobalSeriesIndexChanged method takes a nullable int parameter. This should affect only people who have written custom Series implementations - and the code change is a trivial.

    Other Changes

    Many other fixes and improvements.

    • Proper RoutedEvent support for DataPointSeries.SelectionChangedEvent
    • Better handling of non-double data by shared Series
    • Addition of StrokeMiterLimit to the Polyline used by LineSeries
    • Fixes for edge case scenarios when removing a Series
    • Ability to set Series.Title with a Binding (on Silverlight 3 and WPF)
    • Automatic inheritance of the Foreground property by the Title control
    • Visual improvements to the LegendItem DataPoint marker
    • Addition of SnapsToDevicePixels to the default Chart Template (WPF-only; unnecessary on Silverlight)

    Build Notes

    If you plan to recompile the WPF Toolkit from source, please be aware that two of the three Charting design-time assemblies reference Blend 3 DLLs Microsoft.Windows.Design.Extensibility.dll and Microsoft.Windows.Design.Interaction.dll. Unlike their Visual Studio counterparts, these design-time assemblies are not automatically found by the build and their absence causes 84 build errors in the Controls.DataVisualization.Toolkit.Design and Controls.DataVisualization.Toolkit.Expression.Design projects. :(

    Most people won't care about building the Blend-specific design-time assemblies and can simply right-click the two failing projects in Visual Studio and choose "Unload Project". After that, everything builds successfully.

    Alternatively, users with Blend installed can update these projects' references to both assemblies and then everything (including the Blend design-time assemblies!) builds successfully. The default location of the Blend assemblies is something like C:\Program Files (x86)\Microsoft Expression\Blend 3 Beta. (If you're on a 32-bit OS, remove the " x86"; once Blend releases, remove the " Beta".

    Sorry for the inconvenience - we didn't want to ship pre-release Blend components with the WPF Toolkit.

     

    Long-time readers know that I always include some new Charting samples with my release notes to showcase new features. The big feature here is WPF Charting, so I've put together a solution that contains almost all of the public Charting samples I've ever posted to my blog - now in one handy place! Naturally, the DataVisualizationDemos sample runs on both Silverlight (2 or 3!) and WPF with the exact same code and XAML. And it includes a brand new scenario called "Letter Frequency" that I wrote to help test some of the recent changes.

    Here it is on WPF:

    DataVisualizationDemos Letter Frequency sample

    Click here to download the complete source code for the DataVisualizationDemos sample application.

    (Note: To find the blog post associated with each sample, please refer to the "My posts" section of my Charting Links collection.)

     

    Jafar and I spent most of the previous release cycle helping other teams with their deliverables, so we didn't get as nearly much time to spend on Charting as we would have liked. [Otherwise the release notes would be much longer! :) ] Fortunately, we did make the time to deliver some good fixes for this release and that should help make customers' lives a little easier. Of course, while we've done our best to make Charting as useful and problem-free as possible, there's always room for improvement...

    So if you have any questions or feedback, the right places to start are the Silverlight Discussion Forum or the WPF Discussion List. Bugs and feature requests can be logged with the Silverlight Issue Tracker or the WPF Issue Tracker. Please raise issues that are clearly unique to one platform or the other in the obvious place. But for general questions and things that are common to both platforms, the Silverlight forum/list is probably a better place - just because there's more context and history there.

    A big "thank you" goes out to everyone who's worked with Charting and helped to make it what it is today! Today's release and announcement are specifically directed at the WPF early-adopters who've truly gone the extra mile to use Charting. We thank you for your dedication! Also, my personal thanks go out to the WPF Toolkit team for making this possible - in particular to Samantha Durante, Vamsee Potharaju, and Alexis Roosa for their assistance and support!

     

    PS - If you're a loyal Silverlight Charting user who's feeling a little left out right about now, I have some good news for you, too. :) The Silverlight Toolkit will also be releasing an update fairly soon. And when it does, Silverlight Charting will contain all the fixes described here, one or two others that came in too late to make this release, AND a nice little surprise that will make the wait worthwhile...

  • Delay's Blog

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

    • 47 Comments

    One of the more frequent requests we've gotten for the "Atlas" Control Toolkit is some way to easily alter the content of a popup before displaying it to the user. Typically, page authors want to have a single popup element on their page that is used from multiple locations (often the rows of a data-bound server control) and they want the popup to display information specific to each location that displays it. For example, a page displaying multiple products might want a popup associated with each product to display additional details for that particular product.

    There was previously no easy way to accomplish this task, but with the 60914 release of the Toolkit, we've made it simple! The HoverMenu, ModalPopup, and PopupControl now all derive from new DynamicPopulate*Base classes (see the "Other neat stuff" page for details) and automatically expose four new properties: DynamicControlID, DynamicContextKey, DynamicServicePath, and DynamicServiceMethod. These properties behave just like they do for the DynamicPopulate control (please follow that link for more details) and the existing controls have been modified to call the "populate" function as part of their popup actions.

    What this means for page authors is that it's simple to add dynamic population to new/existing pages - what it means for control authors is that it's simple to add dynamic population to new/existing controls!

    Here's what dynamic population looks like in action (I've arbitrarily chosen ModalPopup for the demonstration):

    Animated demonstration

    The complete code for the sample follows; noteworthy sections have been bolded to make them stand out. The important things to note are:

    • The page content is generated by data binding an XmlDataSource to a DataList. The data are simple CSS style declarations that are used to decorate the dynamic content when it renders. The user can select which decoration to apply by choosing any of the links on the page.
    • Each row of the DataList includes a ModalPopupExtender declaration that pops a modal panel when the CSS style declaration is clicked. All ModalPopupsExtenders share the same popup element in order to avoid unnecessary duplication. The text of the row and the DynamicContextKey of the ModalPopupProperties are both set by a (data bound) call to Eval.
    • The popup (Panel1) contains both static content and dynamic content (Panel2). The static content includes the "OK" button that dismisses the popup. The dynamic content consists of the current server time which is styled according to the selected row's CSS style declaration and displayed in a random color.
    • The dynamic content is generated by a page method which uses its context key parameter to identify the specific row that is being dynamically populated. (Here, the context key is the CSS style declaration, but typically it might be a database index or row number.)

    That's all there is to it!

    Just save the following code to an .ASPX file in the SampleWebSite directory of a Toolkit installation if you want to try it out for yourself:

    <%@ Page Language="C#" %>
    <%
    @ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit"
      TagPrefix="atlasToolkit" %>
    <!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]
      
    public 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 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 --%>
        
    <atlas: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 --%>
            
    <atlasToolkit:ModalPopupExtender ID="ModalPopupExtender" runat="server">
              <atlasToolkit:ModalPopupProperties
                TargetControlID="LinkButton" PopupControlID="Panel1" OkControlID="Button1"
                BackgroundCssClass="background" DynamicControlID="Panel2"
                DynamicContextKey='<%# Eval("style") %>' DynamicServiceMethod="GetContent" />
            </atlasToolkit:ModalPopupExtender>
          </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>

    If you found this "How to" helpful or if you have any suggestions for ways in which future "How to"'s could be improved, please let me know. Thank you!!

  • Delay's Blog

    Using one platform to build another [HTML 5's canvas tag implemented using Silverlight!]

    • 15 Comments

    Background

    There's been some buzz about the upcoming HTML 5 standard over the past few months. In particular, there are a couple of new features that people are looking forward to. One of them is the new <canvas> element which introduces a 2D drawing API offering a pretty rich set of functionality. If you've worked with HTML much, you can probably imagine some of the things that become possible with this. In fact, those are probably some of the same things that Flash and Silverlight are being used for today! So some people have gone as far as to suggest HTML 5 could eliminate the need for Flash and Silverlight...

    I didn't know much about the <canvas> element and I wanted to understand the situation better, so I did some research. The specification for <canvas> is available from two sources: the W3C and the WHATWG. (The two groups are working together, so the spec is the same on both sites.) The API is comprised of something close to 100 interfaces, properties, and methods and offers an immediate mode programming model that's superficially similar to the Windows GDI API. At a very high level, the following concepts are defined (though Philip Taylor did some investigation a while back which suggested that no browser offered complete support):

    • Paths and shapes (move/line/curve/arc/clipping/etc.)
    • Strokes and fills (using solid colors/gradients/images/etc.)
    • Images
    • Context save/restore
    • Transformations (scale/rotate/translate/etc.)
    • Compositing (alpha/blending/etc.)
    • Text (font/alignment/measure/etc.)
    • Pixel-level manipulation
    • Shadows

    There's a variety of stuff there - and as I read through the list, I was struck by how much of it is natively supported by Silverlight. Pretty much all of it, in fact! :) So I thought it might be a fun and interesting learning experience to try implementing the HTML 5 <canvas> specification in Silverlight! What better way to understand the capabilities of <canvas> than to implement them, right?

    So I went off and started coding... I didn't set out to support everything and I didn't set out to write the most efficient code (in fact, some of what's there is decidedly inefficient!) - I just set out to implement enough of the specification to run some sample apps and see how hard it was.

    And it turns out to have been pretty easy! Thanks to Silverlight's HTML Bridge, I had no trouble creating a Silverlight object that looks just like a <canvas> to JavaScript code running on a web page. So similar, in fact, that I'm able to run some pretty cool sample applications on my own <canvas> simply by tweaking the HTML to instantiate a Silverlight <canvas> instead of the browser's <canvas>. And as a nice side effect, Internet Explorer "magically" gains support for the <canvas> tag!

    Aside: Yes, I know I'm not the first person to add <canvas> support to IE. :)

     

    Samples

    I started off easy by working my way through the Mozilla Developer Center's Canvas tutorial and implementing missing features until each of the samples loaded and rendered successfully. Here are three of my favorite samples as rendered by Html5Canvas, my custom <canvas> implementation:

    Mozilla samples

     

    Aside: It's important to note that I did NOT change the JavaScript of these (or any other) samples - I just tweaked the HTML host page to load my <canvas> implementation. My goal was API- and feature-level parity; a Silverlight implementation of <canvas> that was "plug-compatible" with the existing offerings.

     

    After that, I knew I just had to run Ben Joffe's Canvascape "3D Walker" because it bears a striking resemblance to one of the games I played when I was younger:

    Canvascape

     

    Aside: Be sure to look for the "Silverlight" context menu item I've included in the image above and in the next few screen shots to prove there's no trickery going on. :)

     

    Next up was Bill Mill's Canvas Tutorial - and another shout-out to hours of misspent youth:

    Canvas Tutorial

     

    For something completely different, I got Bjoern Lindberg's Blob Sallad running:

    Blob Sallad

     

    Then it was on to Ryan Alexander's Chrome Canopy fractal zoomer (despite the note, it runs okay-ish in IE8 with my Silverlight <canvas>):

    Chrome Canopy

     

    Finally, I wanted to see how the 9elements HTML5 Canvas Experiment ran:

    Canvas Experiment

     

    Whew, What a rush - those apps are really cool! :)

     

    But I still wanted a sample I could include with the source code download, so I also wrote a little app to exercise most of the APIs supported by Html5Canvas (thanks to Mozilla for the Hypotrochoid animation inspiration and Wikipedia for the equation). Here it is on IE:

    Sample application in IE

     

    And wouldn't it be nice to see how Html5Canvas compares to a "real" <canvas> implementation? Sure, here's my sample running on Firefox:

    Sample application in Firefox

     

    Details

    So how does it actually work? Well, I'm obviously not modifying the browser itself, so redefining the actual <canvas> tag isn't an option. Instead, I've written a simple Html5Canvas.js file which gets referenced at the top of the HTML page:

    <script type="text/javascript" src="Html5Canvas.js"></script>

    Among other things, it defines the handy function InsertCanvasObject(id, width, height, action) function which can be used to insert a Silverlight <canvas> thusly:

    <script type="text/javascript">
        InsertCanvasObject("mycanvas", 200, 200, onCanvasLoad);
    </script>
    

    That code inserts a Silverlight object running Html5Canvas.xap that looks just like the <canvas> tag would have. Yep, it's that easy!

    And it brings up an important difference between Html5Canvas and a real <canvas>: Html5Canvas can be used only after the Silverlight object has loaded - whereas <canvas> is usable as soon as the body/window has loaded (which happens sooner). This distinction is important to keep in mind if you're converting an existing page, because it requires moving the initialization call from onload to the action parameter of InsertCanvasObject. Believe it or not, that's really the only big "gotcha"!

    Aside: While I could think of a few ways to avoid exposing this difference to the developer, none of them were general enough to apply universally.

    Other minor differences between Html5Canvas and <canvas> are that Silverlight doesn't natively support the relevant repeat modes used by createPattern to tile images (though I could implement them without much difficulty), Silverlight doesn't support the GIF image format for use with drawImage (also easily worked around), and the conventional technique of JavaScript feature-detection by writing if (canvas.toDataURL) { ... } doesn't work because Silverlight's HTML Bridge doesn't allow a method to be treated like a property (I could work around this, too, but the extra level of indirection was unnecessarily confusing for a sample app).

    Finally, let me reiterate that I did not attempt to implement the complete <canvas> specification. Instead, I implemented just enough to support the first 5 (of 6 total) Mozilla sample pages as well as the handful of applications shown above. Specifically, I've implemented everything that's not in italics in the feature list at the beginning of this post. Thinking about what it would take to add the stuff that's not implemented: text and pixel-level manipulation are both directly supported by Silverlight and should be pretty easy. Shadows seem like a natural fit for Silverlight's pixel shader support (though I haven't played around with it yet). All that's left is layer compositing, which does worry me just a little... I haven't thought about it much, but this seems like another job for WriteableBitmap, perhaps.

     

    [Please click here to download the complete source code to Html5Canvas and the sample application shown above.]

    Be sure to set the Html5Canvas.Web project as the active project and run the TestPage.html within it to see the sample application.

     

    Summary

    Html5Canvas was a fun project that definitely accomplished its goal of bringing me up to speed on HTML 5's <canvas> element! The implementation proved to be fairly straightforward, though there were a couple of challenging bits that ended up being good learning opportunities. :) The code I'm sharing here is intended to be a proof-of-concept and is not optimized for performance. However, if there's interest in making broader use of Html5Canvas, I have some ideas that should really improve things...

    I hope folks find this all as interesting as I did - and maybe next time you want to add browser features, you'll use Silverlight, too! ;)

  • Delay's Blog

    Bringing a bit of HTML to Silverlight [HtmlTextBlock makes rich text display easy!]

    • 42 Comments

    Lately I've seen a few people wanting to display rich text in a Silverlight application, but having no way to do so easily. Most recently, I saw Tim Heuer bump into this when displaying RSS content in a neat demo of his. The basic problem is that Silverlight's primary text display object, TextBlock, does not natively have a way to display HTML - and that's the format most rich text is in these days. It seemed that if only there were a TextBlock that took HTML as input and built up a collection of Run and LineBreak objects corresponding to that HTML, things would be easier...

    So I wrote HtmlTextBlock, a "plug-compatible" replacement for TextBlock that knows how to take simple HTML (technically XHTML, see the notes below) and display it in a manner that fairly closely approximates how a web browser does. A picture is worth a thousand words, so here's what HtmlTextBlock looks like in action:

    HtmlTextBlock Demonstration Page

    You can click here (or on the image above) to experiment with HtmlTextBlock in your own browser in an interactive demo page. As usual, I've made the complete source code available, so click here to download the source code and play around with it yourself! (To build the project, you'll want to use Visual Studio 2008 Beta 2 and the latest Silverlight Tools.)

    Notes:

    • HtmlTextBlock supports the following HTML elements: <A>, <B>, <BR>, <EM>, <I>, <P>, <STRONG>, and <U>. Attributes are not supported with the exception of the <A> element's HREF attribute (see below).
    • I initially planned to have HtmlTextBlock derive from TextBlock and simply override its Text property. However, TextBlock is sealed, so that wasn't going to work. The next obvious approach was to have HtmlTextBlock be a Control with a TextBlock inside it, so that's what I've done here. My goal of "plug-compatibility" (i.e., the ability to easily replace TextBlock with HtmlTextBlock) meant that I needed to manually implement the various TextBlock properties on HtmlTextBlock and pass them through to the underlying TextBlock. So HtmlTextBlock doesn't actually derive from TextBlock, but it behaves as though it did.
    • Having HtmlTextBlock use TextBlock internally and represent the HTML markup with Run and LineBreak elements is nice because it means that just about everything people already know about TextBlock automatically applies to HtmlTextBlock And I get correct word wrapping behavior for free. :) However, the glitch is that the Run element does not support the MouseLeftButton* family of events, making the handling of <A> link elements difficult. Because HtmlTextBlock can't really tell when the user clicks on a link, it displays the URL of each link so the user can type it in themselves (and typing is necessary because TextBlock doesn't support select+copy either). I can think of a few reasons why Run might not support mouse events, but in this case it would be convenient if it did. :)
    • HtmlTextBlock uses an XmlReader to parse its input when creating the Run and LineBreak elements for display. This makes the parsing implementation simple and robust, but breaks down when the input is not XHTML (such as invalid HTML or valid HTML where empty elements don't have a trailing '/' (ex: "<br>" instead of "<br />")). In the event of a parsing error, HtmlTextBlock's default behavior is to display the input text as-is, just like TextBlock always does. Unfortunately, non-XHTML is pretty common, so certain scenarios may benefit from a custom HTML parser implementation that is more flexible in this regard.
    • HTML rendering is covered by a detailed specification, but some of the rules are not what one might expect. Specifically, the rules for handling spacing and whitespace (' ', '\n', '\t', etc.) can be tricky to get right. I've made some attempt to ensure that HtmlTextBlock follows the rules where possible and convenient, but it was not my goal to achieve 100% compliance in this area. Playing around in the demo application, HtmlTextBlock should pretty closely match the browser's HTML rendering of valid input, but if you know the rules, it's not too difficult to trigger whitespace rendering differences.
    • Silverlight's default font, "Portable User Interface"/"Lucida Sans Unicode"/"Lucida Grande" doesn't seem to render bold or italic text any differently than normal text. This always surprises people the first time they try to figure out why their text isn't bold/italic. I don't know why this is myself, but I'd guess it relates to keeping the download size of Silverlight to a minimum.
    • The demo page makes use of JavaScript -> C# function calls. Hooking this up in code is surprisingly easy, though I did run into a small glitch. If the sample text is deleted entirely (leaving a blank text box) in IE, the JS -> C# call originates from the JS side as it should, but never makes it through to the C# side. Looking at the call to SetText in the debugger, textAreaSampleText.value is "", so this should work in IE just like it does in Firefox - but it didn't for me. The simple workaround was to pass textAreaSampleText.value + "" instead and then things worked in IE, too.

    HtmlTextBlock is obviously nothing like a complete HTML rendering engine [that's what web browsers are for! :) ]. However, if you want to add simple support for rich text to your Silverlight application without a lot of work, HtmlTextBlock may be just the thing for you!

  • Delay's Blog

    Where's your leak at? [Using WinDbg, SOS, and GCRoot to diagnose a .NET memory leak]

    • 16 Comments

    In my last post, I explained how it was possible for "hidden" event handlers to introduce memory leaks and showed an easy way to prevent such leaks. I used a sample application to contrast a leaky implementation with one that uses the WeakEventListener class (included as part of the post) to avoid leaking on Silverlight. The changes required to patch the leak were fairly minimal and the entire process was pretty straightforward. But I glossed over one important point...

    What if you don't know the source of the memory leak in the first place? Knowing how something is leaking is the first step to fixing it, and the web has some great resources for learning more about tracking down managed memory leaks in WPF and Silverlight applications. I am not going to try to duplicate that information here. :) Instead, I'll refer interested readers to these excellent resources and recommend a bit of web searching if additional background is needed:

    As luck would have it, there are also a number of fine tools available to help find managed memory leaks. Being a rather frugal individual myself, I nearly always prefer to use free stuff and it just so happens that two of the best tools available are free from Microsoft! They are:

    Again, this post is not a tutorial for either tool. :) Instead, it will demonstrate how to use these tools together to answer a specific question: What part of the sample application's LeakyControl code is causing a leak? The basic technique I'll use is described in the following two posts which do a great job covering the topic:

    Now that we're ready to go, let's remind ourselves what the demo application looked like:

    WeakEventListener Sample Application

    To reproduce the leak, build the sample application and run it outside the Visual Studio debugger (because we'll be using WinDbg instead). You can do this by hitting Ctrl+F5 ("Start Without Debugging") or by double-clicking the TestPage.html file in the Bin\Debug folder. As before, click "Remove From UI" to discard both controls, then click "Garbage Collect" to perform a collection, then click "Check Status". You'll see that FixedControl is gone, but LeakyControl is still present despite our attempt to get rid of it.

    Now start WinDbg from the Start Menu, hit F6 to "Attach to a Process", and pick the iexplore.exe instance corresponding to the test application. (If there are multiple instances of iexplore.exe, you can determine the proper PID via Task Manager or you can just guess - it's nearly always the one at the bottom of the list!) If all went well, you'll see a bunch of modules get loaded and a couple of them should have "Silverlight" in their path. (If not, try again and attach to a different instance of iexplore.exe.) Great, now we're ready to go!

    First, we'll load the SOS debugging extension:

    0:012> .loadby sos coreclr
    

    In this case, we know we're leaking an instance of the LeakyControl class, so what we'll do is find all of the instances of LeakyControl in the managed heap. We expect there to be zero at this point, so if one is present, then it has been leaked. DumpHeap tells us this easily:

    0:012> !DumpHeap -type LeakyControl
     Address       MT     Size
    03ff6df4 02f43c80       56
    total 1 objects
    Statistics:
          MT    Count    TotalSize Class Name
    02f43c80        1           56 WeakEventListenerDemo.LeakyControl
    Total 1 objects
    

    Yep, we're leaking an instance of LeakyControl... Let's find out what reference is keeping this instance alive:

    0:012> !GCRoot 03ff6df4
    Note: Roots found on stacks may be false positives. Run "!help gcroot" for
    more info.
    Scan Thread 10 OSTHread 7ec
    Scan Thread 11 OSTHread e44
    Scan Thread 12 OSTHread e04
    DOMAIN(003CB450):HANDLE(Pinned):2f512f8:Root:  04fe78e0(System.Object[])->
      03fef5bc(WeakEventListenerDemo.App)->
      03ff0710(WeakEventListenerDemo.Page)->
      03ff77b0(System.Collections.ObjectModel.ObservableCollection`1[[System.Int32, mscorlib]])->
      03ff7a20(System.Collections.Specialized.NotifyCollectionChangedEventHandler)->
      03ff7a08(System.Object[])->
      03ff7920(System.Collections.Specialized.NotifyCollectionChangedEventHandler)->
      03ff6df4(WeakEventListenerDemo.LeakyControl)->
    

    I find it's usually easiest to start from the bottom of GCRoot output: in this case we see the LeakyControl instance is referenced by an instance of NotifyCollectionChangedEventHandler. Now, in the trivial sample application that's all we need to identify the source of the leak and we could stop here. But in a larger, more realistic application there might be many places where a NotifyCollectionChangedEventHandler is created - let's see if we can narrow this down even further:

    0:012> !DumpObj 03ff7920
    Name:        System.Collections.Specialized.NotifyCollectionChangedEventHandler
    MethodTable: 02e9dcc0
    EEClass:     02ea0760
    Size:        32(0x20) bytes
    File:        c:\Program Files\Microsoft Silverlight\2.0.40115.0\System.Windows.dll
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    02a444e8  40001e0        4        System.Object  0 instance 03ff6df4 _target
    02c13c58  40001e1        8 ...ection.MethodBase  0 instance 00000000 _methodBase
    02b00a90  40001e2        c        System.IntPtr  1 instance  2f4c14c _methodPtr
    02b00a90  40001e3       10        System.IntPtr  1 instance        0 _methodPtrAux
    02a444e8  40001e4       14        System.Object  0 instance 00000000 _invocationList
    02b00a90  40001e5       18        System.IntPtr  1 instance        0 _invocationCount
    

    What would be nice is if we could figure out which method in LeakyControl corresponds to that _methodPtr because doing so would tell us which particular event hook-up was involved. Let's try the easy way first:

    0:012> !IP2MD 2f4c14c
    Failed to request MethodData, not in JIT code range
    

    Okay, so much for the easy way; the method hasn't been JITted yet. Let's look at the code corresponding to _methodPtr next:

    0:012> !U 2f4c14c
    Unmanaged code
    02f4c14c b84c3cf402      mov     eax,2F43C4Ch
    02f4c151 89ed            mov     ebp,ebp
    02f4c153 e9bc46ceff      jmp     02c30814
    02f4c158 00b000eb18b0    add     byte ptr [eax-4FE71500h],dh
    02f4c15e 02eb            add     ch,bl
    02f4c160 14b0            adc     al,0B0h
    02f4c162 04eb            add     al,0EBh
    02f4c164 10b006eb0cb0    adc     byte ptr [eax-4FF314FAh],dh
    02f4c16a 08eb            or      bl,ch
    02f4c16c 08b00aeb04b0    or      byte ptr [eax-4FFB14F6h],dh
    

    Because the method hasn't been JITted, it's a pretty safe bet that we're looking at a thunk here. Let's take the value it's using and try to examine that as a MethodDesc:

    0:012> !DumpMD 2F43C4C
    Method Name: WeakEventListenerDemo.LeakyControl.OnCollectionChanged(System.Object, System.Collections.Specialized.NotifyCollectionChangedEventArgs)
    Class:       02f41b18
    MethodTable: 02f43c80
    mdToken:     06000013
    Module:      02f433bc
    IsJitted:    no
    CodeAddr:    ffffffff
    

    Success! We see this event handler is for the LeakyControl.OnCollectionChanged method - so now we know exactly which event handler hook-up is responsible for the leak. And, armed with the knowledge from my last post, we've got everything we need to fix this code and patch the leak!

    Once we do, our code will be a little better behaved, our developers won't have to track down leaks in our code, and our users will see more solid, more predictable behavior with lower memory use. Nice work - it's donut time! :)

  • Delay's Blog

    Alive and kickin' [New Silverlight 4 Toolkit released with today's Silverlight 4 RTW!]

    • 42 Comments

    The Silverlight team released Silverlight 4 today and it includes a variety of compelling new features and great improvements for all kinds of scenarios. You can learn more about the new platform hotness in the Silverlight 4 Technical Feature Overview.

    Congratulations to the team on another great release!

    To help celebrate the event, we have just published the April '10 release of the Silverlight Toolkit! If you're new to Silverlight 4 or the Silverlight Toolkit, you might start by reviewing my November 09 Toolkit announcement to see what was in the Silverlight 4 Beta Toolkit. Once you've done that, you're ready for my take on the...

     

    Silverlight 4 Toolkit April '10 Release Notes

     

    ContextMenu (New!)

    ContextMenu

    Silverlight 4 allows applications to handle the right mouse button (via the UIElement.MouseRightButtonDown event), and the showcase control for that is ContextMenu! (If you're not familiar with ContextMenu, here's an overview of the WPF version.). While I considered starting from an existing implementation, the handful I saw didn't match the WPF class hierarchy. Because compatibility is a big priority for us, I wrote the Toolkit's ContextMenu from scratch - and this is a 100% WPF-compatible subset implementation. Which means that existing properties/methods/events should behave the same on Silverlight as they do on WPF - something that makes porting existing code from WPF to Silverlight very straightforward.

    That said, please pay attention to the word "subset"; the Toolkit's ContextMenu doesn't have all the features of WPF's quite yet. Notably, it doesn't support multi-level menu item nesting. However, none of the customers I asked felt that nesting was necessary right now, so I don't expect its absence to be a big limitation.

    Okay, enough about what's not there; here's what is there:

    XAML for the example above:

    <Button
        x:Name="MyButton"
        Content="Button with simple ContextMenu">
        <toolkit:ContextMenuService.ContextMenu>
            <toolkit:ContextMenu>
                <toolkit:MenuItem
                    Header="Simple menu item"
                    Click="MenuItem_Click"/>
                <toolkit:MenuItem
                    Header="Another menu item"
                    Click="MenuItem_Click"/>
                <toolkit:Separator/>
                <toolkit:MenuItem
                    Header="Disabled menu item"
                    IsEnabled="False"/>
                <toolkit:Separator/>
                <toolkit:MenuItem
                    Header="With a pretty icon"
                    Click="MenuItem_Click">
                    <toolkit:MenuItem.Icon>
                        <Image Source="Paste.png"/>
                    </toolkit:MenuItem.Icon>
                </toolkit:MenuItem>
            </toolkit:ContextMenu>
        </toolkit:ContextMenuService.ContextMenu>
    </Button>

    If you're looking for more examples of how to use ContextMenu, just about any WPF sample you find should be useful. The one thing to keep in mind is that Silverlight 4 doesn't have the FrameworkElement.ContextMenu property that's often used to attach a ContextMenu to an element. Instead, it is always necessary to use the (functionally equivalent and more flexible) ContextMenuService.ContextMenu attached property like I show above.

    ContextMenu is useful in a variety of scenarios - some of them are obvious (like the example above) and some a little less so. For an example, please...

    [Click here for my follow-up post about ContextMenu.]

    [Or click here to download the sample application for this post containing all the examples.]

     

    Stacked series support (New!)

    StackedSeries

    One common feature request for the Data Visualization assembly in the Silverlight Toolkit (and WPF Toolkit) has been support for stacked series (like you see in the example above). This release of the Silverlight Toolkit includes full stacking support, which means all of Excel's top-level series types are supported in both normal and stacked modes! The following eight series classes are now available in the Data Visualization assembly:

    • StackedBarSeries
    • StackedColumnSeries
    • StackedLineSeries
    • StackedAreaSeries
    • Stacked100BarSeries
    • Stacked100ColumnSeries
    • Stacked100LineSeries
    • Stacked100AreaSeries

    Another common request has been better performance - and that's something else this release includes. While existing applications aren't likely to see a big difference by default, there's a trivial change that can be made to many scenarios to enable significant performance gains for BarSeries, ColumnSeries, LineSeries, AreaSeries, and ScatterSeries.

    And because customer scenarios involving selection (including "drill down") come up a lot more often than you'd think, the new stacked series types also offer full ListBox-style selection support, including multi-select and all the associated events/properties.

    Based on the fact that a stacked series showing a single set of data is morally equivalent to the corresponding non-stacked series, it's clear that you can get these benefits for existing scenarios, too. In fact, I've added five additional wrapper classes to make it even easier to do so!

    XAML for the example above:

    <toolkit:Chart
        Title="Student Test Scores"
        LegendTitle="Subject">
        <toolkit:Chart.Resources>
            <Style TargetType="toolkit:LinearAxis">
                <Setter Property="Minimum" Value="0"/>
            </Style>
        </toolkit:Chart.Resources>
        <toolkit:StackedColumnSeries>
            <toolkit:SeriesDefinition
                Title="Math"
                ItemsSource="{Binding}"
                DependentValuePath="MathScore"
                IndependentValuePath="StudentName"/>
            <toolkit:SeriesDefinition
                Title="Language"
                ItemsSource="{Binding}"
                DependentValuePath="LanguageScore"
                IndependentValuePath="StudentName"/>
            <toolkit:SeriesDefinition
                Title="Science"
                ItemsSource="{Binding}"
                DependentValuePath="ScienceScore"
                IndependentValuePath="StudentName"/>
        </toolkit:StackedColumnSeries>
    </toolkit:Chart>

    There's a lot that went on under the hood to add this new support, and some of the details are pretty interesting - but it's necessary to understand a bit about how stacked series came about in the first place. Because I want to keep these release notes brief, please...

    [Click here for my follow-up post about stacked series support.]

    [Or click here to download the sample application for this post containing all the examples.]

     

    SystemColors theme (New!)

    SystemColors theme SystemColors theme (high contrast)

    Some customers have asked for an easy way to get a Silverlight application to honor the color settings of the host operating system. This typically comes up in the context of high contrast mode (shown above on the right) and improved accessibility support, but it's also generally applicable. So the UX team created a custom theme for this, and I've incorporated their work into this release of the Silverlight Toolkit as the new SystemColors theme. Just like the 11 themes already in the Toolkit, using it is as easy as wrapping some content in an instance of the SystemColors theme container - everything inside automatically gets the new styles!

    XAML for the example above:

    <toolkit:SystemColorsTheme>
        <StackPanel>
            <Button Content="Button"/>
            <CheckBox Content="CheckBox"/>
            ...
        </StackPanel>
    </toolkit:SystemColorsTheme>

    Actually, it can be even easier than that! :) But to understand how, you need to know about the...

     

    Theme base class improvements

    Theme base class

    Because Silverlight 4's support for implicit styling makes theming so much easier, the Theme base class has been enhanced and is now more useful than ever. For starters, there's a ThemeUri property which can point to an external file to use as the theme. This reference can be a URL for a web resource like /MySiteWideTheme.xaml which gives sites the freedom to change a theme after an application has been deployed. Or it can point to an assembly resource via the /AssemblyShortName;component/ResourceLocation syntax discussed here. In this second case, the theme is loaded immediately; otherwise it is downloaded asynchronously and applied as soon as the download completes. Even better, ThemeUri can be changed dynamically by applications that allow users to change their themes "on the fly".

    The format of a theme file is exactly what you'd expect: a generic.xaml-like ResourceDictionary containing one or more implicit styles. This is how the Toolkit classes store their theme resources, so those themes are accessible in the same manner. This makes it easy to dynamically switch among any of the Toolkit themes, too!

    Okay, that's pretty cool and all, but sometimes you want to theme an entire application and you don't want to have to wrap every page in its own theme container. No sweat, that's what the new ApplicationThemeUri attached property is all about! Just open your project's App.xaml and set the ApplicationThemeUri property on the Application object (just as you would for ThemeUri on the Theme class). When ApplicationThemeUri is used, the corresponding implicit styles are added at the application level and automatically apply to every page.

    Can it get any easier? Yes! :) Every theme that comes with the Toolkit also exposes an IsApplicationTheme attached property. Much like ApplicationThemeUri, you set this property in App.xaml on the Application object. But because IsApplicationTheme is a simple bool value, you don't have to mess with ugly, confusing URI formats or even know what a URI is! Just set it (to True), and forget it!

    XAML for the example above:

    <toolkit:Theme ThemeUri="/ToolkitSamplesApril10;component/CustomTheme.xaml">
        <StackPanel>
            <Button Content="Button"/>
            <CheckBox Content="CheckBox"/>
            ...
        </StackPanel>
    </toolkit:Theme>
    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    
        <Style TargetType="Button">
            <Setter Property="FontFamily" Value="Comic Sans MS"/>
            <Setter Property="Foreground" Value="Red"/>
        </Style>
    
        <Style TargetType="CheckBox">
            <Setter Property="FontFamily" Value="Comic Sans MS"/>
            <Setter Property="Foreground" Value="Orange"/>
        </Style>
    
        ...
        
    </ResourceDictionary>

    Alternatively:

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 x:Class="ToolkitSamplesApril10.App"
                 xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
                 toolkit:Theme.ApplicationThemeUri="/ToolkitSamplesApril10;component/CustomTheme.xaml">
        <Application.Resources>
        </Application.Resources>
    </Application>

    Or:

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 x:Class="ToolkitSamplesApril10.App"
                 xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
                 toolkit:SystemColorsTheme.IsApplicationTheme="True">
        <Application.Resources>
        </Application.Resources>
    </Application>

    [Click here to download the sample application for this post containing all the examples.]

     

    Test Framework improvements and new UI

    Unit Test Framework

    The Silverlight Unit Test Framework that comes with the Toolkit has been updated to include:

    • Out-of-browser support for Silverlight applications
    • Support for testing Windows Phone 7 applications
    • A new, more functional user interface
    Note: The two Unit Test Framework assemblies (Microsoft.Silverlight.Testing and Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight) are no longer located in the Bin directory of the Toolkit install - they have been moved to a new Testing directory instead. This was done to prevent many of the classes used by the new UI from showing up in the Visual Studio and Blend designers and confusing people. However, this location change could cause existing applications that reference the test assemblies to fail to compile due to the "missing" references. If that happens, please delete the two broken references and create references to these assemblies in their new location. Everything else should continue to work as expected.

    For more information about changes to the Silverlight Unit Test Framework, please have a look at Jeff Wilcox's blog.

     

    PanelDragDropTarget (New!)

    PanelDragDropTarget

    A new DragDropTarget has been added to make it easy to support drag/drop scenarios with Panel subclasses like Grid and WrapPanel. Simply wrap the relevant Panel in an instance of PanelDragDropTarget (like you see below), and the Toolkit's drag/drop framework automatically allows users to drag items out of that container with full visual feedback about what's being dragged and what the drop action will be. To allow dropping items into the container, just set its AllowDrop property to True and the details are handled seamlessly.

    XAML for the example above:

    <Border Grid.Column="0">
        <Grid>
            <TextBlock Text="Drag colored squares from here"/>
            <toolkit:PanelDragDropTarget>
                <toolkit:WrapPanel>
                    <Rectangle Fill="Red"/>
                    <Rectangle Fill="Orange"/>
                    <Rectangle Fill="Green"/>
                    <Rectangle Fill="Blue"/>
                    <Rectangle Fill="Purple"/>
                </toolkit:WrapPanel>
            </toolkit:PanelDragDropTarget>
        </Grid>
    </Border>
    
    <Border Grid.Column="1">
        <Grid>
            <TextBlock Text="Drop colored squares on here"/>
            <toolkit:PanelDragDropTarget>
                <toolkit:WrapPanel
                    AllowDrop="True"
                    Background="Transparent"/>
            </toolkit:PanelDragDropTarget>
        </Grid>
    </Border>

    For more about other DragDropTargets and how they work, please have a look at Jafar Husain's series of posts on the topic.

    [Click here to download the sample application for this post containing all the examples.]

     

    TreeView Scenario Examples (New!)

    TreeView connecting lines

    There are some fairly common TreeView scenarios that tend to stymie people who try to implement them in WPF or Silverlight. So this release of the Toolkit includes complete, run-able examples of some of these scenarios in the Toolkit sample application. None of the scenarios requires changing TreeView code - but there are a couple of fancy XAML tricks in there. :) The complete source code for the sample application is installed with the Toolkit and also available within the sample application (just expand the tabs at the bottom of each sample page for the syntax-highlighted code). Please feel free to make use of the same techniques in your own applications.

    For a look at the new samples, please visit the live Toolkit samples application, navigate to the TreeView node, and switch to the "Templating" tab.

     

    Improved XmlnsDefinition support

    Now that Silverlight 4 honors the URI form of XmlnsDefinitionAttribute, we use that to simplify the list of namespace mappings needed by typical applications. Specifically, the primary namespaces of all Toolkit assemblies share the URI http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit which maps to the prefix "toolkit" by default.

    So instead of wrestling with this big glob of XAML goo:

    xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
    xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit" 
    xmlns:datavis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit" 
    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:theming="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.Toolkit"

    The following is now all you need (and will be automatically used by both Visual Studio and Blend):

    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    Aside: If you're someone like me who writes your XAML by hand, there's no need to memorize the URI above - just copy the default xmlns from the top of any XAML file and add "/toolkit" to the end!

    You can read more about this feature in the Silverlight SDK article about a similar change for the SDK assemblies.

     

    Changed AssemblyFileVersion for all assemblies

    AssemblyFileVersion

    Based on feedback from the Visual Studio and Blend teams regarding design-time issues when the Silverlight 3 and Silverlight 4 Toolkits were both installed, we've changed the AssemblyFileVersion of all Silverlight 4 Toolkit assemblies. Where it used to be 2.0.5.0 (which is what's used by versions of Silverlight so far), Toolkit assemblies now specify 4.0.5.0. This change resolves the confusion for both design tools by uniquely distinguishing the Silverlight 3 and Silverlight 4 Toolkit assemblies.

     

    Removed the Reactive Extensions dependency

    In previous releases, limited parts of the Silverlight Toolkit made use of the Reactive Extensions for .NET (Rx) library internally. Those Toolkit assemblies therefore had a direct dependency on the version of the Rx assemblies we referenced when we compiled the Toolkit. However, Rx binaries released by the Rx team in the time since we published the last Toolkit have included some breaking changes. This has caused frustration for customers wanting to use more recent Rx bits in their own applications because of the fact that a XAP can contain only one instance of a particular assembly. Those customers were often unable to upgrade successfully as a result of mismatched Rx assembly versions. Because of the feedback we've received here, Toolkit assemblies no longer have a dependency on the Rx assemblies and applications are again free to reference whatever version of Rx they wish!

    Note: Most applications should be completely unaffected by this change. However, if your project has specific references to any of the Rx assemblies that were previously located in the Bin directory of the Toolkit install (System.CoreEx.dll, System.Interactive.dll, or System.Reactive.dll), those references are no longer valid and should be removed. In rare cases, it may be necessary to add an explicit reference to their replacement assembly, System.Windows.Controls.Toolkit.Internals.dll, which is now present in the Bin directory instead.

     

    Removed System.ComponentModel.Composition.Packaging.Toolkit

    MEF's PackageCatalog class was renamed to DeploymentCatalog and moved to the System.ComponentModel.Composition.Initialization assembly that is part of the Silverlight 4 SDK. The System.ComponentModel.Composition.Packaging.Toolkit assembly was left with nothing in it and therefore removed from the Silverlight Toolkit.

     

    Various bug fixes

    This release also includes bug fixes for a variety of problems customers have reported or that were identified internally.

     

    As you can see, the Toolkit has a lot of new stuff for Silverlight 4! Of course, the first thing to do is install Silverlight 4! Once you've done that, please check out the live Toolkit samples application, download the Toolkit installer, and start writing great applications!

     

    We hope you enjoy the new release!! :)

  • Delay's Blog

    Silverlight "Surface" Demonstration [Silverlight implementation of Surface's "photo table" UI]

    • 43 Comments

    Yesterday, Microsoft announced its Surface product to much buzz and excitement. The demo videos I saw featured a "photos on a table" user interface that displayed a handful of photos sitting on the Surface. The interface allowed people to easily move the virtual photos around by touching them in the center and sliding them to a different location on the screen. By touching the corners instead, photos could be sized and rotated with ease.

    It struck me that this interface would be pretty easy to replicate with Silverlight and I decided to do so as a learning exercise. I spent some time on this last night and tonight and came up with an application that looks like this:

    Silverlight "Surface" Demonstration

    You can click here (or on the image above) to play with the application in your browser. The code's quite simple; click here to download the source code and play around with it yourself! (To build the project, you'll want to use Visual Studio Orcas Beta 1 and the Silverlight Tools.)

    Notes:

    • When the application loads, it randomly lays out the sample photos. To interact with a photo, simply move the mouse pointer over the photo and click+drag on one of the yellow control elements that appears. The center element moves the photo around and the corner elements all rotate/resize it. Click on any part of a photo to bring it to the top of the pile.
    • Without the snazzy Surface hardware support, this application doesn't support the Human Finger 1.0 input device. :) However, if you run it on a Tablet PC or hooked up to something like the Wacom Cintiq, you can get pretty close.
    • As expected, Silverlight's XAML support makes this kind of interface pretty easy to build. I understand the Surface UI was written using WPF (Silverlight's big brother), so I suspect some of the techniques they used are fairly similar to what's being done here.
    • The sample images are a few of my favorite wallpapers that come with Windows Vista. I have not included them with the code download because they're large and it's easy enough to copy them from your own %windir%\Web\Wallpaper directory. Or just use your own favorite images!
    • I don't demonstrate it here (partly because I don't have a good nature video), but it would be easy to add video support so that each of the photos was a streaming video instead. Hum, maybe I'll do a follow-up post... :)

    It's pretty obvious that XAML lets you do some pretty neat things with ease - I look forward to even more compelling new interfaces based on Silverlight and WPF!

  • Delay's Blog

    Lighting up the XML Paper Specification [Proof-of-concept XPS reader for Silverlight!]

    • 46 Comments

    Since getting involved with Silverlight and finding out the XPS document type WPF enables has XAML at its core, I've been wondering how Silverlight would do as a lightweight XPS viewer.

    First, a bit of background: WPF is the Windows Presentation Foundation and represents a new approach to UI for Windows. XPS refers to the XML Paper Specification, a device-independent file format for flexible document representation (think PDF) that's part of Office 2007 and .NET 3.0. WPF offers rich support for displaying XPS documents via its DocumentViewer and XpsDocument classes (among others). Because the 1.1 Alpha release doesn't currently include the relevant classes, Silverlight wouldn't appear to be well suited for XPS document display at first glance...

    However, Silverlight does have the Downloader class which includes support for packages (for the purposes of this discussion, packages are basically just ZIP archives). Since an XPS document is really just a package, and the core document format XPS uses is XAML, and Silverlight speaks XAML (well, at least a subset of it!), maybe it's not such a stretch to do XPS with Silverlight after all.

    I thought it would be a neat exercise to try to write an XPS viewer with the publically available Silverlight 1.1 Alpha bits so I gave it a try and ended up with an application I call SimpleSilverlightXpsViewer:

    SimpleSilverlightXpsViewer Application

    Go ahead and click here (or on the image above) to play around with the application in your browser. If you find yourself wondering how it works, just click here to download the complete source code/resources and play around with it yourself! (To build the SimpleSilverlightXpsViewer project, you'll want to use Orcas Beta 1 and the Silverlight Tools.)

    Of course, this is just a proof-of-concept application built on an Alpha platform, so there are some rough edges. :) Some notes are in order:

    • I created my own XPS documents so I wouldn't have to worry about getting permission to use someone else's XPS documents. Office 2007 comes with a handy "Microsoft XPS Document Writer" printer driver that lets you create an XPS document from any application simply by printing to the XPS "printer" (which then saves the resulting output to a file you specify). I created the three sample documents this way: the "Intro" document came from a simple Word document, the "Blog" document came from my blog via IE7, and the "Site" document came from the Silverlight Forums via IE7 with a landscape page layout.
    • Because the only kind of XPS document I've worked with is the kind the XPS printer driver outputs, there's a very good chance SimpleSilverlightXpsViewer won't understand the internal format of other valid XPS files. Remember, though, that I didn't set out to write an XPS file parser - I just set out to write a simple XPS viewer for Silverlight. :)
    • The translation of "XPS XAML" to "Silverlight XAML" is done by the XpsToSilverlightXamlReader class, a minimal derivation from XmlReader that performs on-the-fly modification of the "XPS XAML" to translate it into "Silverlight XAML". Specifically, some elements are renamed, some attribute values are tweaked, and some attributes are removed entirely. The tweaking is done to address the Glyphs.FontUri/ImageBrush.ImageSource issue mentioned next and re-points the relevant content to an external location.
    • XPS documents are entirely self-contained, with any necessary fonts and images embedded in the file (package) itself. This is great for simplifying distribution and Silverlight's Downloader class makes it easy to get at individual files in a package. However, SimpleSilverlightXpsViewer works best when the images and the fonts are extracted from the XPS file:
      • Under the right conditions, embedded images can be fetched by Silverlight by using the ImageBrush.SetSource method. However, things tend to break if there are multiple references to the same image in a single page (an exception is thrown when the second call to SetSource is made), so SimpleSilverlightXpsViewer doesn't enable this by default. Interested parties can #define SETSOURCE (for both C# files) to experiment with this feature (things work fine for the first page of all of the sample documents, but break on the second pages of the Blog and Site documents).
      • The default behavior of Glyphs.FontUri does not seem to automatically pull the font out of the package - at least not as it's used by SimpleSilverlightXpsViewer (possibly because Silverlight doesn't seem to like the leading '/' on package-relative paths). TextBlock has a SetFontSource method that seems interesting, but XPS XAML uses the Glyphs class which doesn't seem to support SetFontSource.
    • For some reason, the XPS documents generated by the XPS printer driver aren't directly open-able by Silverlight's Downloader (a COM exception is thrown). However, I've found that a quick un-ZIP/re-ZIP with either of my favorite ZIP tools yields XPS documents that open right up. I suspect this is due to a simple issue with the Alpha Downloader implementation (endian-ness of the ZIP file, some special section embedded by the XPS printer driver, etc.) that could be fixed by the Silverlight team without much difficulty.
    • Silverlight doesn't support the TIFF file format (which is not surprising because full support can be quite complex and TIFF images are hardly ever used on the web). As it happens, XPS printer driver output may contain TIFF images (it seems they're used as a mask of some kind behind another PNG or JPG image) - SimpleSilverlightXpsViewer simply ignores the TIFF images and neatly side-steps the support issue. :)

    While SimpleSilverlightXpsViewer is a cute proof-of-concept application I enjoyed writing, it is hardly the final word on Silverlight XPS support. (Hey, I'm not even on the Silverlight team!) I don't know what the official plans are for more formal XPS support in the Silverlight platform, but my experience with SimpleSilverlightXpsViewer suggests that most of the pieces are already in place for a pretty reasonable XPS experience with the Silverlight 1.1 Alpha. Throw in a couple of tweaks to Silverlight (and/or SimpleSilverlightXpsViewer!), and it should be possible to provide a pretty compelling XPS-like user experience for Silverlight!

  • Delay's Blog

    The web just got even better... [Silverlight announced at MIX07!]

    • 48 Comments

    During his keynote at the MIX07 conference in Las Vegas, Scott Guthrie showed off some of the power of Microsoft's recently announced Silverlight platform. In particular, the ability to easily run managed code in the web browser - coupled with a powerful rendering engine - seems like it will to radically change the landscape of the web. My team had the privilege of writing the Silverlight Airlines demonstration he used to show off just how easy it is to develop with Silverlight. Demoed on stage, it looked something like the following image:

    Silverlight Airlines Demonstration

    Now that your appetite is whetted, go ahead and click here (or on the image above) to view the demo in your browser with the Silverlight 1.1 Alpha thanks to the seamless cross-browser, cross-platform support that Silverlight provides.

    When our manager Shawn Burke asked us to put this demo together, my coworker Ted Glaza and I had practically no experience with Silverlight or WPF. So we spent about a week playing around with the technology to learn how it worked. By that time, the general concept of the demo was fairly well established and we spent time the next week developing the foundations of the application. Before long, we had a working demo that we showed off to Scott. The third week was spent incorporating visual feedback from a designer and adding some finishing touches. For those of you keeping track at home, that's one cool app written by two developers in just three weeks - beginning with nothing and building on top of a platform that was still being developed - pretty compelling, I think!

    In the spirit of openness and learning, you can click here to download the complete source code for this demo application and play around with it yourself!

    A few notes on the application:

    • It's implemented as three self-contained controls (the map, calendar, and itinerary picker) that are hooked together via a couple of simple event handlers and property accessors.
    • The goal of code/design separation was achieved here to an extent I haven't experienced before. In particular, the fact that we were able to incorporate an external party's XAML design into our existing code with such ease was a rare treat.
    • I experimented with a vaguely CSS-y approach to XAML design with the calendar and itinerary picker controls I wrote, overlapping a number of different styles and using opacity to display the right style at the right time. I liked the way it worked out here because it enabled me to (for example) completely define the look of the calendar's day cells in a single XAML file - even though that style is actually somewhat complex (there are different styles for alternating months, weekends, hovering, selection, etc.).
    • The "plane flying" animation was Ted's doing and adds a really nice effect. All it took to implement was a plane graphic, a few transforms, a couple of animations, and a bit of high school math. :)
    • The XAML content is automatically resized to fit the browser window (while maintaining its original aspect ratio) with some JavaScript code that hooks the Silverlight control's onLoad and onResize events and manipulates two simple transforms it creates for that purpose. Silverlight lets you program against it with C# and JavaScript - at the same time!
    • In order to compile and build the source code, you need Visual Studio "Orcas" Beta 1 and the Silverlight Tools installed on you machine. Complete details and download links for these tools (and others) can be found on the Silverlight web site.
    • The inspiration for the demo application came from Bret Victor's Magic Ink essay which is a great read and recommended for anyone who's interested in user interface design.

    The Silverlight Airlines demo was a fun project to work on - I look forward to be seeing (and doing!) a lot more with Silverlight in the coming days!

    PS - Since the keynote presentation, there has been some interest in reusing the calendar control. Beyond making the source code available here, I may write a follow-up blog post going into more detail about the calendar itself. As a quick teaser: it's capable of more sophisticated display than what's in the demo application. :)

    PPS - If you watched the Scott Guthrie keynote, you probably saw that there was a time Scott tried to switch the display screen over to the Mac to demonstrate something and it took a while for the conference's A/V folks to actually make the switch. A couple of people have asked if this delay was due to a problem with the Mac or Silverlight. I happen to have been sitting backstage mere inches away from the Mac in question (conferences use KVM switches to keep all the demo machines backstage) and I can assure you that there was no technical issue with the Mac or Silverlight. Aside from the conference tech taking a little while to switch the display over, there were no technical glitches during the demo. :)

Page 1 of 28 (277 items) 12345»