Welcome to MSDN Blogs Sign in | Join | Help

We came across an interesting problem a customer hit when trying to write a custom control. The issue was that although the control appeared to work correctly in the application, when it came time to do out-of-process testing using UI Automation (UIA), the newly added functionality of the custom control wasn’t being exposed, and therefore couldn’t be tested. In this post, I’ll explain a little what the problem is, and offer a possible solution.

First, kudos to the customer for taking the time to test the custom control, and realizing there was an issue to begin with. This is a good example of why it's important to do software testing and verify assumptions, as although things seem to “just work”, that’s not always the case.

The custom control in question is a modified tab control, with a Header property that allows you to specify content in addition to the usual tab items. This is a little similar to the concept of a HeaderedContentControl, and the markup would look like this:

   <local:CustomTabControl Style="{StaticResource TabControlStyle}">
      <local:CustomTabControl.Header>
         <!-- Any content can go here -->
         <Button Content="Header Button" />
      </local:CustomTabControl.Header>
      <local:CustomTabControl.Items>
         <TabItem Header="Tab 1" />
         <TabItem Header="Tab 2" />
      </local:CustomTabControl.Items>
   </local:CustomTabControl>

As you may have guessed, the problem is that although the custom tab control exposed the tab items properly to UIA, it didn’t also expose the Header content. Is this expected? Yes, because controls in WPF are responsible for exposing their UIA items themselves.

This is done through the AutomationPeer class. All the major control classes in WPF, such as TabControl, have a corresponding AutomationPeer class that exposes the control’s functionality to UIA, creatively named TabControlAutomationPeer in this case. This is explained in some detail in this MSDN page.

When a UIA client looks at the structure of the application, WPF will raise the OnCreateAutomationPeer event on elements in the WPF application tree. In the case of a regular TabControl, when the event is raised, a TabControlAutomationPeer instance is created. If you write a custom control but don’t handle this event, the behavior of the base class your control derives from is the behavior that will be exposed to UIA. Since TabControlAutomationPeer doesn’t know about the newly added Header property in CustomTabControl, it doesn’t expose it to UIA.

Now that the problem is clearer, lets focus on a solution. In order for CustomTabControl to behave as expected, you would need to create its CustomTabControlAutomationPeer counterpart. Since we’re only adding one property to TabControl, we can derive from TabControlAutomationPeer and reuse most of the base class functionality:

 

   public class CustomTabControlAutomationPeer : TabControlAutomationPeer
   {
      public CustomTabControlAutomationPeer(TabControl owner)
         : base(owner)
      {
      }
      
      protected override string GetClassNameCore()
      {
         return "CustomTabControl";
      }
      
      protected override List<AutomationPeer> GetChildrenCore()
      {
         List<AutomationPeer> automationPeers = base.GetChildrenCore();
         CustomTabControl owner = base.Owner as CustomTabControl;
         if (owner != null)
         {
            UIElement headerUIElement = owner.Header as UIElement;
            if (headerUIElement != null)
            {
               AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(headerUIElement);
               if (peer != null)
               {
                  automationPeers.Add(peer);
               }
            }
         }
      
         return automationPeers;
      }
   }
The CustomTabControl now needs to create an instance of the new CustomTabControlAutomationPeer:

 

   public class CustomTabControl : TabControl
   {
      ...
      protected override AutomationPeer OnCreateAutomationPeer()
      {
         return new CustomTabControlAutomationPeer(this);
      }
   }

If you launch a UIA tool like UI Spy (great tool which is available in the .Net Framework SDK), this is what you would see before the change, with a view scoped to the custom tab control:

This is what you can see after the change, with the Header button properly exposed:

So is that all we need? Actually, no. There is an issue with the solution I have described so far. What happens if the content of the Header property is changed to something else? At the moment, nothing from a UIA perspective. Because UIA doesn’t keep track of changes, and because you didn’t notify it of any changes, the image you see above would remain the same, and it would incorrectly believe the Header content is the same.

