{"id":5983,"date":"2011-10-28T04:30:00","date_gmt":"2011-10-28T04:30:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2011\/10\/28\/coded-ui-test-extension-for-3rd-party-windows-forms-controlshow-to\/"},"modified":"2022-07-27T03:06:35","modified_gmt":"2022-07-27T11:06:35","slug":"coded-ui-test-extension-for-3rd-party-windows-forms-controlshow-to","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/coded-ui-test-extension-for-3rd-party-windows-forms-controlshow-to\/","title":{"rendered":"Coded UI Test Extension for 3rd party Windows Forms controls\u2013How to?"},"content":{"rendered":"<p>Here is how one can add FULL Coded UI Test support for a 3rd party control based on Windows Forms technology.<\/p>\n<p><span style=\"font-size: medium\"><strong>Implementation Method \u2013 Accessibility<\/strong><\/span><\/p>\n<p>Accessibility means having equal access to web-based information and services regardless of physical or developmental abilities or impairments. Once implemented, it helps developers make their programs more compatible with accessibility aids (help users with impairment to use programs more effectively).<\/p>\n<p>Microsoft has developed two accessibility standards &#8211; Microsoft Active Accessibility (MSAA) and Microsoft UI Automation (UIA)<\/p>\n<p>MSAA is designed to help Assistive Technology (AT) products interact with standard and custom user interface (UI) elements of an application (or the operating system), as well as to access, identify, and manipulate an application&#8217;s UI elements including enabling automation testing.<\/p>\n<p>UIA is a newer technology that provides a much richer object model than MSAA, and is compatible with both Win32 and the .NET Framework. It is designed so that it can be supported across platforms other than Microsoft Windows.<\/p>\n<p>We recommend MSAA for Windows Forms because Windows Forms natively supports MSAA and not UIA. Although there is MSAA to UIA &amp; vice-versa conversion available via built-in proxybridge but the results in an extra layer of dependency which could eat into performance, hence MSAA.<\/p>\n<p><strong><span style=\"font-size: medium\">Why Accessibility for Coded UI Test?<\/span><\/strong><\/p>\n<p>1&#46; Implementing accessibility is simpler because one needs to follow established guidelines that serve the purpose of developing testable as well as accessible controls in one go<\/p>\n<p>2&#46; There is not much need to write an entire plugin for controls as much of the work is already done. We have built plugins for Windows Forms and Windows Presentation Foundation controls using accessibility technologies and have exposed appropriate extension points for easy hook-up<\/p>\n<p>3&#46; Vendors such as Telerik who develop 3rd party controls have already announced <a href=\"http:\/\/www.telerik.com\/products\/winforms\/getting-started\/accessibility-support.aspx\" target=\"_blank\" rel=\"noopener\">accessibility implementation<\/a><\/p>\n<p>\u00a0<\/p>\n<p><strong><span style=\"font-size: large\">Detailed steps with reference to <\/span><span style=\"font-size: small\"><a href=\"http:\/\/blogs.msdn.com\/b\/visualstudioalm\/archive\/2011\/10\/28\/coded-ui-test-extension-for-3rd-party-controls-the-basics-explained.aspx\"><span>Coded UI Test Extension for 3rd party controls &#8211; the basics explained<\/span><\/a><\/span><\/strong><\/p>\n<p><strong><span style=\"font-size: medium\">Level 1 \u2013 Basic Record and Playback<\/span><\/strong><\/p>\n<p><strong>How can I make a third party GridView with rows and cells to work with basic recording and playback of Coded UI Test?<\/strong><\/p>\n<p>1&#46; Implement MSAA on existing control<\/p>\n<p><img decoding=\"async\" style=\"padding-left: 0px;padding-right: 0px;padding-top: 0px;border-width: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2011\/10\/7206.image_thumb_0AD4AF50.png\" width=\"509\" height=\"93\" \/><\/p>\n<p>2&#46; Override Accessibility methods while you refer to <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.accessibleobject_methods.aspx\" title=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.accessibleobject_methods.aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.accessibleobject_methods.aspx<\/a><\/p>\n<p><img decoding=\"async\" style=\"padding-left: 0px;padding-right: 0px;padding-top: 0px;border-width: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2011\/10\/3666.image_thumb_3DF09D1F.png\" width=\"423\" height=\"105\" \/><\/p>\n<p>3&#46; Example <em>GetChild<\/em> implementation<\/p>\n<table style=\"width: 508px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"506\">\n<p>\n          <span style=\"color: #333399;font-size: x-small\">public override AccessibleObject GetChild(int index) <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">{ <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0 if (index >= 0 &#038;&#038; index < this.GetChildCount()) <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0 { <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GridViewCellInfo cellInFocus = row.Cells[index]; <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RectangleF rectangle = GetCellElement(row, owner.Columns[index]); <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return new CellAccessibleObject(owner, cellInFocus, <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 owner.TableElement.ViewElement.RowLayout.RenderColumns[index+1], <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this, new Point((int)rectangle.X, (int)rectangle.Y), <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new Size((int)rectangle.Width, (int)rectangle.Height), <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 row.Cells[index].Value); <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0 } <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">\u00a0\u00a0\u00a0 return null; <\/span> <br \/><span style=\"color: #333399;font-size: x-small\">}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong><span style=\"font-size: medium\">Level 2 \u2013 Rich Property Validation<\/span><\/strong><\/p>\n<p><strong>How to add BackColor \/ ForeColor \/ BorderColor properties of the Cell so I can assert on the values using the Coded UI Test Builder?<\/strong><\/p>\n<p>1&#46; Override <em>Description<\/em> method of <em>AccessibleObject<\/em> and pass rich property values as semi-colon separated string. This modification needs to be added in the custom control code.<\/p>\n<table style=\"width: 595px;height: 170px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"746\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override string Description <br \/>{ <br \/>\u00a0\u00a0\u00a0 get <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return &#8220;GridViewCellInfo ;&#8221; + cell.Value+&#8221;;&#8221;+this.cell.Style.BackColor.A + &#8220;, &#8221; + <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.cell.Style.BackColor.B + &#8220;, &#8221; + cell.Style.BackColor.G + &#8220;;&#8221; + this.cell.Style.ForeColor.A + &#8220;, &#8221; + <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.cell.Style.ForeColor.B + &#8220;, &#8221; + cell.Style.ForeColor.G + &#8220;;&#8221; + this.cell.Style.BorderColor.A + &#8220;, &#8221; + <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.cell.Style.BorderColor.B + &#8220;, &#8221; + cell.Style.BorderColor.G+&#8221;;&#8221;+cell.IsSelected; <br \/>\u00a0\u00a0\u00a0 } <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0<\/p>\n<p>2&#46; A plugin needs to be written on top of PropertyProvider. Write custom <em>PropertyProvider<\/em> and implement <em>GetPropertyValue<\/em> method. Use this method to retrieve the semi-colon separated property values<\/p>\n<table style=\"width: 592px;height: 556px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"758\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override object GetPropertyValue(UITestControl uiTestControl, string propertyName) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (CellPropertiesMap.ContainsKey(propertyName) &#038;&#038; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (CellPropertiesMap[propertyName].Attributes &#038; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 UITestPropertyAttributes.Readable) == UITestPropertyAttributes.Readable) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 object[] native = uiTestControl.NativeElement as object[]; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IAccessible a = native[0] as IAccessible;<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (string.Equals(propertyName, GridViewCellInfo.PropertyNames.BackColor, StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string[] descriptionTokens = a.accDescription.Split(new char[] { &#8216;;&#8217; }); ; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return descriptionTokens[2]; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (string.Equals(propertyName, GridViewCellInfo.PropertyNames.ForeColor, StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string[] descriptionTokens = a.accDescription.Split(new char[] { &#8216;;&#8217; }); ; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return descriptionTokens[3]; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (string.Equals(propertyName, GridViewCellInfo.PropertyNames.BorderColor, StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string[] descriptionTokens = a.accDescription.Split(new char[] { &#8216;;&#8217; }); ; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return descriptionTokens[4]; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 throw new NotSupportedException(); <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 isInThisProvider = true; <br \/>\u00a0\u00a0\u00a0 try <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 UITestControl winControl = new UITestControl(); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 winControl.CopyFrom(uiTestControl); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return winControl; <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 finally <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 isInThisProvider = false; <br \/>\u00a0\u00a0\u00a0 } <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>3&#46; Define a Dictionary of custom property names and <em>UITestPropertyDescriptor<\/em> property types<\/p>\n<table style=\"width: 590px;height: 251px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"824\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">private static Dictionary<string, UITestPropertyDescriptor> CellPropertiesMap <br \/>{ <br \/>\u00a0\u00a0\u00a0 get <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (cellPropertiesMap == null) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 UITestPropertyAttributes read = UITestPropertyAttributes.Readable | UITestPropertyAttributes.DoNotGenerateProperties; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cellPropertiesMap = new Dictionary<string, UITestPropertyDescriptor>(StringComparer.OrdinalIgnoreCase); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cellPropertiesMap.Add(&#8220;BackColor&#8221;, new UITestPropertyDescriptor(typeof(string), read)); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cellPropertiesMap.Add(&#8220;ForeColor&#8221;, new UITestPropertyDescriptor(typeof(string), read)); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cellPropertiesMap.Add(&#8220;BorderColor&#8221;, new UITestPropertyDescriptor(typeof(string), read)); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return cellPropertiesMap; <br \/>\u00a0\u00a0\u00a0 } <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>4&#46; Override *GetPropertyDescriptor *and return the property types set in step 3<\/p>\n<table style=\"width: 588px;height: 170px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"719\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override UITestPropertyDescriptor GetPropertyDescriptor(UITestControl uiTestControl, string propertyName) <br \/>{ <br \/>\u00a0\u00a0\u00a0 var map = GetAllPropertiesMap(uiTestControl); <br \/>\u00a0\u00a0\u00a0 var map2 = GetCellPropertiesMap(uiTestControl); <br \/>\u00a0\u00a0\u00a0 if (map2.ContainsKey(propertyName)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return map2[propertyName]; <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 return null; <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>5&#46; Override <em>GetpropertyNames *of *PropertyProvider<\/em><\/p>\n<table style=\"width: 585px;height: 156px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"721\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override ICollection<string> GetPropertyNames(UITestControl uiTestControl) <br \/>{ <br \/>\u00a0\u00a0\u00a0 String controlType = uiTestControl.ControlType.Name; <br \/>\u00a0\u00a0\u00a0 if (uiTestControl.ControlType.NameEquals(&#8220;Cell&#8221;)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return GetCellPropertiesMap(uiTestControl).Keys; <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 return GetAllPropertiesMap(uiTestControl).Keys; <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>6&#46; Override <em>GetControlSupportLevel<\/em> of *PropertyProvider. *The method should be set to return maximum Control Support for the custom control which in this case includes Table, Row and Cell<\/p>\n<table style=\"width: 583px;height: 263px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"902\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override int GetControlSupportLevel(UITestControl uiTestControl) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (!isInThisProvider &#038;&#038; IsSupported(uiTestControl)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return (int)ControlSupport.ControlSpecificSupport; <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 return (int)ControlSupport.NoSupport; <br \/>} <br \/>private static bool IsSupported(UITestControl uiTestControl) <br \/>{ <br \/>\u00a0\u00a0\u00a0 return (uiTestControl is RadGridView) || (uiTestControl is GridViewRowInfo) || (uiTestControl is GridViewCellInfo) || (uiTestControl is GridViewDataColumn) || <br \/>\u00a0\u00a0\u00a0 (string.Equals(uiTestControl.TechnologyName, &#8220;MSAA&#8221;, StringComparison.OrdinalIgnoreCase) &#038;&#038; <br \/>\u00a0\u00a0\u00a0 (uiTestControl.ControlType == ControlType.Table || uiTestControl.ControlType == &#8220;Row&#8221; || uiTestControl.ControlType == &#8220;Cell&#8221; || <br \/>\u00a0\u00a0\u00a0 uiTestControl.ControlType == &#8220;Edit&#8221;));<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This completes the PropertyProvider implementation to add rich control validation. Now we need to add this service to the UITestExtension package.<\/p>\n<p>7&#46; Implement <em>GetService<\/em> of <em>UITestExtensionPackage<\/em><\/p>\n<table style=\"width: 582px;height: 331px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"695\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">internal class RadGridViewExtensionPackage : UITestExtensionPackage <br \/>{<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public override object GetService(Type serviceType) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (serviceType == typeof(UITestPropertyProvider)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (propertyProvider == null) { propertyProvider = new PropertyProvider(); } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return propertyProvider; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return null; <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public override void Dispose() {} <br \/>\u00a0\u00a0\u00a0 public override string PackageDescription {get { return &#8220;RadGridView Extension&#8221;; }} <br \/>\u00a0\u00a0\u00a0 public override string PackageName { get { return &#8220;RadGridView Extension&#8221;; } } <br \/>\u00a0\u00a0\u00a0 public override string PackageVendor { get { return &#8220;Shubhra Maji&#8221;; }} <br \/>\u00a0\u00a0\u00a0 public override Version PackageVersion { get { return new Version(1, 0); }\u00a0 } <br \/>\u00a0\u00a0\u00a0 public override Version VSVersion { get { return new Version(10, 0); } }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 private UITestPropertyProvider propertyProvider; <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>4&#46; Build and deploy the binaries to &#8220;%CommonProgramFiles(x86)%Microsoft SharedVSTT10.0UITestExtensionPackages&#8221; directory<\/p>\n<p>\u00a0<\/p>\n<p><strong><span style=\"font-size: medium\">Level 3 \u2013 Code Generation<\/span><\/strong><\/p>\n<p><strong>What do I need to do in order to see objects of custom classes in the auto-generated code after recording user actions?<\/strong><\/p>\n<p>1&#46; Add specialized class for control extending from WinControl, in this example, Cell control (<em>GridViewCellInfo)<\/em><\/p>\n<p>2&#46; Add Custom Property Names in the Specialized class if desired<\/p>\n<table style=\"width: 581px;height: 329px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"635\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public class GridViewCellInfo:WinControl <br \/>{<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public GridViewCellInfo(UITestControl c) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : base(c) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SearchProperties.Add(UITestControl.PropertyNames.ControlType, &#8220;Cell&#8221;); <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public virtual string BackColor <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 get <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return (string)this.GetProperty(PropertyNames.BackColor); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 new public abstract class PropertyNames : UITestControl.PropertyNames <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public static readonly string BackColor = &#8220;BackColor&#8221;; <br \/>\u00a0\u00a0\u00a0 } <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>3&#46; Override <em>GetSpecializedClass *method of *PropertyProvider<\/em><\/p>\n<table style=\"width: 582px;height: 153px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"632\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override Type GetSpecializedClass(UITestControl uiTestControl) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (uiTestControl.ControlType.NameEquals(&#8220;Cell&#8221;)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return typeof(GridViewCellInfo); <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 return null;<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>4&#46; Override *GetPropertyNamesClassType *method of *PropertyProvider *if you have defined custom properties for the control<\/p>\n<table style=\"width: 582px;height: 141px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"633\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override Type GetPropertyNamesClassType(UITestControl uiTestControl) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (uiTestControl.ControlType.NameEquals(&#8220;Cell&#8221;)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return typeof(GridViewCellInfo.PropertyNames); <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 return null; <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This completes the PropertyProvider implementation to add custom code generation. Since we have already added the property provider service in Level 2, we need to re-deploy the binaries to &#8220;%CommonProgramFiles(x86)%Microsoft SharedVSTT10.0UITestExtensionPackages&#8221; directory<\/p>\n<p>\u00a0<\/p>\n<p><strong><span style=\"font-size: medium\">Level 4 \u2013 Intent Aware Actions<\/span><\/strong><\/p>\n<p><strong>How can I aggregate a double click on a cell followed by edit text into one action &#8211; set value on cell?<\/strong><\/p>\n<p>Write aggregators for recording setValue and property provider for playing back the setValue.<\/p>\n<p>1&#46; Write custom <em>ActionFilter<\/em> and implement <em>ProcessRule<\/em> to filter actions<\/p>\n<table style=\"width: 580px;height: 388px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"785\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override bool ProcessRule(IUITestActionStack actionStack) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (actionStack.Count < 2) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return false; <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 SetValueAction lastAction = actionStack.Peek() as SetValueAction; <br \/>\u00a0\u00a0\u00a0 MouseAction mouseAction = actionStack.Peek(1) as MouseAction; <br \/>\u00a0\u00a0\u00a0 if (lastAction != null &#038;&#038; mouseAction != null) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (lastAction.UIElement != null &#038;&#038; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 lastAction.UIElement.ControlTypeName.Equals(ControlType.Edit.ToString(), StringComparison.OrdinalIgnoreCase) &#038;&#038; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mouseAction.UIElement != null &#038;&#038; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mouseAction.UIElement.ControlTypeName.Equals(ControlType.Cell.ToString(), StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 actionStack.Pop(); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 UITestAction cellAction = actionStack.Pop(); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SetValueAction newCellAction = new SetValueAction(cellAction.UIElement, lastAction.Value); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 newCellAction.AdditionalInfo = &#8220;Aggregated&#8221;; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 actionStack.Push(newCellAction); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return false; <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0<\/p>\n<p>2&#46; Override <em>GetPropertyForAction\u00a0 of PropertyProvider<\/em> if you want to define custom action names<\/p>\n<table style=\"width: 556px;height: 142px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"628\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">public override string GetPropertyForAction(UITestControl uiTestControl, UITestAction action) <br \/>{ <br \/>\u00a0\u00a0\u00a0 if (uiTestControl.ControlType.Equals(ControlType.Cell)) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return GridViewCellInfo.PropertyNames.CellValue; <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 throw new NotSupportedException(); <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This completes the PropertyProvider implementation to add rich control validation. Now we need to add this service to the UITestExtension package.<\/p>\n<p>3&#46; Implement <em>SetPropertyValue *of *PropertyProvider<\/em><\/p>\n<table style=\"width: 552px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"550\">\n<p>\n          <span style=\"color: #333399;font-size: xx-small\">public override void SetPropertyValue(UITestControl uiTestControl, string propertyName, object propertyValue) <br \/>{ <br \/>\u00a0\u00a0\u00a0 isInThisProvider = true; <br \/>\u00a0\u00a0\u00a0 try <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 UITestControl copyControl = GetCopiedControl(uiTestControl);<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #333399;font-size: xx-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (string.Equals(propertyName, GridEditTextBoxElement.PropertyNames.EditText, StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 copyControl.SetProperty(WinEdit.PropertyNames.Text, propertyValue); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else if (string.Equals(propertyName, GridViewCellInfo.PropertyNames.CellValue, StringComparison.OrdinalIgnoreCase)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (copyControl.ControlType.Equals(ControlType.Cell)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mouse.Click(copyControl); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GridEditTextBoxElement editcontrol = new GridEditTextBoxElement(copyControl); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mouse.Click(editcontrol); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{Home}&#8221;); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{End}&#8221;, System.Windows.Input.ModifierKeys.Shift); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{Delete}&#8221;); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(propertyValue.ToString()); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch (UITestControlNotFoundException) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ retry after one more click <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mouse.Click(copyControl);<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #333399;font-size: xx-small\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GridEditTextBoxElement editcontrol = new GridEditTextBoxElement(copyControl); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mouse.Click(editcontrol); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{Home}&#8221;); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{End}&#8221;, System.Windows.Input.ModifierKeys.Shift); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(&#8220;{Delete}&#8221;); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Keyboard.SendKeys(propertyValue.ToString()); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GetCopiedControl(uiTestControl).SetProperty(propertyName, propertyValue); <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0 finally <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 isInThisProvider = false; <br \/>\u00a0\u00a0\u00a0 } <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>4&#46; Implement <em>GetService<\/em> of <em>UITestExtensionPackage<\/em><\/p>\n<table style=\"width: 552px;height: 413px\" border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"627\">\n<p>\n          <span style=\"color: #400080;font-size: x-small\">internal class RadGridViewExtensionPackage : UITestExtensionPackage <br \/>{<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public override object GetService(Type serviceType) <br \/>\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (serviceType == typeof(UITestPropertyProvider)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (propertyProvider == null) { propertyProvider = new PropertyProvider(); } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return propertyProvider; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else if (serviceType == typeof(UITestActionFilter)) <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 { <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (actionFilter == null) { actionFilter = new RadGridViewActionFilter(); } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return actionFilter; <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } <br \/>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return null; <br \/>\u00a0\u00a0\u00a0 }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 public override void Dispose() {} <br \/>\u00a0\u00a0\u00a0 private RadGridViewActionFilter actionFilter; <br \/>\u00a0\u00a0\u00a0 public override string PackageDescription {get { return &#8220;RadGridView Extension&#8221;; }} <br \/>\u00a0\u00a0\u00a0 public override string PackageName { get { return &#8220;RadGridView Extension&#8221;; } } <br \/>\u00a0\u00a0\u00a0 public override string PackageVendor { get { return &#8220;Shubhra Maji&#8221;; }} <br \/>\u00a0\u00a0\u00a0 public override Version PackageVersion { get { return new Version(1, 0); }\u00a0 } <br \/>\u00a0\u00a0\u00a0 public override Version VSVersion { get { return new Version(10, 0); } }<\/span>\n        <\/p>\n<p>\n          <span style=\"color: #400080;font-size: x-small\">\u00a0\u00a0\u00a0 private UITestPropertyProvider propertyProvider; <br \/>}<\/span>\n        <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>4&#46; Build and deploy the binaries to &#8220;%CommonProgramFiles(x86)%Microsoft SharedVSTT10.0UITestExtensionPackages&#8221; directory<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here is how one can add FULL Coded UI Test support for a 3rd party control based on Windows Forms technology. Implementation Method \u2013 Accessibility Accessibility means having equal access to web-based information and services regardless of physical or developmental abilities or impairments. Once implemented, it helps developers make their programs more compatible with accessibility [&hellip;]<\/p>\n","protected":false},"author":77,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[226,229,1,252],"tags":[],"class_list":["post-5983","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ci","category-community","category-devops","category-testing"],"acf":[],"blog_post_summary":"<p>Here is how one can add FULL Coded UI Test support for a 3rd party control based on Windows Forms technology. Implementation Method \u2013 Accessibility Accessibility means having equal access to web-based information and services regardless of physical or developmental abilities or impairments. Once implemented, it helps developers make their programs more compatible with accessibility [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/5983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/77"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=5983"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/5983\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=5983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=5983"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=5983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}