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 -
- 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).
- 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.
- 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.