Enabling UI Testing for Third party WinForms custom controls - 1

Most of the leading Third party WinForms custom control vendors implement Microsoft Active Accessibility(MSAA). Since Visual Studio UI Testing framework uses MSAA for WinForms controls, it is natural to expect that users can test these custom controls also. The custom control vendors have implemented sufficient accessibility for Narrator. There are some subtle differences in the requirements for Screen Narrator & UI Test Framework.   In this article, I will describe the additional requirements from a Visual Studio UI Testing Framework perspective.

For the purposes of this article, I have picked up the DevExpress XtraScheduler Scheduler Control. The guidance in this article should be applicable for all custom WinForms controls.

 

How does the control behave in Coded UI Test if required accessibility is not implemented?

The Scheduler Control appears as a MSAA client object. The appointments inside are not accessible.

clip_image001[4]

 

What are the steps required to make the Appointment objects visible in Coded UI Test?

Step 1: I create a Custom Control which inherits from SchedulerControl.

public partial class CustomControl1 : DevExpress.XtraScheduler.SchedulerControl

 

Step 2: I override the CreateAccessibilityInstance of the CustomControl class to return my Accessibility implementation.

protected override AccessibleObject CreateAccessibilityInstance()

        {

               return new CustomControl1AccessibleObject(this);

        }

Step 3:- I implement Accessibility for my Custom Control. I am inheriting from Control.ControlAccessibleObject.

public sealed class CustomControl1AccessibleObject: Control.ControlAccessibleObject

The key methods that I want implemented here are GetChildCount & GetChildren. These methods are used by Visual Studio UI Testing framework to navigate in the UI Tree.

For GetChildren, I return the number of Appointments in the ActiveView.

For GetChild, I return the Accessibility implementation for the Appointments.

public override int GetChildCount()

            {

                  return owner.ActiveView.GetAppointments().Count();

            }

public override AccessibleObject GetChild(int index)

            {

                if ((appointments == null) || appointments.Count() != this.GetChildCount() )

                {

                    appointments = new AppointmentAccessibleObject[this.GetChildCount()];

                    int i = 0;

                    foreach (Appointment a in owner.ActiveView.GetAppointments())

                    {

                            appointments[i] = new AppointmentAccessibleObject(owner,a,this,

                                                            owner.ActiveView.ViewInfo.AppointmentViewInfos[i].Bounds.Location,

                                                            owner.ActiveView.ViewInfo.AppointmentViewInfos[i].Bounds.Size,

                                                            a.Start.ToString() + "-" + a.End.ToString());

                           i++;

                    }

                }

                return appointments[index];

            }

AppointmentAccessible Object is also inheriting from ControlAccessible Object.

public sealed class AppointmentAccessibleObject : Control.ControlAccessibleObject

The key property in this class is Bounds. This helps the Visual Studio UI Testing framework to locate the control.

public override Rectangle Bounds

            {

                get

                {

                      return new Rectangle(owner.PointToScreen(location), size);

                }

            }

The complete source code for my Custom Control is attached. Now I go to my application code and replace instances of DevExpress.XtraScheduler.SchedulerControl with CustomControl1.

Now using Coded UI Test Builder, I can access the Appointments.

clip_image001[6]

In the next article, I will continue discussion on this topic and describe how we can retrieve additional properties for both the Scheduler Control & appointments.

CustomControl1.cs