Writing extension for WPF custom control

Ever since I wrote extensibility series on Coded UI Test, I have been getting lot of good feedback via questions and comments. One learning that I got from this is there are folks out there wanting to use the extensibility and are not able to easily do so. We need to simplify the extensibility interfaces in the future release.

Based on the questions from various folks, I saw two common usage patterns for extensibility.  The first one is –

  • User has custom WPF control with good accessibility.  User wants to support it as rich control with good recording, playback and properties for validation and not as default of WpfControl.

In this blog, I will cover this scenario with a specific example.  Overall, the extensibility points for this scenario are same as the one mentioned in previous extensibility series and going through the earlier series is pre-requisite.

So, what is special about custom WPF control? The answer is WPF has windowless controls i.e. only some controls like “Window” control has actual window handle and other controls like “Button” or “ListBox” are all natively painted without their own window handle. This is not the case with Win32 technologies like Windows Forms or MFC where most control have their own window handle.  So, how does this matter? The reason this matter is one of the central method in Coded UI Test extensibility story is UITechnologyManager.GetControlSupportLevel() which takes a window handle as an input.  This means the technology manager has to handle complete window; users don’t want to do this – they want to just handle their custom control which is there in the window along with other controls.  Well, the solution for this is to aggregate (as in COM sense) the default WPF technology manager in the custom control technology manager and delegate calls as appropriate to WPF technology manager.

Attached is the sample.  The sample has 3 parts –

  1. Application – This is sample application that includes a custom control.  The custom control here is NumericUpDown control (on lines of Windows Forms NumericUpDown). The control consists of a TextBox and two RepeatButton. The application and the control is just a sample for this illustration (given my limited proficiency with WPF).
  2. Extension – This is actual extension that has technology manager and property providers to support the above custom control as rich WpfNumericUpDown control with well defined properties and richer intent recording. This is further explained below.
  3. Test – This is sample test project showing how playback\validation for this custom control is same as any other control. For recording, you can play with the control.

The Application and Test part of the solution are straight forward and I am not going to explain those any further.  To install and play with the extension, follow the steps mentioned in the series here. In addition, you will need to put the Sample.UITest.WpfNumericUpDown.Extension.dll in the GAC.

In the Extension, we have following files –

  • NudExtensionPackage – The extension package returns NudTechnologyManager as the technology manager and WrappedPropertyProvider & NudPropertyProvider as property providers.
  • NudTechnologyManager – This is the technology manager that is wrapping the default WPF technology manager. It does following –
    • Gets the WPF technology manager as inner manager by using Playback.GetCoreTechnologyManager() API.
    • It delegates most of the call to this inner manager except below ones.
    • GetControlSupportLevel – Here, it inspects to see if this is window of interest and if so, it returns weight more than the default WPF plugin so that it gets picked over the default one.
    • AddEventHandler – Here when the control is TextBox or RepeatButton inside NumericUpDown control, it listens to the value changed event of the TextBox (using inner manager) but fires the event as if it is coming from NumericUpDown.
    • RemoveEventHandler – Ensures reverse mapping to remove listener from the inner manager.
    • All methods that return IUITechnologyElement – Here it maps the IUITechnologyElement that it gets from inner manager to either WrappedTechnologyElement (for all except NumericUpDown) and NudTechnologyElement (for NumericUpDown).
  • WrappedTechnologyElement – This just wraps the WPF UITechnologyElement as the inner element with two differences which are it overrides TechnologyName and TechnologyManager properties to route all technology manager calls to NudTechnologyManager.
  • NudTechnologyElement – This inherits from WrappedTechnologyElement and lets you override any other method for the specific control that you are supporting.  Here, I am overriding the QueryId property which represents the search criteria used during playback to identify the control.
  • WrappedPropertyProvider – This is equivalent of WrappedTechnologyElement on the property provider side.
  • NudPropertyProvider – This is equivalent of NudTechnologyElement on the property provider side.
  • WpfNumericUpDown – This is the specialized class for NumericUpDown control that users of this extension will see in their code.  The class derives from the WpfControl and adds the control specific properties.
  • Utilities – Miscellaneous utilities.

With above details, comments in the code and some debugging on your own, you should be able to understand what is going on here.  Overall, there are some hacks and more code that I would have liked to get the entire scenario working. We will look into making this simpler in future release but folks interested in supporting this scenario now should be able to leverage significant portion of the code from here.


