Delay's Blog

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

July, 2010

Posts
  • Delay's Blog

    Banana SplitButton [A WPF-specific fix for SplitButton and some code analysis improvements for the Silverlight version, too]

    • 20 Comments

    I've previously written that one of my ContextMenu test cases for the April '10 release of the Silverlight Toolkit was to implement a quick "split button" control for Silverlight using Button and ContextMenu. Though it wasn't my goal to build a general-purpose control for widespread use, there's been a lot of interest in SplitButton/MenuButton and I followed up with a few fixes for the Silverlight version and "official" support for WPF.

     

    SplitButton and MenuButton

     

    That might have been the end of the story - until Fabio Buscaroli contacted me to report an issue he was seeing with the WPF version (follow our exchange here). At first, I thought the problem was related to the DataContext not inheriting properly - and while that was true, it wasn't the whole story! When Fabio told me the tweak for DataContext I'd suggested didn't solve his RoutedCommand scenario, I had a look at a simple example he posted and realized the DataContext problem was a symptom of a larger issue: that the ContextMenu wasn't a logical child of the SplitButton. As soon as I solved that problem, it fixed Fabio's scenario and the related DataContext issue I'd discovered during my own investigation.

    Aside: None of this applies to Silverlight because that platform doesn't expose the notion of a logical tree the way WPF does.

     

    While I was working on this fix, I noticed full code analysis wasn't enabled for the SplitButton assemblies; I turned it on and addressed the handful of warnings it generated. Most of the changes won't matter to you, but one of them will: the namespace for SplitButton/MenuButton has changed. These classes now live in the Delay namespace - which is consistent with the rest of the sample code I post to my blog. Upgrading existing projects to the latest code will require a tweak of the XAML's "xmlns:" prefix and/or a tweak of the code's "using" statements. Otherwise, there have been no behavior changes to the functionality of SplitButton on Silverlight or WPF, so everything else should continue to work the same as before.

     

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

     

    It's been great to see the positive response SplitButton and MenuButton have generated. Thanks for everyone's help trying these controls out, finding issues, and reporting them!

  • Delay's Blog

    Hopping outside the box [How to: Leapfrog Bindings (bridge DataContexts) in Silverlight and WPF]

    • 9 Comments

    The data binding infrastructure for Silverlight and WPF is extremely powerful and makes it easy to write powerful, dynamic applications without worrying about synchronizing the UI with every change to the underlying data. By leveraging this power, developers can think entirely in terms of the data model and be confident that any changes they make will be reflected by the interface automatically.

    The way this works is that every element has a DataContext property, and the value of that property is inherited. DataContext can be assigned any object and acts as the default source for all Bindings applied to the element's properties. The object acting as DataContext can be as simple or complex as an application needs and is free to "shape" the data however is most convenient for the UI and Bindings. Collection-based controls like ItemsControl (and its subclasses ListBox, TreeView, etc.) automatically set the DataContext of their containers to the specific item they represent. This is what you'd expect and enables a great deal of flexibility when displaying collections. However, each element has a only one DataContext - so sometimes it's useful to "reach outside" that and bind to properties on some other object.

    The good news is that there's an easy way to leapfrog the DataContext and "bridge" the two elements! The trick is to use an ElementName Binding to point to that other element - then to root the Binding's Path at that element's DataContext and "dot-down" to the property of interest. An example should make things clearer...

     

    LeapFroggingDataContexts sample

    The sample above has an application-wide DataContext model object ApplicationViewModel containing a bool property ShowHeight that's TwoWay-bound to the CheckBox control. For convenience, ShowHeight is also exposed as a Visibility value via HeightVisibility - which is much more convenient to bind the Visibility property to. There's also a Mountains property containing a collection of MountainViewModel model objects. Each mountain in the list is meant to show or hide its height according to the setting on ApplicationViewModel - but because the DataContext of the ListBoxItem containers is set to instances of MountainViewModel, they can't "see" the HeightVisibility property... The most direct option is probably to propagate this value "down" to the MountainViewModel instances by adding a property to the class for that purpose and keeping it in sync with the "real" property on ApplicationViewModel.

    However, that feels like a bit of overkill for the current situation. Instead, if we just "leapfrog" the Binding in the item content, we can make use of the ApplicationViewModel directly and everything stays nice and simple!

     

    [Click here to download the Silverlight 4 source code for the LeapFroggingDataContexts sample.]

     

    Here's what it looks like in XAML:

    <UserControl x:Class="LeapFroggingDataContexts.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:LeapFroggingDataContexts">
    
        <UserControl.Resources>
            <local:ApplicationViewModel x:Key="ApplicationViewModel"/>
        </UserControl.Resources>
    
        <Grid
            x:Name="LayoutRoot"
            DataContext="{StaticResource ApplicationViewModel}"
            Width="150"
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
    
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition/>
            </Grid.RowDefinitions>
    
            <CheckBox
                Grid.Row="0"
                Content="Show height"
                IsChecked="{Binding ShowHeight, Mode=TwoWay}"/>
    
            <ListBox
                Grid.Row="1"
                ItemsSource="{Binding Mountains}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Name}"/>
                            <TextBlock
                                Text="{Binding Height, StringFormat=' [{0:n0}m]'}"
                                Visibility="{Binding DataContext.HeightVisibility, ElementName=LayoutRoot}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </UserControl>

    ElementName points the Binding at an element with the DataContext of interest, then the Path selects the DataContext as a starting point (an instance of the ApplicationViewModel class in this case), hooks up to that object's HeightVisibility property - and we're done!

     

    While architectural purists might argue this technique is bad form, I've seen it come in handy for enough customer scenarios that it seems a worthwhile approach to keep in mind. Please don't abuse it - but feel free to use it! :)

  • Delay's Blog

    Spin Spin Sugar [Updated code to easily animate orientation changes for any Windows Phone application]

    • 8 Comments

    A few weeks after the initial release of the Windows Phone Developer Tools in April, I blogged a sample showing how to easily animate device orientation changes for Windows Phone 7 applications. I noted at the time that the default behavior for application projects is no animation - the app immediately switches to the new orientation when the device is rotated (click here for a brief video of the default behavior). While this is clearly the simplest approach, I wanted to enable something a little fancier by smoothly animating the application's rotation from one orientation to another - just like the built-in applications do.

    To show what I'm talking about, here's a video of my implementation running on the emulator:

    Video of animated orientation change behavior

    FYI: The buttons in the video rotate the device one quarter turn clockwise or counter-clockwise. I begin by rotating counter-clockwise once, then clockwise once back to the starting orientation, then clockwise three more times to loop all the way around. And then show off just a bit. :)

    Note: I made that video back in April; the emulator looks a little different now, but the animation works just the same.

     

    As of yesterday's release of the Windows Phone Developer Tools Beta, some of the platform changes have invalidated my original implementation. But that's okay, because I've updated the code to work with the latest release - and made a few improvements along the way! :)

     

    [Click here to download the AnimateOrientationChanges sample for Windows Phone 7.]

     

    Notes:

    • [Please review the "Notes" section of my previous blog post for additional information.]
    • The implementation is now based off PhoneApplicationFrame which simplifies things a bit by avoiding the need to track state across pages. Conveniently, this also makes the setup process a bit easier. What's more, I was able to get rid of the TranslateTransform based on a suggestion by Seema Ramchandani, one of the Silverlight performance experts. And I've added a bit of code to avoid unnecessary calls to InvalidateArrange which helps free up a few extra CPU cycles.
    • One of my earlier concerns was that I hadn't been able to run code on actual Windows Phone hardware, so I wasn't sure the snappy performance I saw under the emulator carried over to the device. Fortunately, I've gotten access to an actual prototype and have verified the sample application runs quite smoothly in the real world, thank you very much. :)
    • That said, my sample is pretty simple - Seema expressed concern about possible slowness for the more complex layouts real applications might use. And while I share her concerns, the options for improving the situation in such cases all seem like they'll degrade the visual quality of the rotation animation. The current implementation gives the best quality it can on any device for any layout (and automatically degrades as necessary to catch up if it falls behind); the alternatives create animations that just won't be as smooth. :( So I'm reluctant to start down that path until I know it's necessary. Please let me know what your experience is - whether good or bad - so I can make an informed decision!
    • Here are the complete directions for adding rotation animation to a new application (if you're upgrading an existing application, please undo all the previous install steps first!):
      1. Enable support for orientation changes by making the following change to the XAML for the relevant PhoneApplicationPages (note that rotation is no longer enabled by default for new pages):
        SupportedOrientations="Portrait"
        SupportedOrientations="PortraitOrLandscape"
      2. Verify (by running in the emulator) the pages you expect to support rotation really do - if things aren't rotating at this point, trying to animate the rotations won't help. :)
      3. Add the AnimateOrientationChangesFrame.cs code file from the sample to your project/solution.
      4. Open App.xaml.cs and change the RootFrame initialization in the InitializePhoneApplication method (you may need to expand the Phone application initialization region at the bottom):
        RootFrame = new PhoneApplicationFrame();
        RootFrame = new Delay.AnimateOrientationChangesFrame();
      5. Done; rotations will now be animated! To customize the animation, use the Duration, EasingFunction, and IsAnimationEnabled properties which are all still present and continue to work as outlined in the previous post.
    • The phone emulator has an annoying bug where it frequently fails to notify applications about an orientation change that just happened. This problem has nothing to do with my code (you can reproduce it by enabling rotation for any application), but shows up regularly when playing around with the sample app in the emulator. When the orientation gets "stuck" like that, just rotate a few more times and things sort themselves out. (Fortunately, this problem does not exist on actual phone hardware!)
    • The PageOrientation.PortraitDown value remains unsupported with this release because the platform still does not support it.

     

    On the one hand, animating orientation changes is kind of a whimsical behavior to add to an application - but on the other hand, it helps to create the kind of pleasing, platform-consistent experience that users appreciate and enjoy. AnimateOrientationChangesFrame isn't going to turn a crummy application into a good one - but it just might add some polish to help turn a good application into a great one.

    I've had fun creating this sample - I hope you enjoy using it!

  • Delay's Blog

    New phone bits, same pretty charts [Upgraded my Windows Phone 7 Charting example for the Windows Phone Developer Tools Beta]

    • 5 Comments

    The recent release of the Windows Phone Developer Tools Beta introduces a variety of notable changes to the Windows Phone platform and I've been meaning to update my Data Visualization on Windows Phone sample so I could continue to refer people to it for educational purposes. (Just like I did when the April Tools Refresh came out.) I finally got some time and have updated the sample so it targets the Beta Tools and works "out of the box".

     

    Sample in portrait orientation Sample in landscape orientation

     

    [Click here to download the updated Windows Phone 7 Data Visualization sample application.]

     

    Rather than relying on an automated project upgrade, I simply diff-ed the existing project against a new project I created width the Beta Tools and made the necessary changes myself in Notepad. It was all pretty straightforward - here are the things that stood out for me:

    • App.xaml.cs: There's a lot more initialization code by default.
    • App.xaml: There's no longer a need to bake all those phone-specific styles into every application, so the default App.xaml is nearly empty (like it should be)! Also, the new PhoneApplicationService events are hooked up by default.
    • SplashScreenImage.jpg: An appropriately-named splash screen is now created and used automatically.
    • MainPage.xaml: The platform-specific Phone* assemblies and default namespaces have shifted around a bit. SupportedOrientations is now set in XAML instead of code.
    • DataVisualizationOnWindowsPhone.csproj: The WINDOWS_PHONE symbol is now #define-ed by default, giving shared code now a standard way of detecting the Windows Phone platform. The phone assembly references are slightly different and the splash screen is included by default.
    • WMAppManifest.xml: The property PlaceHolderString on the DefaultTask element has been renamed.

    While I was at it, I also tweaked the way the data source is created (by making it a class and moving it to the Resources section) so now the charts show up at design-time, too. I'm using the exact same System.Windows.Controls.DataVisualization.Toolkit.dll and System.Windows.Controls.dll assemblies as before (see notes 4 and 5 of the previous post for more context) - though there should no longer be a need to "un-sign" the Silverlight Toolkit assembly to use it on Windows Phone.

     

    This was all pretty basic stuff and it's important to note that none of the application code was affected. Changes like this are a natural part of the platform and project templates maturing - and it's great to see improvements like the default styles moving into the platform!

  • Delay's Blog

    If they build it, I will come (and link to it) [WPPFormatter plug-in now available for TextAnalysisTool.NET]

    I went public with TextAnalysisTool.NET a few years back - it's a handy tool for interactive log file analysis that's popular with people in many parts of the company. The introductory post has more background and detail, but this snippet from the README gives an overview:

    The Problem: For those times when you have to analyze a large amount of textual data, picking out the relevant line(s) of interest can be quite difficult. Standard text editors usually provide a generic "find" function, but the limitations of that simple approach quickly become apparent (e.g., when it is necessary to compare two or more widely separated lines). Some more sophisticated editors do better by allowing you to "bookmark" lines of interest; this can be a big help, but is often not enough.

    The Solution: TextAnalysisTool.NET - a program designed from the start to excel at viewing, searching, and navigating large files quickly and efficiently. TextAnalysisTool.NET provides a view of the file that you can easily manipulate (through the use of various filters) to display exactly the information you need - as you need it.

    And here's an animated GIF showing TextAnalysisTool.NET working with some MSBuild output:

    TextAnalysisTool.NET demonstration

     

    I don't talk about it in the introductory post, but one of the things TextAnalysisTool.NET supports is a flexible plug-in architecture for handling custom file formats. Here's what the included documentation says:

    TextAnalysisTool.NET's support for plug-ins allows users to add in their own code that understands specialized file types. Every time a file is opened, each plug-in is given a chance to take responsibility for parsing that file. When a plug-in takes responsibility for parsing a file, it becomes that plug-in's job to produce a textual representation of the file for display in the usual line display. If no plug-in supports a particular file, then it gets opened using TextAnalysisTool.NET's default parser (which displays the file's contents directly). One example of what a plug-in could do is read a binary file format and produce meaningful textual output from it (e.g., if the file is compressed or encrypted). Another plug-in might add support for the .zip format and display a list of the files within the archive. A particularly ambitious plug-in might translate text files from one language to another. The possibilities are endless!

     

    Over the years, I've been contacted by various people wanting to use the plug-in architecture to add support for specialized file formats. One of those people is Tomer Rotstein who recently released a WPPFormatter plug-in. (If the acronym "WPP" isn't familiar to you, you might start by reading the Windows software trace preprocessor entry on Wikipedia - it's the file format used by the event tracing infrastructure in Windows.) But Tomer has gone above and beyond what I ever had in mind - as you can see from the following screen shot of WPPFormatter's "open file" dialog:

    WPPFormatter demonstration

    I encourage people to read Tomer's post to get a full sense of what WPPFormatter does. There's a download link at the end of that post, so please try it out if it seems useful!

     

    And for those of you who aren't already TextAnalisisTool.NET users, please:

    [Click here to download the latest version of TextAnalysisTool.NET.]

     

    Aside: Tomer's accomplishment is even more notable when you realize that TextAnalysisTool.NET was the first .NET application I ever wrote and that it targets .NET 1.1 - from a time before there were generics, extensibility frameworks, and all the other goodness we've come to take for granted! Truth be told, the plug-in model for TextAnalysisTool.NET is downright wacky in some ways, so I congratulate Tomer on succeeding in spite of my goofy design. :)
Page 1 of 1 (5 items)