To solve this, you need to find a way to notify UIA of the change. Luckily, WPF makes this fairly straightforward when using a DependencyProperty, which is how you would expose a Header property in the custom control. When you declare the property, you can specify a PropertyChanged handler for the Header which would look like this:

   public class CustomTabControl : TabControl
   {
      ...
      public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(CustomTabControl),
         new FrameworkPropertyMetadata(OnPropertyChanged));
      private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
         CustomTabControl tabControl = d as CustomTabControl;
         if (tabControl != null && (e.OldValue != e.NewValue))
         {
            if (AutomationPeer.ListenerExists(AutomationEvents.StructureChanged))
            {
               // Notify the UI automation client that the content changed
               TabControlAutomationPeer peer = UIElementAutomationPeer.FromElement(tabControl) as TabControlAutomationPeer;
               if (peer != null)
               {
                  peer.RaiseAutomationEvent(AutomationEvents.StructureChanged);
               }
            }
         }
      }
   }

When the Header content changes, this raises an event which lets UIA know it needs to perform an update. A VS 2008 sample with all the code in this post can be found below, and hope you found this useful!

Thought I’d share an interesting (albeit rather old) series of blog posts on how to write scrollable custom panels.

The set of 4 posts walk through how to write a simple panel that implements part of the IScrollInfo interface, which is needed to allow the ScrollViewer control to delegate the responsibility of scrolling.

Part 1, Part 2, Part 3, Part 4

A new version of the TestAPI library has just been released. The new release contains fault injection APIs, combinatorial variation generation APIs and application control APIs.

We encourage you to try it out and give us your feedback! You can find the latest release of the TestAPI library here.

It’s been a while since my last update. I’ve been busy working on a new WPF Model-View-ViewModel toolkit, which you can find on the Codeplex WPF Futures site.

