Delay's Blog

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

Posts
  • 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

    SplitButtoning hairs [Two fixes for my Silverlight SplitButton/MenuButton implementation - and true WPF support]

    • 31 Comments

    One of my ContextMenu test cases for the April '10 release of the Silverlight Toolkit (click here for the full write-up) was to implement a quick "split button" control for Silverlight using Button and ContextMenu. In that post, I cautioned that my goal at the time was to do some scenario testing, not to build the best SplitButton control ever. However, what I came up with seemed to work pretty well in practice and I figured folks could probably use the code mostly as-is.

    And it seems like they did - because I got two bug reports in that post's comments section! :)

    SplitButton and MenuButton

     

    Let me address them in reverse order:

    The position of the ContextMenu was wrong when the browser is zoomed: True enough - though I'm going to ask for a bit of leniency here because the cause of the misalignment is actually a bug in Silverlight (which I've already reported). It seems the results of a call to element.TransformToVisual(Application.Current.RootVisual) or element.TransformToVisual(null) are not consistent for elements that are vs. are not inside a Popup control when the browser is zoomed (in or out). As a result, the SplitButton code to position the menu got inconsistent data and was unable to place the menu correctly. I've tweaked the code slightly to accommodate the underlying issue and now the menu is properly aligned at any zoom setting.

    While I was at it, I figured it might be nice if the menu moved around with the SplitButton as the user resized the browser or changed the zoom while the menu was displayed. This is admittedly an edge case, but it's easy enough to handle by hooking the LayoutUpdated event while the menu is displayed (and only while it's displayed!), so I did that and now the menu sticks to the button and refuses to be shaken off. :)

    The code didn't work on WPF: I had a footnote claiming my Silverlight implementation should work on WPF as well, though I hadn't tried it myself. It turns out that statement is mostly true - except for the positioning logic which bumps into an subtle API incompatibility with the TransformToVisual method. (Noticing a pattern here?) In the process of getting things working for WPF, I realized the code to position the menu could be simplified somewhat with the (WPF-only) TranslatePoint method. Therefore, the actual positioning logic is a tad different across the two platforms ("a tad" == 4 lines of code) while everything else stays the same. This time when I claim SplitButton and MenuButton work on WPF, it's because I've tried it. :)

    In fact, I've added a new, WPF-specific assembly (SplitButtonWpf) and demo (SplitButtonWpfSample) to the sample code associated with this post. Which means there is a dedicated assembly containing SplitButton and MenuButton for both platforms as well as a separate sample application for each!

     

    [Click here to download the complete Silverlight/WPF source code for SplitButton/MenuButton and the sample application shown above.]

     

    With those changes in place (and an unrelated key handling tweak for WPF), I feel even better about the prospects of using SplitButton and MenuButton in a real application. Naturally, if something else comes up, please let me know. Otherwise, I hope you find it useful!

  • Delay's Blog

    As the platform evolves, so do the workarounds [Better SetterValueBindingHelper makes Silverlight Setters better-er!]

    • 27 Comments

    Back in May, I mentioned that Silverlight 2 and 3 don't support putting a Binding in the Value of a Setter. I explained why this is useful (ex: MVVM, TreeView expansion, developer/designer separation, etc.) and shared a helper class I wrote to implement the intended functionality on Silverlight. My workaround supported setters for normal DependencyPropertys as well as attached ones, so it covered all the bases. It worked well on both flavors of Silverlight and a bunch of you went off and used SetterValueBindingHelper successfully in your own projects.

    The sun was shining, birds were chirping, and all was right with (that part of) the world...

    SetterValueBindingHelperDemo sample

     

    Now flash forward to a few days ago when I was contacted by fellow Silverlight team members RJ Boeke and Vinoo Cherian with a report that certain uses of SetterValueBindingHelper which worked fine on Silverlight 2 and 3 were likely to break if used in a possible future version of Silverlight that was more consistent with WPF's handling of such things. You can imagine my astonishment and dismay...

    Important aside: The Silverlight team takes backward compatibility very seriously, so running any Silverlight 2 or 3 application with SetterValueBindingHelper on such a future version of Silverlight would continue to work in the expected manner. The Silverlight team makes a concerted effort to ensure that each version of Silverlight is "bug compatible" with previous versions to prevent existing applications from suddenly breaking when a new version of Silverlight comes out. However, were someone to recompile such an application to target a newer release of Silverlight, that application would no longer be subject to the backwards compatibility quirks and would begin seeing the new (more correct/consistent) platform behavior.

    RJ and Vinoo pointed out that a more WPF-consistent handling of Styles would break one of the samples that was part of my original blog post. Specifically, the following example would not have the first Binding applied (note: per convention, code in italics is wrong):

    <Style TargetType="Button">
        <!-- WPF syntax:
        <Setter Property="Grid.Column" Value="{Binding}"/>
        <Setter Property="Grid.Row" Value="{Binding}"/> -->
        <Setter Property="local:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <local:SetterValueBindingHelper
                    Type="System.Windows.Controls.Grid, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
                    Property="Column"
                    Binding="{Binding}"/>
            </Setter.Value>
        </Setter>
        <Setter Property="local:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <local:SetterValueBindingHelper
                    Type="Grid"
                    Property="Row"
                    Binding="{Binding}"/>
            </Setter.Value>
        </Setter>
    </Style>
    

    What's important to note is that two Setters are both setting the same Property (local:SetterValueBindingHelper.PropertyBinding) and WPF optimizes this scenario to only apply the last Value it sees. Clearly, it was time to think about how tweak SetterValueBindingHelper so it would work with this theoretical future release of Silverlight...

    Tangential aside: This kind of platform change wouldn't affect just SetterValueBindingHelper - any place where multiple Setters targeted the same Property would behave differently. But that difference won't matter 99% of the time - SetterValueBindingHelper is fairly unique in its need that every Value be applied.

     

    One idea for a fix is to expose something like PropertyBinding2 from SetterValueBindingHelper and treat it just like another PropertyBinding. While that would definitely work, how do we know that two properties is enough? What if you need three or four? No, despite its simplicity, this is not the flexible solution we're looking for.

    Taking a step back, what we really want is to somehow provide an arbitrary number of Property/Binding pairs instead of being limited to just one. And if you read that last sentence and thought "Collection!", I like the way you think. :) Specifically, what if the same SetterValueBindingHelper class we're already using to provide the attached DependencyProperty and the data for it were also capable of storing a collection of other SetterValueBindingHelper objects? Yeah, sure, that would work!

     

    So let's lay a few ground rules to help guide us:

    • Every current use of SetterValueBindingHelper should continue to be valid after we make our changes. In other words, upgrading should be a simple matter of dropping in the new SetterValueBindingHelper.cs file and that's all.
    • The new SetterValueBindingHelper syntax should work correctly for the current Silverlight 3 release as well as this mythical future version of Silverlight with the WPF-consistent Style changes.
    • The new collection syntax should be easy to use and easy to understand.
    • Arbitrary nesting is unnecessary; either someone's using a SetterValueBindingHelper on its own, or else they're using it as a container for a single, nested layer of SetterValueBindingHelper children.
    • We could try to be fancy and let children inherit things from their parent, but it's not actually as useful as it seems. Let's not go there and instead keep everything simple and consistent.

    Keeping these guidelines in mind, the resulting changes to SetterValueBindingHelper give us the following alternate representation of the above XAML which works fine on Silverlight 3 today and will also give the desired effect on a possible future version of Silverlight with the WPF optimization:

    <Style TargetType="Button">
        <!-- WPF syntax:
        <Setter Property="Grid.Column" Value="{Binding}"/>
        <Setter Property="Grid.Row" Value="{Binding}"/> -->
        <Setter Property="delay:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <delay:SetterValueBindingHelper>
                    <delay:SetterValueBindingHelper
                        Type="System.Windows.Controls.Grid, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
                        Property="Column"
                        Binding="{Binding}"/>
                    <delay:SetterValueBindingHelper
                        Type="Grid"
                        Property="Row"
                        Binding="{Binding}"/>
                </delay:SetterValueBindingHelper>
            </Setter.Value>
        </Setter>
    </Style>
    
    Aside: The two different ways of identifying Grid above are part of the original sample showing that both ways work - in practice, both instances would use the simple "Grid" form.

     

    Other than the namespace change to "delay" (for consistency with my other samples), the only change here is the extra SetterValueBindingHelper wrapper you see highlighted. Everything else is pretty much the same and now it works on imaginary versions of Silverlight, too! :) So if you're working on an app and you find yourself needing SetterValueBindingHelper, please use this latest version; you can rest assured that you're future-proof.

     

    [Click here to download the complete source code for SetterValueBindingHelper and its sample application.]

     

    Here's the updated code in its entirety. Please note that I have used a normal (i.e., non-observable) collection, so dynamic updates to the Values property are not supported. This was a deliberate decision to minimize complexity. (And besides, I've never heard of anyone modifying the contents of a Style dynamically.)

    /// <summary>
    /// Class that implements a workaround for a Silverlight XAML parser
    /// limitation that prevents the following syntax from working:
    ///    &lt;Setter Property="IsSelected" Value="{Binding IsSelected}"/&gt;
    /// </summary>
    [ContentProperty("Values")]
    public class SetterValueBindingHelper
    {
        /// <summary>
        /// Optional type parameter used to specify the type of an attached
        /// DependencyProperty as an assembly-qualified name, full name, or
        /// short name.
        /// </summary>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
            Justification = "Unambiguous in XAML.")]
        public string Type { get; set; }
    
        /// <summary>
        /// Property name for the normal/attached DependencyProperty on which
        /// to set the Binding.
        /// </summary>
        public string Property { get; set; }
    
        /// <summary>
        /// Binding to set on the specified property.
        /// </summary>
        public Binding Binding { get; set; }
    
        /// <summary>
        /// Collection of SetterValueBindingHelper instances to apply to the
        /// target element.
        /// </summary>
        /// <remarks>
        /// Used when multiple Bindings need to be applied to the same element.
        /// </remarks>
        public Collection<SetterValueBindingHelper> Values
        {
            get
            {
                // Defer creating collection until needed
                if (null == _values)
                {
                    _values = new Collection<SetterValueBindingHelper>();
                }
                return _values;
            }
        }
        private Collection<SetterValueBindingHelper> _values;
    
        /// <summary>
        /// Gets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element for which to get the property.</param>
        /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            return (SetterValueBindingHelper)element.GetValue(PropertyBindingProperty);
        }
    
        /// <summary>
        /// Sets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element on which to set the property.</param>
        /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(PropertyBindingProperty, value);
        }
    
        /// <summary>
        /// PropertyBinding attached DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty PropertyBindingProperty =
            DependencyProperty.RegisterAttached(
                "PropertyBinding",
                typeof(SetterValueBindingHelper),
                typeof(SetterValueBindingHelper),
                new PropertyMetadata(null, OnPropertyBindingPropertyChanged));
    
        /// <summary>
        /// Change handler for the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="d">Object on which the property was changed.</param>
        /// <param name="e">Property change arguments.</param>
        private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Get/validate parameters
            var element = (FrameworkElement)d;
            var item = (SetterValueBindingHelper)(e.NewValue);
    
            if ((null == item.Values) || (0 == item.Values.Count))
            {
                // No children; apply the relevant binding
                ApplyBinding(element, item);
            }
            else
            {
                // Apply the bindings of each child
                foreach (var child in item.Values)
                {
                    if ((null != item.Property) || (null != item.Binding))
                    {
                        throw new ArgumentException(
                            "A SetterValueBindingHelper with Values may not have its Property or Binding set.");
                    }
                    if (0 != child.Values.Count)
                    {
                        throw new ArgumentException(
                            "Values of a SetterValueBindingHelper may not have Values themselves.");
                    }
                    ApplyBinding(element, child);
                }
            }
        }
    
        /// <summary>
        /// Applies the Binding represented by the SetterValueBindingHelper.
        /// </summary>
        /// <param name="element">Element to apply the Binding to.</param>
        /// <param name="item">SetterValueBindingHelper representing the Binding.</param>
        private static void ApplyBinding(FrameworkElement element, SetterValueBindingHelper item)
        {
            if ((null == item.Property) || (null == item.Binding))
            {
                throw new ArgumentException(
                    "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
            }
    
            // Get the type on which to set the Binding
            Type type = null;
            if (null == item.Type)
            {
                // No type specified; setting for the specified element
                type = element.GetType();
            }
            else
            {
                // Try to get the type from the type system
                type = System.Type.GetType(item.Type);
                if (null == type)
                {
                    // Search for the type in the list of assemblies
                    foreach (var assembly in AssembliesToSearch)
                    {
                        // Match on short or full name
                        type = assembly.GetTypes()
                            .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                            .FirstOrDefault();
                        if (null != type)
                        {
                            // Found; done searching
                            break;
                        }
                    }
                    if (null == type)
                    {
                        // Unable to find the requested type anywhere
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                            "Unable to access type \"{0}\". Try using an assembly qualified type name.",
                            item.Type));
                    }
                }
            }
    
            // Get the DependencyProperty for which to set the Binding
            DependencyProperty property = null;
            var field = type.GetField(item.Property + "Property",
                BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
            if (null != field)
            {
                property = field.GetValue(null) as DependencyProperty;
            }
            if (null == property)
            {
                // Unable to find the requsted property
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                    "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
                    item.Property, type.Name));
            }
    
            // Set the specified Binding on the specified property
            element.SetBinding(property, item.Binding);
        }
    
        /// <summary>
        /// Returns a stream of assemblies to search for the provided type name.
        /// </summary>
        private static IEnumerable<Assembly> AssembliesToSearch
        {
            get
            {
                // Start with the System.Windows assembly (home of all core controls)
                yield return typeof(Control).Assembly;
    
                // Fall back by trying each of the assemblies in the Deployment's Parts list
                foreach (var part in Deployment.Current.Parts)
                {
                    var streamResourceInfo = Application.GetResourceStream(
                        new Uri(part.Source, UriKind.Relative));
                    using (var stream = streamResourceInfo.Stream)
                    {
                        yield return part.Load(stream);
                    }
                }
            }
        }
    }
    
  • Delay's Blog

    Safely avoiding the "access denied" dialog [How to: Work around the access denied cross-domain IFRAME issue in the AJAX Control Toolkit]

    • 27 Comments

    Bertrand recently blogged "How to work around the access denied cross-domain frame issue in ASP.NET Ajax 1.0". Unfortunately, a similar issue exists in the AJAX Control Toolkit - with a similar workaround that's detailed in this post.

    Background: The AJAX Control Toolkit attempts to use as much of the ASP.NET AJAX infrastructure as possible in order to keep things simple and benefit from the established architecture of ASP.NET AJAX. However, the ASP.NET AJAX 1.0 implementation of Sys.UI.getLocation was not accurate for IFRAME content with certain page layouts in IE6 - one of which was used by the Toolkit test harness. We couldn't have our automated tests failing - and the ASP.NET AJAX team wasn't able to include a fix in their 1.0 release - so we needed to address this somehow. Since we had developed our own getLocation implementation that was accurate in IE6, we decided to route all Toolkit calls to getLocation through our own wrapper function - which used our improved implementation for IE6 and called through to the ASP.NET AJAX implementation for everything else. This works pretty well - except that our version suffers from the same cross-domain permissions issue that the ASP.NET AJAX version suffers from (please refer to Bertrand's post for more details).

    Fix: We've just checked in a fix to the Toolkit's Development branch to add the same try/catch wrapper that Bertrand suggests; this fix will be included with the next Toolkit release (in about a month). In the meantime, people who want the fix sooner are encouraged to apply the changes themselves. To do so, open AjaxControlToolkit.sln in Visual Studio, open the file AjaxControlToolkit\Common\Common.js, find the getLocation function, add the yellow, italic block below, and build the project to get a new AjaxControlToolkit.dll with the fix. The complete function definition with the fix applied is included here to make this as easy as possible:

    getLocation : function(element) {
        
    /// <summary>Gets the coordinates of a DOM element.</summary>
        /// <param name="element" domElement="true"/>
        /// <returns type="Sys.UI.Point">
        ///   A Point object with two fields, x and y, which contain the pixel coordinates of the element.
        /// </returns>

        // workaround for an issue in getLocation where it will compute the location of the document element.
        // this will return an offset if scrolled.
        //
        if (element === document.documentElement) {
            
    return new Sys.UI.Point(0,0);
        }

        
    // Workaround for IE6 bug in getLocation (also required patching getBounds - remove that fix when this is removed)
        if (Sys.Browser.agent == Sys.Browser.InternetExplorer && Sys.Browser.version < 7) {
            
    if (element.window === element || element.nodeType === 9 || !element.getClientRects || !element.getBoundingClientRect) return new Sys.UI.Point(0,0);

            
    // Get the first bounding rectangle in screen coordinates
            var screenRects = element.getClientRects();
            
    if (!screenRects || !screenRects.length) {
                
    return new Sys.UI.Point(0,0);
            }
            
    var first = screenRects[0];

            
    // Delta between client coords and screen coords
            var dLeft = 0;
            
    var dTop = 0;

            var inFrame = false;
            
    try {
                inFrame = element.ownerDocument.parentWindow.frameElement;
            }
    catch(ex) {
                
    // If accessing the frameElement fails, a frame is probably in a different
                // domain than its parent - and we still want to do the calculation below
                inFrame = true;
            }

            
    // If we're in a frame, get client coordinates too so we can compute the delta
            if (inFrame) {
                // Get the bounding rectangle in client coords
                var clientRect = element.getBoundingClientRect();
                
    if (!clientRect) {
                    
    return new Sys.UI.Point(0,0);
                }

                
    // Find the minima in screen coords
                var minLeft = first.left;
                
    var minTop = first.top;
                
    for (var i = 1; i < screenRects.length; i++) {
                    
    var r = screenRects[i];
                    
    if (r.left < minLeft) {
                        minLeft = r.left;
                    }
                    
    if (r.top < minTop) {
                        minTop = r.top;
                    }
                }

                
    // Compute the delta between screen and client coords
                dLeft = minLeft - clientRect.left;
                dTop = minTop - clientRect.top;
            }

            
    // Subtract 2px, the border of the viewport (It can be changed in IE6 by applying a border style to the HTML element,
            // but this is not supported by ASP.NET AJAX, and it cannot be changed in IE7.), and also subtract the delta between
            // screen coords and client coords
            var ownerDocument = element.document.documentElement;
            
    return new Sys.UI.Point(first.left - 2 - dLeft + ownerDocument.scrollLeft, first.top - 2 - dTop + ownerDocument.scrollTop);
        }

        
    return Sys.UI.DomElement.getLocation(element);
    },

    Sorry for the trouble - we hope this patch helps any people who might be running into this issue!

    Updated at 6pm: Modified the getLocation implementation to return the correct value in all cases.

  • Delay's Blog

    There's no substitute for customer feedback! [Improving Windows Phone 7 application performance now a bit easier with LowProfileImageLoader and DeferredLoadListBox updates]

    • 26 Comments

    PhonePerformance List Scrolling sample Windows Phone 7 applications run on hardware that's considerably less powerful than what drives typical desktop and laptop machines. Therefore, tuning phone applications for optimum performance is an important task - and a challenging one! To help other developers, I previously coded and blogged about two classes: LowProfileImageLoader (pushes much of the cost of loading images off the UI thread) and DeferredLoadListBox (improves the scrolling experience for long lists). These two classes can be used individually or together and have become a regular part of the recommendations for developers experiencing performance issues.

     

    I've heard from lots of people who've benefitted from LowProfileImageLoader and DeferredLoadListBox - thank you! I've also received some great suggestions; I recently implemented some of them and wanted to share the new code/bits:

    • The first issue was reported to me by Corrado Cavalli via email. Whereas my sample applications loaded data after they'd initialized, Corrado's DeferredLoadListBox scenario populated its data during initialization. This led to code running in OnApplyTemplate which made the (wrong) assumption that the ListBox's ListBoxItem containers would already have been created. That's not the case during OnApplyTemplate, so DeferredLoadListBox got confused and threw an exception. The simple fix for this problem is to allow for missing containers during OnApplyTemplate - which I've done. Fortunately, subsequent activity (container creation during PrepareContainerForItemOverride) already ensures the right things happen after the containers are created.

    • The second issue was reported to me by Pat Long in the comments to my first blog post. The problem he encountered was that Blend would crash when working with an application using LowProfileImageLoader in certain cases (presumably because of the background worker thread it creates). There's an easy fix here as well - simply short-circuit the worker thread at design-time because the performance implications of LowProfileImageLoader aren't relevant then anyway. I reproduced the problem myself with Visual Studio and fixed it there - then I checked Pat's blog and found he'd done almost exactly the same thing for his Blend-based scenario! [It's nice when separate efforts arrive at the same place. :) ]

    • The third suggestion also came from comments to that blog post - David Burela wanted to use LowProfileImageLoader for images that were part of his application. I'd only been considering the cost of downloading images when I wrote this class, but David pointed out that much of the same "UI thread-friendly" logic should apply to local images as well. Fortunately, it was a simple matter to add support for relative Uris (ex: "/Images/Picture.jpg") - and now LowProfileImageLoader works well with both kinds of images!

      Note: For this new functionality to work, the project's images must have their "Build Action" set to "Content" (not "Resource"). (Here's what that setting looks like in Visual Studio.)
    • The fourth suggestion came from the comments to my second blog post where Johnny Westlake pointed out that LowProfileImageLoader could be counterproductive once it had already worked its magic. In other words, though it's great for lowering the cost of initial image load, the throttling behavior might be undesirable during subsequent loads (ex: during Back button navigation) because by that time the image has been cached by the web stack and the download cost is much lower. At first, I wasn't sure how LowProfileImageLoader could tell which situation a particular image was in - then I realized I didn't have to! :)

      What I've done instead is add a static LowProfileImageLoader.IsEnabled property (true by default) that the developer can toggle whenever he/she wants to (ex: on Back navigation to a page that has already used LowProfileImageLoader). When this property is set to false, LowProfileImageLoader doesn't perform its UI thread sleight-of-hand so the image load behavior is the same as it would have been if LowProfileImageLoader weren't present at all. While this might seem like a bit of a pass the buck move on my part, the practical truth is that the application's author has way more context than LowProfileImageLoader does. So in lieu of a reliable way to detect the cache state of individual images (I'm open to suggestions, by the way!), the new IsEnabled property seems like a reasonable "next best thing".

     

    [Click here to download the compiled PhonePerformance assembly, sample applications, and full source code for everything.]

     

    My thanks go out to the people who have shared their experience and suggestions with/for LowProfileImageLoader and DeferredLoadListBox! While these two classes are not appropriate in every situation, they seem to be useful in enough situations that it's worth giving them a quick try if you're experiencing relevant performance problems. Both classes are easy to hook up, so trying them out takes no more than a couple of minutes - which will be time well spent if the problem goes away!

    I wish everyone good luck with their Windows Phone 7 applications - and please don't forget the value of great performance! :)

  • Delay's Blog

    My new home page, extended [Updated collection of great Silverlight and WPF Charting resources!]

    • 25 Comments

    It's been a while since the March 09 release of the Silverlight Toolkit - and even longer since I last posted a collection of Charting links. It's clearly time for an update, so I've added a bunch of new links to the collection below (FYI: previously published links are gray):

    Overviews (100 level)

    Scenarios (200 level)

    Internals (300 level)

    Jafar Husain's posts (Partner level)

    My posts (Ego level)

    Many, many thanks to everyone who has spent time helping others learn how to use Silverlight/WPF Charting!

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

  • Delay's Blog

    Controls are like diapers: you don't want a leaky one [Implementing the WeakEvent pattern on Silverlight with the WeakEventListener class]

    • 25 Comments

    One of the nice things about developing on a platform that uses a garbage collecting memory manager (like Silverlight and WPF) is that the traditional concerns about memory leaks pretty much go away; most common types of memory leaks are impossible in a garbage collected environment. I say "most" and not "all" because there are still a few ways to leak memory - typically by creating a reference to an object and then "forgetting" about that reference. Sometimes this forgetfulness is simply an oversight on the part of the developer, but sometimes it is due to the reference being created in such a way that it's not obvious it even exists...

    One of the easiest ways to create a "hidden" reference is by creating an event handler. Greg Schechter blogged in detail about the event handler situation back in 2004, and interested readers would do well to refer to his post for more details and some pretty diagrams. To summarize the issue briefly: when component A attaches an event handler to an event on component B, what happens behind the scenes is that component B creates a reference to component A - which it needs in order to provide a notification to A when the event is fired. This "backwards" reference is a bit subtle, but if you know what you're looking for, it's usually not too hard to spot.

    What's more challenging is when a component you're using creates one of these backwards references in response to an action that's (superficially) completely unrelated to the event handling. As an exercise, see if you can spot the event handler here:

    control.ItemsSource = collection;

    Not so obvious, huh? :) The context needed to understand what's going on here is that an the control variable is some type that derives from ItemsControl (such as ListBox) and the collection variable is some type that derives from ObservableCollection<T>. It so happens that when an ItemsControl sees an assignment to its ItemsSource property of an object that implements INotifyCollectionChanged, it automatically adds a handler for that object's CollectionChanged event. And there's the potentially troublesome backward reference...

    All it takes to start leaking memory at this point is an application with a long-lived reference to an ObservableCollection that gets passed to a short-lived ItemsControl that gets discarded. What can end up happening is that all of the references to the ItemsControl go away when it is discarded except for the one the ItemsControl itself created to listen to CollectionChanged events. Unless something is done to avoid this problem, the long-lived reference to the ObservableCollection will inadvertently keep the ItemsControl and all of its references alive considerably longer than the application developer expects. Furthermore, if the application is creating and discarding these ItemsControls on a fairly regular basis, it will quickly build up a sizable memory leak due to the accumulation of all the "discarded" ItemsControls.

    As luck would have it, this situation was well understood and by the WPF team and that platform exposes APIs to implement what they call the WeakEvent pattern. WPF makes use of the WeakEvent pattern for its own ItemsControl, so the scenario described above isn't a problem in practice.

    However, the WeakEvent pattern APIs don't exist in Silverlight 2 and the scenario above actually is a problem for ItemsControl and its subclasses as well as the DataGrid, and Charting's Series classes (each of which has a non-ItemsControl-based ItemsSource property). The good news is that Silverlight intends to fix this problem for ItemsControl-derived classes as part of a future release. Unfortunately, that doesn't help Charting - and besides I'd like to help customers avoid this problem on the current release...

    So I got in touch with Silverlight developer Ivan Naranjo to see if his team had anything we could make use of and he kindly responded with something very much like the WeakEventListener class you see below. (For my part, I just tweaked things to address a few code- and source-analysis warnings and made a small change to avoid a possible area of confusion Ivan and I independently agreed on.) If you read Greg Schechter's post, the technique and implementation should look pretty familiar - WeakEventListener is a small, intermediary class that can be attached to an event so the resulting backwards reference affects only the extremely lightweight WeakEventListener and not the heavyweight class that created it. This avoids the costly "hidden" reference and allows the owning class to be garbage collected as soon as it is no longer in use. It was easy to add a WeakEventListener in Charting's Series.ItemsSource handler - and now our users don't have to worry about inadvertently leaking Chart instances!

    To show just how easy it is to use WeakEventListener, I created a sample project that you can download and experiment with as you read the rest of this post. Here's what it looks like:

    WeakEventListener Sample Application

    The sample application includes two custom controls: LeakyControl (which has a typical ItemsSource implementation) and FixedControl (which uses WeakEventListener). To see the problem and solution in action, start the application, click the "Check Status" button to verify both controls are present, then click "Remove From UI" to discard both controls. If you click "Check Status" again at this point, you'll see that both controls are still present - and that's expected because the garbage collector hasn't needed to run and so nothing has been done to clean up. Now click "Garbage Collect" and then "Check Status" again. You'll see that LeakyControl is still present, but FixedControl is gone. Yay, WeakEventListener works! :)

    Now, take things just a bit further and click "Clear ItemsSource", then "Garbage Collect", then "Check Status". We see that LeakyControl is gone as well! Why? Because by setting ItemsSource property of LeakyControl to null, we've explicitly told it we were done with the old collection and it knew enough to remove its event handler from that collection - thereby breaking the backwards reference and making itself eligible for clean-up during the next garbage collection. And, in fact, this is the workaround for controls that don't implement some form of the WeakEvent pattern and suffer from leaky behavior because of it: null-out the relevant property and hope they're kind enough to detach their event handlers in response. Depending on your application scenario, implementing this work around may be quite simple - or it may be almost impossible if your application has no way of knowing when some subcomponent has gotten into this situation - or no explicit knowledge of when affected controls are removed from the user interface. That's why it's nice when controls behave properly on their own - they work no matter what you do! :)

    For an idea of how an easy it is to make use of WeakEventListener in a control, here is the relevant (leaky) code from LeakyControl:

    // Change handler for the ItemsControl.ItemsSource-like DependencyProperty
    private void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        // See if the old value implements INotifyCollectionChanged
        var oldNotifyCollectionChanged = oldValue as INotifyCollectionChanged;
        if (null != oldNotifyCollectionChanged)
        {
            // It does; detach from the CollectionChanged event
            oldNotifyCollectionChanged.CollectionChanged -= OnCollectionChanged;
        }
        // See if the new value implements INotifyCollectionChanged
        var newNotifyCollectionChanged = newValue as INotifyCollectionChanged;
        if (null != newNotifyCollectionChanged)
        {
            // It does; attach to the CollectionChanged event
            newNotifyCollectionChanged.CollectionChanged += OnCollectionChanged;
        }
    }
    

    And here's what that same code looks like in FixedControl where WeakEventListener is used to avoid the backward reference problem:

    // Change handler for the ItemsControl.ItemsSource-like DependencyProperty
    private void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        // See if the old value implements INotifyCollectionChanged
        var oldNotifyCollectionChanged = oldValue as INotifyCollectionChanged;
        if (null != oldNotifyCollectionChanged)
        {
            // It does; detach our WeakEventListener and clear our reference
            _weakEventListener.Detach();
            _weakEventListener = null;
        }
        // See if the new value implements INotifyCollectionChanged
        var newNotifyCollectionChanged = newValue as INotifyCollectionChanged;
        if (null != newNotifyCollectionChanged)
        {
            // It does; create a WeakEventListener, attach us to it, and add it to the event
            _weakEventListener = new WeakEventListener<FixedControl, object, NotifyCollectionChangedEventArgs>(this);
            _weakEventListener.OnEventAction = (instance, source, eventArgs) =>
                instance.OnCollectionChanged(source, eventArgs);
            _weakEventListener.OnDetachAction = (weakEventListener) =>
                newNotifyCollectionChanged.CollectionChanged -= weakEventListener.OnEvent;
            newNotifyCollectionChanged.CollectionChanged += _weakEventListener.OnEvent;
        }
    }
    

    Note that the basic structure of the code is unchanged - there's just a bit more bookkeeping involved in creating and hooking up the WeakEventListener. The first thing to look at is the bottom half of the method where a new collection is handled - a WeakEventListener instance is created and a couple of properties are set. The OnEventAction property specifies a strongly-typed (thanks to WeakEventListener being generic!) function that gets called when the event is fired - this maps to whatever method would otherwise be used to handle the event. The OnDetachAction property specifies a strongly-typed function that gets called when the WeakEventListener is detached from the event it's listening to - it simply removes the WeakEventListener's handler for the event. (Note that this function takes a WeakEventListener parameter which should be used to unhook the event so as to prevent creating a closure that itself contains a hidden reference that could cause a leak. And if that last sentence makes no sense, don't worry about it - just follow the pattern shown here and you'll be fine.) Now that everything's in place, the WeakEventListener is attached to event of interest. Going back to the top half of the function, all that needs to be done is to manually detach the WeakEventListener from the event. The example also sets the WeakEventListener reference to null - but this is done for clarity and debugging convenience and not because it's necessary.

    That's all there is to it - WeakEventListener adds only a couple of lines of code and saves gobs of aggravation!

    Aside: People who prefer not to use anonymous methods like I've done here are welcome to write explicit methods to do the same thing. It's a few more lines of code and a tiny bit more work, but if you go that route, you can create static methods which almost guarantee you won't inadvertently create a leaky closure. Either way you do it, WeakEventListener works the same.

    Finally, here's the complete implementation of WeakEventListener for anyone who's curious how it works:

    /// <summary>
    /// Implements a weak event listener that allows the owner to be garbage
    /// collected if its only remaining link is an event handler.
    /// </summary>
    /// <typeparam name="TInstance">Type of instance listening for the event.</typeparam>
    /// <typeparam name="TSource">Type of source for the event.</typeparam>
    /// <typeparam name="TEventArgs">Type of event arguments for the event.</typeparam>
    internal class WeakEventListener<TInstance, TSource, TEventArgs> where TInstance : class
    {
        /// <summary>
        /// WeakReference to the instance listening for the event.
        /// </summary>
        private WeakReference _weakInstance;
    
        /// <summary>
        /// Gets or sets the method to call when the event fires.
        /// </summary>
        public Action<TInstance, TSource, TEventArgs> OnEventAction { get; set; }
    
        /// <summary>
        /// Gets or sets the method to call when detaching from the event.
        /// </summary>
        public Action<WeakEventListener<TInstance, TSource, TEventArgs>> OnDetachAction { get; set; }
    
        /// <summary>
        /// Initializes a new instances of the WeakEventListener class.
        /// </summary>
        /// <param name="instance">Instance subscribing to the event.</param>
        public WeakEventListener(TInstance instance)
        {
            if (null == instance)
            {
                throw new ArgumentNullException("instance");
            }
            _weakInstance = new WeakReference(instance);
        }
    
        /// <summary>
        /// Handler for the subscribed event calls OnEventAction to handle it.
        /// </summary>
        /// <param name="source">Event source.</param>
        /// <param name="eventArgs">Event arguments.</param>
        public void OnEvent(TSource source, TEventArgs eventArgs)
        {
            TInstance target = (TInstance)_weakInstance.Target;
            if (null != target)
            {
                // Call registered action
                if (null != OnEventAction)
                {
                    OnEventAction(target, source, eventArgs);
                }
            }
            else
            {
                // Detach from event
                Detach();
            }
        }
    
        /// <summary>
        /// Detaches from the subscribed event.
        /// </summary>
        public void Detach()
        {
            if (null != OnDetachAction)
            {
                OnDetachAction(this);
                OnDetachAction = null;
            }
        }
    }
    
  • Delay's Blog

    Proof-of-concept Silverlight XPS reader comes to Beta 2 [SimpleSilverlightXpsViewer sample updated for Silverlight 2 Beta 2!]

    • 25 Comments

    Earlier this week I was asked about an update to my SimpleSilverlightXpsViewer sample for the newly released Silverlight 2 Beta 2. (Background reading: Introductory Post, Beta 1 Update.) I spent a bit of time on this just now and migrating SimpleSilverlightXpsViewer to Beta 2 was very straightforward.

    SimpleSilverlightXpsViewer Application

    I've updated the SimpleSilverlightXpsViewer demonstration page and also the source code download, so you can try things out in your browser and/or download the code to see how it works!

    Notes:

    • A project reference to System.Net needed to be added in order for WebClient to resolve properly. (This is covered in the "Breaking Changes" document.)
    • DependencyObject.SetValue no longer seems to automatically convert the type of its value parameter, so there were three places I changed an int to a double for consistency with the underlying DependencyProperty type (ex: "0"->"0.0").
    • The "disappearing page border" issue that showed up in Beta 1 still seems to be present in Beta 2, so I worked around it by changing the "pageGraphic" from a Rectangle[Fill/Stroke] to a Border[BorderBrush]+Grid[Background]. A web search turned up a couple of customer reports of this behavior for Shapes (Path, Rectangle, etc.), so it should be fixed for the final release of Silverlight.
    • I discovered and fixed a bug with the math behind the zoom slider that could cause problems when the browser window was made very small. (This bug was unrelated to Beta 2.)

    SimpleSilverlightXpsViewer is a fun project that really seems to resonate with people; folks have told me all kinds of neat ideas they had while playing around with it. In fact, if all goes well, there just might be a cool, practical, relevant use of SimpleSilverlightXpsViewer that I'll be able to share sometime soon... :)

  • Delay's Blog

    Simple column labels you can create at home! [Re-Templating the Silverlight/WPF Data Visualization ColumnDataPoint to add annotations]

    • 24 Comments

    A customer contacted me over the weekend asking how to add labels (also known as annotations) to a ColumnSeries. My reply was that we don't support annotations in Silverlight/WPF Charting yet, but it's possible to create some pretty simple ones for limited scenarios just by editing the default ColumnDataPoint Template. And because it's so quick, I thought I'd write up a brief example on the bus!

    Aside: For some more examples of basic DataPoint Template changes, please have a look at my earlier post on customizing ToolTips.

     

    In this case, the customer wanted to add a label showing the column's value at the bottom of the column, just above its axis label. (This is a nice place to put labels because it makes it easy for viewers to associate the category with its value no matter how high each column is.) The obvious approach is to add a TextBlock to the body of the default Template, but the problem with that is that the text can get clipped or even disappear for small columns... So the trick is to add a negative Margin to pull the text "outside" the normal clipping region. Fortune must have been smiling upon me, because when I tried this on Silverlight, it worked just like I wanted! :)

    Aside: My other idea was to use a Canvas because it doesn't clip by default; maybe someone else will need to use that approach for their scenario.

     

    Here's how the resulting chart looks:

    Simple column annotations (on bottom)

    The XAML's nothing special - aside from the negative Margin, it's all standard stuff:

    <charting:Chart
        Title="Simple Column Annotations - Bottom">
        <charting:ColumnSeries
            DependentValuePath="Value"
            IndependentValuePath="Key"
            ItemsSource="{Binding}">
            <charting:ColumnSeries.DataPointStyle>
                <Style TargetType="charting:ColumnDataPoint">
                    <Setter Property="Background" Value="Yellow"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="charting:ColumnDataPoint">
                                <Grid>
                                    <Rectangle
                                        Fill="{TemplateBinding Background}"
                                        Stroke="Black"/>
                                    <Grid
                                        Background="#aaffffff"
                                        Margin="0 -20 0 0"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Bottom">
                                        <TextBlock
                                            Text="{TemplateBinding FormattedDependentValue}"
                                            FontWeight="Bold"
                                            Margin="2"/>
                                    </Grid>
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </charting:ColumnSeries.DataPointStyle>
        </charting:ColumnSeries>
    </charting:Chart>
    

     

    Just for fun, I thought I'd try the same trick to put the annotations on top of the columns, too. This is the more traditional location - and that also works pretty nicely:

    Simple column annotations (on top)

    The only change from the previous XAML is switching the VerticalAlignment to Top:

    <Grid
        Background="#aaffffff"
        Margin="0 -20 0 0"
        HorizontalAlignment="Center"
        VerticalAlignment="Top">
        <TextBlock
            Text="{TemplateBinding FormattedDependentValue}"
            FontWeight="Bold"
            Margin="2"/>
    </Grid>
    

     

    And there you have it - a simple technique for simple column annotations!

    Aside: Of course, these aren't "real" annotations - they'll eventually break in more complicated scenarios. But hey, if you've got simple needs, here's a simple solution for you. :)

     

    PS - For people playing along at home, here's how I created the data for the samples:

    public MainPage()
    {
        InitializeComponent();
        var items = new List<KeyValuePair<string, double>>();
        items.Add(new KeyValuePair<string,double>("Apples", 0));
        items.Add(new KeyValuePair<string,double>("Oranges", 0.1));
        items.Add(new KeyValuePair<string,double>("Pears", 1));
        DataContext = items;
    }
    
  • 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.

Page 3 of 28 (277 items) 12345»