/// <summary> /// Get Glimpses of UIA Elements /// </summary> /// <param name="e"></param> /// <returns></returns> private static string GetGlimpsesOfUIAElements(IUIAutomationElementArray arr) { if (arr.Length != 0) { StringBuilder sb = new StringBuilder(); sb.Append('['); for (int i = 0; i < arr.Length; i++) { var e = arr.GetElement(i); if (i != 0) { sb.Append(", "); } sb.Append($"{GetGlimpseOfUIAElement(e)}"); Marshal.ReleaseComObject(e); } sb.Append(']'); return(sb.ToString()); } return(null); }
/// <summary> /// Get DesktopElements from UIAElements. /// </summary> /// <param name="uia"></param> /// <returns>An IEnumerable of <see cref="DesktopElement"/></returns> private static IEnumerable <DesktopElement> ElementsFromUIAElements(IUIAutomationElementArray elementArray) { if (elementArray == null) { throw new ArgumentNullException(nameof(elementArray)); } // Return an empty IEnumerable<DesktopElement> instead of null from ElementsFromUIAElements so that downstream calls to Linq extensions on the IEnumerable don't throw null reference exceptions. var count = elementArray.Length; if (count <= 0) { return(Enumerable.Empty <DesktopElement>()); } // This function was originally an iterator // Meaning it used the yield keyword to yield return each element // But that caused a com exception IRL // So now we use a list List <DesktopElement> elements = new List <DesktopElement>(); for (int i = 0; i < count; ++i) { var uiaElement = elementArray.GetElement(i); var e = ElementFromUIAElement(uiaElement); if (e == null) { continue; } elements.Add(e); } // for each element return(elements); }
private void EnumarateChildren(IUIAutomationElement element) { Console.WriteLine("{0}", element.CurrentName.Trim()); IUIAutomationCacheRequest cacheRequest = _automation.CreateCacheRequest(); cacheRequest.AddProperty(System.Windows.Automation.AutomationElement.NameProperty.Id); cacheRequest.AddProperty(System.Windows.Automation.AutomationElement.ControlTypeProperty.Id); cacheRequest.TreeScope = TreeScope.TreeScope_Element | TreeScope.TreeScope_Children | TreeScope.TreeScope_Subtree; IUIAutomationCondition cond; cond = _automation.CreatePropertyConditionEx( System.Windows.Automation.AutomationElement.ControlTypeProperty.Id, System.Windows.Automation.ControlType.Window.Id, PropertyConditionFlags.PropertyConditionFlags_IgnoreCase); IUIAutomationElementArray elementList = element.FindAllBuildCache(TreeScope.TreeScope_Children, cond, cacheRequest); if (elementList == null) { return; } for (int i = 0; i < elementList.Length; i++) { EnumarateChildren(elementList.GetElement(i)); } }
internal AutomationElementCollection(IUIAutomationElementArray elementArray) { this._elements = new AutomationElement[elementArray.Length]; for (var index = 0; index < elementArray.Length; ++index) { this._elements[index] = new AutomationElement(autoElement: elementArray.GetElement(index: index)); } }
/// <summary> /// Change IUIAutomationElementArray To a list of DesktopElement /// </summary> /// <param name="array"></param> /// <returns></returns> public static List <DesktopElement> ToListOfDesktopElements(this IUIAutomationElementArray array) { List <DesktopElement> list = new List <DesktopElement>(); for (int i = 0; i < array.Length; i++) { list.Add(new DesktopElement(array.GetElement(i))); } return(list); }
private static void DeselectAll(IUIAutomationElementArray elementArray) { for (var i = 0; i < elementArray.Length; i++) { var selectedItem = elementArray.GetElement(i); if (selectedItem.GetCurrentPattern(UIA_PatternIds.UIA_SelectionItemPatternId) is IUIAutomationSelectionItemPattern selectedItemPattern) { selectedItemPattern.RemoveFromSelection(); } } }
public Element[] GetAllElements(TreeScope Scope) { IUIAutomationElementArray elementsToFind = null; elementsToFind = IUIElement.FindAll(Scope, new CUIAutomationClass().CreateTrueCondition()); int size = elementsToFind.Length; Element[] arr = new Element[size]; for (int i = 0; i < size; i++) { arr[i] = new Element(elementsToFind.GetElement(i)); } return(arr); }
/// <summary> /// Get all elements from the current element that match the specified control type. /// </summary> /// <param name="Scope"></param> /// <param name="ControlType"></param> /// <returns></returns> public ControlElement[] GetControlsByControlType(TreeScope Scope, LocalizedControlType ControlType) { IUIAutomationElementArray elementsToFind = null; IUIAutomationCondition cond = new CUIAutomationClass().CreatePropertyCondition(By.ControlType.GetId(), ControlType.GetControlTypeValue()); elementsToFind = this.IUIElement.FindAll(Scope, cond); int size = elementsToFind.Length; ControlElement[] arr = new ControlElement[size]; for (int i = 0; i < size; i++) { arr[i] = new ControlElement(elementsToFind.GetElement(i)); } return(arr); }
//public void RefreshScrollingContainer(IntPtr hwnd) //{ //} public IUIAutomationElement[] GetAppsArray(IUIAutomationElement homeElement) { IUIAutomationCondition condition = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_ListItemControlTypeId); IUIAutomationElementArray appsList = homeElement.FindAll(TreeScope.TreeScope_Children, condition); Console.WriteLine(appsList.Length); IUIAutomationElement[] appsArray = new IUIAutomationElement[appsList.Length]; for (int i = 0; i < appsList.Length; i++) { appsArray[i] = appsList.GetElement(i); Console.WriteLine(appsArray[i].CurrentAutomationId); } return(appsArray); }
/// <summary> /// Change IUIAutomationElementArray To a list of DesktopElement /// </summary> /// <param name="array"></param> /// <returns></returns> public static List <DesktopElement> ToListOfDesktopElements(this IUIAutomationElementArray array) { if (array == null) { throw new ArgumentNullException(nameof(array)); } List <DesktopElement> list = new List <DesktopElement>(); for (int i = 0; i < array.Length; i++) { list.Add(new DesktopElement(array.GetElement(i))); } return(list); }
public IUIAutomationElement[] GetTopFreeHomeArray(IUIAutomationElement element) { IUIAutomationCondition[] conditionArray = new IUIAutomationCondition[2]; conditionArray[0] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "Top free"); conditionArray[1] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_ListItemControlTypeId); IUIAutomationCondition conditions = _automation.CreateAndConditionFromArray(conditionArray); IUIAutomationElementArray topFreeList = element.FindAll(TreeScope.TreeScope_Children, conditions); IUIAutomationElement[] topFreeArray = new IUIAutomationElement[topFreeList.Length]; for (int i = 0; i < topFreeList.Length; i++) { topFreeArray[i] = topFreeList.GetElement(i); } return(topFreeArray); }
internal static AutomationElement[] ConvertToElementArray(IUIAutomationElementArray array) { AutomationElement[] elementArray; if (array != null) { elementArray = new AutomationElement[array.Length]; for (int i = 0; i < array.Length; i++) { elementArray[i] = AutomationElement.Wrap(array.GetElement(i)); } } else { elementArray = null; } return(elementArray); }
private void AutomationTree_TargetUpdated(object sender, DataTransferEventArgs e) { //IUIAutomationCondition uIAutomationCondition = new IUIAutomationCondition(); CUIAutomation8 cUIAutomation8 = new CUIAutomation8(); IUIAutomationElementArray rootChildrens = cUIAutomation8.GetRootElement().FindAll(TreeScope.TreeScope_Children, cUIAutomation8.CreateTrueCondition()); TreeViewItem tree = new TreeViewItem(); tree.Header = cUIAutomation8.GetRootElement().GetCurrentPropertyValue(30005); // IUIAutomationTreeWalker uIAutomationTreeWalker; // uIAutomationTreeWalker. for (int i = 0; i < rootChildrens.Length; i++) { IUIAutomationElement children = rootChildrens.GetElement(i); tree.Items.Add(String.Format("{0} {1}", children.GetCurrentPropertyValue(30005), children.CurrentLocalizedControlType)); } automationTree.Items.Add(tree); //MessageBox.Show(rootElement.GetCurrentPropertyValue(30012)); }
private void loadChildren(TreeNode node) { IUIAutomationElementArray array = node.element.FindAll(TreeScope.TreeScope_Children, automation.CreateTrueCondition()); if (0 == array.Length) { node.children = null; node.isLeaf = true; } else { for (int i = 0; i < array.Length; i++) { IUIAutomationElement e = array.GetElement(i); TreeNode n = new TreeNode(e); node.children.Add(n); this.loadChildren(n); } } }
public ViewTree(IUIAutomationElement element, IUIAutomation automation) { this.root = new TreeNode(element); this.root.parent = null; IUIAutomationElementArray array = element.FindAll(TreeScope.TreeScope_Children, automation.CreateTrueCondition()); if (0 == array.Length) { this.root.children = null; this.root.isLeaf = true; } else { for (int i = 0; i < array.Length; i++) { IUIAutomationElement e = array.GetElement(i); TreeNode n = new TreeNode(e); this.root.children.Add(n); } } }
/// <summary> /// Get an element from the current element that matches the specified conditon. /// </summary> /// <param name="Scope"></param> /// <param name="Condition"></param> /// <returns></returns> public ControlElement[] GetControls(TreeScope Scope, SearchCondition Condition) { IUIAutomationElementArray elementsToFind = null; ControlElement[] arr = null; for (int i = 0; i < 100; i++) { try { elementsToFind = this.IUIElement.FindAll(Scope, Condition.UIAutomationCondition); } catch (COMException e) { } catch (UnauthorizedAccessException ex) { } if (elementsToFind != null) { int size = elementsToFind.Length; arr = new ControlElement[size]; for (int j = 0; j < size; j++) { arr[j] = new ControlElement(elementsToFind.GetElement(j)); } break; } else { Thread.Sleep(100); } } if (elementsToFind == null) { return(null); } else { return(arr); } }
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // GetCachedDataFromElement() // // Get the cached name from a UIA element. If the element doesn't have a name, // optionally try to find a name from the cached children of the element. // // Runs on the background thread. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// private string GetCachedDataFromElement(IUIAutomationElement element, bool fSearchLinkChildren) { // (A shipping app would do parameter checking here.) string strName = null; // Get the bounding rectangle for the hyperlink. By retrieving this from the // cache, we avoid the time-consuming cross-process call to get the data. tagRECT rectBounds = element.CachedBoundingRectangle; // If the hyperlink has a zero-size bounding rect, ignore the element. This // might happen if the hyperlink has scrolled out of view. (We could also // investigate whether using the IsOffscreen property tells us that the link // can be ignored. In fact, if the IsOffscreen property is reliable, we could // have included a property condition of IsOffcreen is false in the original // search, and not check whether the link's visible here.) if ((rectBounds.right > rectBounds.left) && (rectBounds.bottom > rectBounds.top)) { // Get the name of the element. This will often be the text shown on the screen. // Note that the set of get_Cached* functions (or get_Current*), are convenient // ways of retrieving the same data that could be retrieved through the functions // GetCachedPropertyValue() (or GetCurrentPropertValue().) In the case of get_CachedName(), // the alternative would be to call GetCachedPropertyValue() with UIA_NamePropertyId. string strNameFound = element.CachedName; if (strNameFound.Length > 0) { // A shipping app would check for more than an empty string. (A link might // just have " " for a name.) strName = strNameFound; } else { // The hyperlink has no usable name. Consider using the name of a child element of the hyperlink. if (fSearchLinkChildren) { // Given that hyperlink element has no name, use the name of first child // element that does have a name. (In some cases the hyperlink element might // contain an image or text element that does have a useful name.) We can take // this action here because we supplied TreeScope_Children as the scope of the // cache request that we passed in the call to FindAllBuildCache(). IUIAutomationElementArray elementArrayChildren = element.GetCachedChildren(); if (elementArrayChildren != null) { int cChildren = elementArrayChildren.Length; // For each child element found... for (int idxChild = 0; idxChild < cChildren; ++idxChild) { IUIAutomationElement elementChild = elementArrayChildren.GetElement(idxChild); if (elementChild != null) { string strNameChild = elementChild.CachedName; // Check the name of the child elements here. We don't // care what type of element it is in this sample app. if (strNameChild.Length > 0) { // We have a usable name. strName = strNameChild; break; } // Try the next child element of the hyperlink... } } } } } } return(strName); }
// Step 2: Find all the links of interest on the loaded page. private void buttonFindLinks_Click(object sender, EventArgs e) { checkedListBoxLinks.Items.Clear(); if (webBrowserPage.Url == null) { MessageBox.Show(this, "Please load the web page of interest.", "Link Getter", MessageBoxButtons.OK); labelLinkCount.Text = "No links found."; return; } // Get the UIA element for the webBrowser with the page of interest loaded. IUIAutomationElement elementBrowser = automation.ElementFromHandle(webBrowserPage.Handle); // Build up a cache request for all the data we need, to reduce the time it // takes to access the link data once with have the collection of links. IUIAutomationCacheRequest cacheRequest = automation.CreateCacheRequest(); cacheRequest.AddProperty(propertyIdName); cacheRequest.AddPattern(patternIdValue); cacheRequest.AddProperty(propertyIdValueValue); // Assume the links have names as expected, and we don't need to // search children of the links for names. cacheRequest.TreeScope = TreeScope.TreeScope_Element; // We want the collection of all links on the page. IUIAutomationCondition conditionControlView = automation.ControlViewCondition; IUIAutomationCondition conditionHyperlink = automation.CreatePropertyCondition( propertyIdControlType, controlTypeIdHyperlink); IUIAutomationCondition finalCondition = automation.CreateAndCondition( conditionControlView, conditionHyperlink); // TODO: Call FindAllBuildCache() in a background thread in case it takes // a while. As it is, the app UI's going to freeze. // Now get the collection of links. IUIAutomationElementArray elementArray = elementBrowser.FindAllBuildCache( TreeScope.TreeScope_Descendants, finalCondition, cacheRequest); if (elementArray != null) { // Process each returned hyperlink element. for (int idxLink = 0; idxLink < elementArray.Length; ++idxLink) { IUIAutomationElement elementLink = elementArray.GetElement(idxLink); // Despite the fact that we've got the names of the UIA links, don't // use that information here. Perhaps we will use it in the future. IUIAutomationValuePattern valuePattern = (IUIAutomationValuePattern)elementLink.GetCurrentPattern( patternIdValue); if (valuePattern != null) { // We're only interested in references the page makes to itself. string strValueLink = valuePattern.CachedValue; var index = strValueLink.IndexOf('#'); if ((index > 0) && strValueLink.StartsWith(textBoxURL.Text)) { checkedListBoxLinks.Items.Add(new LinkItem() { linkName = elementLink.CachedName, linkURL = strValueLink }); } } } } // Let's assume we'll want most of the links found. SetLinkCheckedState(true); labelLinkCount.Text = "Count of links found: " + checkedListBoxLinks.Items.Count; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // This function is not used by the sample, but it shows an alternative approach to building up // the cache of hyperlinks. Depending on the action taken by the target app when providing data // to be stored in the cache of results, different approaches taken by the UIA client can have // different performance benefits. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void BuildListOfHyperlinksFromWindowInternalAlternateApproach(bool fSearchLinkChildren) { // If we're already building up a list of links, ignore this request to refresh the list. // (A shipping app might consider queueing this request in order to refresh the list again // once the in-progress refreshing action is complete.) if (_fRefreshInProgress) { return; } _fRefreshInProgress = true; // First build a cache request in the same way as done elsewhere in the sample. // This means that for each element returned following the search, they will // have their name, bounding rect and Invoke pattern cached. IUIAutomationCacheRequest cacheRequest = _automation.CreateCacheRequest(); cacheRequest.AddProperty(_propertyIdName); cacheRequest.AddProperty(_propertyIdBoundingRectangle); cacheRequest.AddPattern(_patternIdInvoke); // At this point elsewhere in the sample, we specified that we only wanted data // for the hyperlink elements (and optionally their children) cached. In this // approach here, we will say that we want data for ALL descendants of the // found elements cached. cacheRequest.TreeScope = TreeScope.TreeScope_Descendants; // Now create a property condition as we've done elsewhere, to say that we're only // interested in elements which are in the Control view and are hyperlinks. IUIAutomationCondition conditionControlView = _automation.ControlViewCondition; IUIAutomationCondition conditionHyperlink = _automation.CreatePropertyCondition(_propertyIdControlType, _controlTypeIdHyperlink); IUIAutomationCondition condition = _automation.CreateAndCondition(conditionControlView, conditionHyperlink); // Now unlike steps we took elsewhere, specify that the cache request should // have an additional filter of the property condition we just created. cacheRequest.TreeFilter = condition; // Elsewhere in the sample, we called FindAllBuildCache(). This returned an array of hyperlink // elements with their data cached, (and optinally their children with cache data too.) This // CacheLinksFromWindow() function takes a different approach. The element that is returned // from the call to BuildUpdatedCache() below is the browser element with some data cached. // But the returned element will have an array of cached child elements, and each of those // elements will by the hyperlinks we need. So the cache request here has specified through // its tree filter that we're only interest in hyperlinks, whereas elsewhere in this sample, // we supplied that condition in the search call we made. How much difference this makes to // the performance of calls depends on the action taken by the target application. // *** Note, using this appoach, we can't also cache data for the direct children of the // hyperlinks as we did elsewhere in the sample. So whether this approach is practical // depends on the needs of the client application. // Note that with a property conditions, it's not possible to request that the set of elements // returned from a search are all elements which have a control type of hyperlink OR whose parent // has a control type of hyperlink. // Get a handle to the window of interest. IntPtr hwnd = Win32.FindWindow(strBrowserWindowClass, null); if (hwnd != IntPtr.Zero) { IUIAutomationElement elementBrowser = _automation.ElementFromHandleBuildCache(hwnd, cacheRequest); if (elementBrowser != null) { _linkItems.Clear(); IUIAutomationElementArray arrayChildren = elementBrowser.GetCachedChildren(); if (arrayChildren != null) { int cElements = arrayChildren.Length; // Process each returned hyperlink element. for (int idxElement = 0; idxElement < cElements; idxElement++) { IUIAutomationElement elementChild = arrayChildren.GetElement(idxElement); // Take the same action elsewhere in the sample to present the hyperlink // in the sample app UI. string strLinkName = GetCachedDataFromElement(elementChild, fSearchLinkChildren); if (strLinkName != null) { strLinkName = strLinkName.Trim(); LinkItem item = new LinkItem(); item.linkName = strLinkName; item.element = elementChild; _linkItems.Add(item); } } // Notify the main UI thread that a list of links is ready for processing. Do not block in this call. _listViewLinks.BeginInvoke(_UIUpdateDelegate, _linkItems); } } } // Allow another refresh to be performed now. _fRefreshInProgress = false; }
private List <TextAttributeViewModel> GetTextRangeAttributeKeyValuePair(TextRange tr, KeyValuePair <int, string> kv, bool collapse) { List <TextAttributeViewModel> list = new List <TextAttributeViewModel>(); dynamic value = tr.GetAttributeValue(kv.Key); switch (kv.Key) { case TextAttributeType.UIA_AnimationStyleAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, AnimationStyle.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_BackgroundColorAttributeId: case TextAttributeType.UIA_ForegroundColorAttributeId: case TextAttributeType.UIA_OverlineColorAttributeId: case TextAttributeType.UIA_StrikethroughColorAttributeId: case TextAttributeType.UIA_UnderlineColorAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, string.Format("#{0:X8}", value))); } break; case TextAttributeType.UIA_BulletStyleAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, BulletStyle.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_CapStyleAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, CapStyle.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_CultureAttributeId: if (value is int culture) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, Invariant($"{CultureInfo.GetCultureInfo(culture).EnglishName} ({culture})"))); } break; case TextAttributeType.UIA_StyleIdAttributeId: case TextAttributeType.UIA_SayAsInterpretAsAttributeId: // VT_I4 if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, SayAsInterpretAs.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_FontNameAttributeId: case TextAttributeType.UIA_StyleNameAttributeId: case TextAttributeType.UIA_LineSpacingAttributeId: // VT_BSTR if (value is string) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, value)); } break; case TextAttributeType.UIA_FontSizeAttributeId: case TextAttributeType.UIA_IndentationFirstLineAttributeId: case TextAttributeType.UIA_IndentationLeadingAttributeId: case TextAttributeType.UIA_IndentationTrailingAttributeId: case TextAttributeType.UIA_MarginBottomAttributeId: case TextAttributeType.UIA_MarginLeadingAttributeId: case TextAttributeType.UIA_MarginTopAttributeId: case TextAttributeType.UIA_MarginTrailingAttributeId: case TextAttributeType.UIA_BeforeParagraphSpacingAttributeId: case TextAttributeType.UIA_AfterParagraphSpacingAttributeId: // VT_R8 if (value is double || value is long) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, value.ToString())); } break; case TextAttributeType.UIA_FontWeightAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, Axe.Windows.Desktop.Styles.FontWeight.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_HorizontalTextAlignmentAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, Axe.Windows.Desktop.Styles.FontWeight.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_IsHiddenAttributeId: case TextAttributeType.UIA_IsItalicAttributeId: case TextAttributeType.UIA_IsReadOnlyAttributeId: case TextAttributeType.UIA_IsSubscriptAttributeId: case TextAttributeType.UIA_IsSuperscriptAttributeId: case TextAttributeType.UIA_IsActiveAttributeId: if (value is bool) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, value.ToString())); } break; case TextAttributeType.UIA_OutlineStylesAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, OutlineStyle.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_OverlineStyleAttributeId: case TextAttributeType.UIA_StrikethroughStyleAttributeId: case TextAttributeType.UIA_UnderlineStyleAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, TextDecorationLineStyle.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_TabsAttributeId: var txt = ConvertArrayToString(value); if (txt != null) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, txt)); } break; case TextAttributeType.UIA_TextFlowDirectionsAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, Axe.Windows.Desktop.Styles.FlowDirection.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_AnnotationTypesAttributeId: StringBuilder sb = new StringBuilder(); if (value is double) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, AnnotationType.GetInstance().GetNameById((int)value))); } else if (value is Array arr) { if (collapse && arr.Length > 0) // collapse the array into a single row { var count = new Dictionary <string, int>(); foreach (var val in arr) { var key = AnnotationType.GetInstance().GetNameById((int)val); if (count.ContainsKey(key)) { count[key]++; } else { count[key] = 1; } } StringBuilder strBuild = new StringBuilder(); foreach (var item in count) { strBuild.Append(Invariant($"{item.Key}: {item.Value}, ")); } strBuild.Length -= 2; //remove final , and <space> list.Add(new TextAttributeViewModel(kv.Key, kv.Value, strBuild.ToString())); } else // create a row for each array value { if (arr.Length > 0) { for (int i = 0; i < arr.Length; i++) { list.Add(new TextAttributeViewModel(kv.Key, string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", kv.Value, i), AnnotationType.GetInstance().GetNameById((int)arr.GetValue(i)))); } } } } break; case TextAttributeType.UIA_SelectionActiveEndAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, ActiveEnd.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_CaretPositionAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, CaretPosition.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_CaretBidiModeAttributeId: if (value is int) { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, CaretBidiMode.GetInstance().GetNameById(value))); } break; case TextAttributeType.UIA_AnnotationObjectsAttributeId: if (value is IUIAutomationElementArray) { IUIAutomationElementArray arr = value; if (arr.Length > 0) { for (int i = 0; i < arr.Length; i++) { list.Add(new TextAttributeViewModel(kv.Key, string.Format(CultureInfo.InvariantCulture, Resources.TextRangeViewModel_GetTextRangeAttributeKeyValuePair_AnnotationObjects_0, i), new DesktopElement((IUIAutomationElement)arr.GetElement(i)))); } } } break; case TextAttributeType.UIA_LinkAttributeId: // do nothing for now until it is shown as necessary information. //try //{ // IUIAutomationTextRange lnk = Marshal.GetObjectForIUnknown(value) as IUIAutomationTextRange; // list.Add(new TextAttributeViewModel(kv.Value, new TextRangeViewModel(new TextRange(lnk)))); //} //catch (Exception e) //{ // e.ReportException(); //} break; default: // need to make a decision for these Attributes since it return Object. if (value.GetType().Name != "__ComObject") { list.Add(new TextAttributeViewModel(kv.Key, kv.Value, value)); } break; } return(list); }