The template is meant to introduce the Model-View-ViewModel (M-V-VM) design pattern to the WPF community. It includes:

  • A Visual Studio 2008 template (Visual C# Express 2008 also supported)
  • Documentation
    • General introduction to M-V-VM
    • Walkthrough using the VS template
  • A complete WPF application demonstrating the MVVM pattern

We hope you find it useful. Feel free to try it out and share your comments/suggestions!

Silverlight 3.0 Beta was unveiled at Mix09 yesterday, along with a preview of Expression Blend 3.0.

The list of new features being released in the products is nothing short of impressive. This article at Wired Magazine does a good job of going through the main features, but if you’re short on time, the highlights are as follows:

Silverlight:

  • HD Streaming of 720p without buffering
  • Standalone application support (aka out of browser!)
  • Hardware acceleration
  • 3D visual features
  • Multi-touch support
  • Eclipse for Silverlight support on the Mac

Expression Blend:

  • Sketchflow feature allows for quick prototyping of workflow by defining states and transitions between states
  • Import files directly from Adobe Illustrator/Photoshop
  • Export workflow to an automatically generated Word document

If you’ve been holding off trying out Silverlight, this seems like a great time to take a closer look!

I was recently taking a look at the apps thirteen23 has been working on. The company specializes in designing and developing rich applications, primarily focused around .Net, whether it be for desktop, touch or mobile devices.

While perusing the experiences they offer, I stumbled on Drama. In short, it’s a desktop application that allows you to search and view Netflix movies. You can sign into your account, giving you access to your personalized queue, and allowing you to you re-organize it using intuitive drag & drop. You can also watch movies available for instant viewing.

Aside from the fact it’s visually stunning, I particularly liked the fact the app does a great job of seamlessly integrating with the publicly available Netflix API, resulting in a truly compelling desktop experience.

It goes to show that even if a company is primarily known for its web presence, there’s nothing preventing it from also getting a branded desktop presence. If you were to include a few premium features that can be done on the desktop but difficult to do in a web browser (multiple windows, minimizing, disk access, etc.), you could potentially increase the amount of time users spend actively interacting with your services. If you include some well-placed context-aware advertising (new movie releases in a theater near you, for example), you might even be generating a new revenue stream.

Wouldn’t it be nice to have a clean, well-designed Facebook app without having to use a web browser?

At one point or another, you run in the situation where you need to debug an application that makes use of optimized binaries, as is the case with WPF binaries.

Although you have the right symbols, and even have source code (through Source Server or other means), you can't see values in Visual Studio, which frustratingly reports that them as "unavailable".

Shawn Burke posted a great blog entry that explains, step by step, how to work around the issue. I hope it proves useful to others!

As part of our effort to make it easier to test applications, we would like to share some of the test technology we use internally on the WPF team with the community.

We are making a library available, and although this first release is fairly small, it can already provide value to existing applications. New features will be added in no small part based on the feedback we receive from the community!

Some of the current APIs in the library include:

  • Command Line Parsing: Arguments are parsed and can be strongly typed
  • Visual Verification: Screenshot comparison
  • WPF Dispatcher Helper: Manage the dispatcher queue to make testing more predictable
  • Input Helpers: Keyboard, Mouse input APIs
  • Accessibility Helpers

The project is called TestApi. Binaries, source code and samples were released on CodePlex at http://codeplex.com/TestApi.

One of the many announcements made at the PDC was that Visual Studio 10 will be built on top of WPF. In addition, VS will be using MEF as an extensibility mechanism. I just wanted to take a few minutes to explain what MEF is all about.

The Managed Extensibility Framework (MEF) is a library that makes it easy to develop reusable components. The framework provides a standard way for a host application to discover, expose and consume component extensions without the need for each of them to be coupled together.

At the heart of MEF is a ComposablePart, which exposes services or consumes externally provided services. This is done using a Contract, which can be as simple as adding an Import (to consume) or Export (to expose) attribute.

Although MEF is still in development, it already provides a number of key benefits, and would be worth a look if you are, or plan on working on extensible applications. Full source and documentation can be found on CodePlex. It also includes samples, but if there’s interest I’ll add a sample on my blog as a step-by-step walk through.

Silverlight 2.0 has been released, and you can install it here. The link will work for both PC and Mac versions.

If you had any doubts about Silverlight, I highly recommend you check out the Hard Rock Memorabilia site. The user experience and performance are both extremely impressive!

You can find more info about Silverlight at www.microsoft.com/silverlight.

In case you haven't heard, the .Net FX 3.5 Service Pack 1 and VS 2008 Service Pack 1 have been released! The VS 2008 Express Edition with SP1 is also available here.

In addition to providing bug fixes, the update also includes a number of new WPF features. One of these is the .Net Client Profile, which improves the setup experience of client applications in both speed of installation and size of the redistributable, reduced from 197 MB to 26.5 MB.

You can read more about the SP1 update on Somasegar's blog.

If you ever debug WPF elements or use the QuickWatch feature in VS, I suggest you try out Mole. It’s a visualizer similar to Snoop, allowing you to view the visual/logical trees, as well as an extended set of properties, directly from VS.

I was particularly impressed by the number of cool features, such as being able to add “favorite” properties to debug (always annoying in VS to have to scroll) or being able to dynamically view a collection’s items in a data grid. You can also get a visual representation of the element you're debugging, as well as its Xaml. It is also reported to work with XBAPs, although I haven’t tried that.

Install:

  • For X64: Copy the assembly to %ProgramFiles(x86)%\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers
  • For X86: Copy the assembly to %ProgramFiles%\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers

Usage:

After setting a breakpoint near a WPF element, you should be able to highlight the object and click on the magnifying lens icon. To make this easier, you can temporarily add a PreviewMouseLeftButtonDown event to your top-most window and Ctrl-Click an item.

You can find videos and more documentation here.

Screenshot:

Mole

If you are trying to write an application in WPF that separates the UI from the underlying business logic (otherwise known as Model-View patterns), you may have noticed that some of the features in WPF don't always make that easy.

Commands are an example of this. Although defining and using a command in Xaml is fairly straightforward, you are currently pushed to declare the handlers that do the work in the code-behind, going against the mantra of separation, and making harder to get some of the benefits of encapsulation.

There's a few options you might consider:

  • Command Binding in Xaml, Handlers in code-behind: By implement the business logic somewhere else than your view, you can always re-direct to it in the code-behind methods. (Simplest)
  • Command Binding in Code-Behind: Creating the binding through code allows you to avoid having to implement handlers in code-behind. An example of how to do that can be found on Richard Griffin's blog. (Less Declarative)
  • Command Binding in Xaml using Attached Properties: The idea is to use an attached property in Xaml to create the command binding. I'll give credit to Dan Crevier for coming up with the idea, which you can read in more detail here. (Harder)

 

Another option I didn't list above is using the WPF Composite Application Library (CAL), which has support for Delegate Commands. It's somewhat more heavy-weight, primarily geared towards enterprise application development, so I'll likely create a separate post on the topic.

It's been a while since my last post, so I figured I'd write something I just recently had to work on: user settings.

In many client applications, you quickly run into the need to store application or user settings. There are a few options on how to do that, some of which are more complex than others, and I'll provide links at the end on a other options I found. In this post, I'll describe one of the simpler solutions, which takes advantage of existing functionality in Visual Studio, makes use of data-binding in Xaml, and also allows you to retrieve or set settings through code.

Visual Studio has design-time support for application and user settings, described quite well in the MSDN documentation. The VS designer creates as Settings class and automatically generates properties based on the setting names. Moreover, the settings will work in a ClickOnce application. As for the limitations mentioned in the article, I would add that design-time implies you need to know the user settings ahead of time. Not usually a big problem, but it can be for more complex scenarios. For example, if your application supports plug-ins that have custom settings, you wouldn't necessarily know this ahead of time.

Assuming you’ve already created settings for your application, how could you go about making use of them in a WPF application? In order to access the properties in Xaml, you could add an entry in the application's resource dictionary:

<Application x:Class="SampleApp.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:properties="clr-namespace:SampleApp.Properties"
   Exit="OnExit"
   StartupUri="MainWindow.xaml">
     <Application.Resources>
         <properties:Settings x:Key="Settings" />
     </Application.Resources>
</Application>

If you had added a setting named Username as a string type, you could bind a TextBox in Xaml this way:

<TextBox Text="{Binding Source={StaticResource Settings}, Path=Default.Username}" />

As you enter text in the TextBox, the two-way binding automatically updates the Username setting, and similarly at startup, the TextBox will be populated with the most recently saved Username value.

Finally, in order to ensure your settings are properly saved, you could implement the OnExit handler declared above, or alternatively you could put the settings in a dedicated window and save at the appropriate time.

private void OnExit(object sender, ExitEventArgs e)
{
    Properties.Settings.Default.Save();

}

To access the current property value through code:

Properties.Settings.Default[“Username”]

Now, for the additional links I promised. This article offers a more complex and complete solution. Although it’s relatively heavy-weight, it adds support for specific WPF controls, such as saving column positions in a ListView.

One of the questions we frequently get when meeting with customers is whether or not to adopt WPF over WinForms, Win32 or some other technology. As much as I'd love to have the answer always be "of course!", the reality is that it depends on a number of factors that need to be taken in consideration.

This technical article by Peter Faraday and Brad Becker outlines well some of the benefits and tradeoffs. In addition, I would consider the following:

  • Length of Project: Although we've tried to make WPF easy to use, as with any new technology there is a learning curve, which can be problematic if the schedule doesn't leave much room for it or if you can't afford to train developers to use WPF.
  • Project Lifespan: Are you planning on using this project, and its associated technology, for an indefinite period of time? Or is the project near it's end of life, only requiring an incremental improvement?
  • Goals of Project: Are you planning on providing an improved user experience for your application, or are you planning on extending existing functionality provided by your custom control? You could decide to use WPF for the application chrome, yet continue using the existing technology for custom components that would be too expensive to re-write.
  • Scope of WPF Use: Using some of the interop features of WPF, it's possible to make use of other technologies in conjunction with WPF. For example, you can use WinForms in WPF (WinFormsHost), WPF in WinForms (ElementHost), Win32 in WPF (HWndHost) or WPF in Win32 (HwndSource).
  • 3rd Party Components: The application might depend on components that can't be updated, in which case it might not be as easy to transition to WPF.

In addition, a few additional points have come up:

  • High DPI: WPF applications are DPI aware, meaning WPF is resolution independent and will scale if DPI settings are changed. This blog entry describes this in good detail.
  • System Fonts: This is particularly important for companies that rely on system fonts to provide a consistent experience, as well as companies that have accessibility requirements such as High Contrast. WPF does use system font settings for the default theme, that is unless you override these settings by using a custom style/skin/theme that does not make use of system fonts.
  • Accessibility: WPF has support for the latest UI automation technology (UIA), which works well with the screen reader and magnifier included with the OS. Although UIA does have backwards compatibility with its predecessor (MSAA), many 3rd party screen readers and magnifiers are still MSAA based and don't directly support UIA at this particular time, but some have indicated they are working on adding UIA support going forward.
  • Globalization/Localization: This is possible using WPF. Rob Relyea posted this blog entry on the topic.
More Posts Next page »
 
Page view tracker