Comments (15)

  1. gsr says:

    How can i write the extensibilty for a Win Control to use UIA technology. I modified the technology manager to UIA as mentioned in the example.It uses the UIA technology but it gets identified as WPF control.

    How can i make it as a WinControl ?

  2. gsr941 says:

    I able to use UIA technology for a Win form control but not able to display it as WinControl. Instead it is shown as WPF control.

    How can i make it as WinControl. Do i need to write a UITestPropertyProvider class? Which proeprty will make sure that that the control and its children use UIA technology but shown as WinControl.

  3. Sorry for late reply.  For some reason, my blog settings got messed up and I had trouble login in.  In general, the Coded UI Test forum (social.msdn.microsoft.com/…/threads) is better place to post your questions as that is monitored by many folks & you will get faster response.

    Regarding the above question, today there is hard binding between UIA technology provider and WpfControl.  If you don't want to do that, you will have to write lot of code – essentially the entire UITestPropertyProvider and all WinXXX classes.

    The question I have for you is why do you want to use UIA technology for WinForms?  We have added lot of functionality and workarounds over and above the one that is provided by accessibility to have better support for WinForms.  For example, for an edit box you can get MAX_LINE_LENGTH using WinEdit.  This information is not provided by UIA or MSAA but we get it via windows message because it is important property.



  4. Eric Chen says:

    why cannot download the attached codes on this post? the link seemed expired.

  5. Alex says:

    The tests fail for me on the very first check. Part of the trace .trx file is below. What should I attempt to make this work? Thanks!


       <UnitTestResult executionId="3139ea25-ddea-44a4-baa6-f0fd751227f9" testId="3d8d8c1f-24c1-9cd2-bce9-175c9b4767a1" testName="CodedUITestMethod1" computerName="KENNY" duration="00:00:08.5609771" startTime="2011-02-17T18:08:59.1746977-05:00" endTime="2011-02-17T18:09:09.6247426-05:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Failed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="3139ea25-ddea-44a4-baa6-f0fd751227f9">


           <DebugTrace>W, 12976, 13, 2011/02/17, 18:09:01.623, 747588891927, QTAgent32.exe, ExtensionFramework : A Technology Manager with name Web is already registered.

    W, 12976, 13, 2011/02/17, 18:09:09.533, 747609437671, QTAgent32.exe, IEDOM : StopSession of the plugin called before StartSession

    W, 12976, 13, 2011/02/17, 18:09:09.533, 747609439198, QTAgent32.exe, UIA : StopSession of the plugin called before StartSession

    W, 12976, 13, 2011/02/17, 18:09:09.534, 747609441870, QTAgent32.exe, SLPlugin : StopSession of the plugin called before StartSession



             <Message>Test method Sample.UITest.WpfNumericUpDown.Test.CodedUITest.CodedUITestMethod1 threw exception:

    System.NotSupportedException: GetProperty of "Maximum" is not supported on control type: Spinner</Message>

             <StackTrace>    at Microsoft.VisualStudio.TestTools.UITesting.PropertyProviderBase.ThrowNotSupportedException(Boolean isNotSupported)

      at Microsoft.VisualStudio.TestTools.UITesting.WpfPropertyProvider.GetPropertyValueInternal(UITestControl uiControl, String propertyName)

      at Microsoft.VisualStudio.TestTools.UITesting.PropertyProviderBase.GetPropertyValue(UITestControl uiControl, String propertyName)

      at Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.GetPropertyValueWrapper(UITestControl uiControl, String propertyName)

      at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetPropertyValue(String propertyName)

      at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetProperty(String propertyName)

      at Sample.UITest.WpfNumericUpDown.Extension.WpfNumericUpDown.get_Maximum() in C:TempWpfNumericUpDownWpfNumericUpDownExtensionWpfNumericUpDown.cs:line 66

      at Sample.UITest.WpfNumericUpDown.Test.UIMap.VerifyNumericUpDownProperties(Double maximum, Double minimum, Double change, Double value, Boolean readOnly) in C:TempWpfNumericUpDownWpfNumericUpDownTestUIMap.cs:line 38

      at Sample.UITest.WpfNumericUpDown.Test.CodedUITest.CodedUITestMethod1() in C:TempWpfNumericUpDownWpfNumericUpDownTestCodedUITest.cs:line 37




  6. Alex says:

    Good post!

    What would be amazing is to also have the solution take care of the deploying / undeploying stuff as part of the build / clean events, preferably using MsBuild tasks.

  7. @alex – Thanks for the suggestion.  Not sure if you have figured out your issue already.  If you haven't this could be deploying issue or Office not installed (at least the .NET interop piece).

  8. Hi Gautam, excellent post!

    I am attempting to create an extension library for the Infragistics UltraGrid class (to start with) and wanted to know if there is an interface that I can implement in my class definition for InfUltraGrid (class similar to WpfNumericUpDown.cs in your example)? Since your example derives the custom object from the Presentation library whereas mine doesn't, I am a little lost on how I can approach a solution and would appreciate your assistance.

    Please let me know if you need more specifics.

  9. Hi Ravi – We have looked at Ultra Grid and there are known issues there because of which writing extension for it in this release will not be possible.  These issues are being considered for future releases.  At this point, you will not be able to use Coded UI Test for Ultra Grid.

    Sorry about that.

  10. Tracy says:

    Hi Gautam,I have a question now.I defined a WpfTabPage to select a control using TabPage.SearchProperties[WpfTabPage.PropertyNames.Name].

    But it is not very stable and some time Test can not select the control.I do not know why it is.

  11. Aharon says:

    Hi there

    what is the case when i have a Wpf app – when i move the "target cross" (at the codedui builder) on the main window – it regognize it and give me its params.

    but when i try to stand on an inner cotrol the "target cross" doesnt recognize it as control at all, and doesnt allow me to point the inner controls,  

  12. @Aharon – This means the control has not exposed inner control properly via accessibility.  Check other commentquestion that you asked on my blog for links to accessibility.

  13. ok -so if i will add custom property to my each control and

    will use "itemStatus" to recognize its control – will then i would be able to locate it?

    as well what is the advantage of using "TechnolayManager" (like your numeric exsample) comparing using location by "itemStatus"?