Activate tab in TabControl that was retrieved as AutomationElement - c#

I used the UIAutomationClient API to retrieve an AutomationElement t:
AutomationElement t = AutomationElement.RootElement.FindFirst(...);
The WPF counterpart of t is a TabItem inside a TabControl. I want to activate the tab that t represents (i.e. bring t into foreground). How do I do that?
I tried t.SetFocus();, but it did not have any (visible) effect at all.
If I had the TabItem (let's call it tabItem), I would just call
tabItem.IsSelected = true;
So I thought by using the select pattern I could achieve the same:
var p = t.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
p.Select();
It turned out that the IsSelected property of p already is true prior to selecting it - so calling Select still does not select/activate the tab. But in the GUI, the TabItem is clearly not selected/activated.

I encountered the same problem, This is my solution below hope it helps even though it's already late.
Example UI:
Sample Code:
AutomationElement aeDesktop = AutomationElement.RootElement;
AutomationElement aeForm = aeDesktop.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "davinceleecode"));
AutomationElement aeTabControl = aeForm.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "tabControl1"));
aeTabControl.SetFocus();
AutomationElement aeTabPage = aeTabControl.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "tabPage2"));
SelectionItemPattern changeTab_aeTabPage = aeTabPage.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
changeTab_aeTabPage.Select();
Please check the IsKeyboardFocusable properties and make sure this is set to true.

Related

Is there a way to find an item in a System.Windows.Forms.FolderBrowserDialog using AutomationElement.FindFirst?

I'm trying to use automation to find a tree item in an instance of a WinForms FolderBrowserDialog
I show the dialog in one process and then call the following in another test process:
var dlg = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Browse For Folder"));
var treectrl = dlg.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "SHBrowseForFolder ShellNameSpace Control"));
var treeview = treectrl.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "SysTreeView32"));
var item = treeCtrl.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "Desktop"),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TreeItem)));
dlg, treectrl, and treeview come back with valid AutomationElements but item ends up being null even though, when I use the Inspect app, it shows that item with the name "Desktop" as an immediate child of the treeview.
When I tried to use a TreeWalker to walk through the tree control children, all I see are the scrollbar and its children.
Is there something else I need to do to be able to find tree items in a shell tree control?

Must disconnect specified child from current parent Visual before attaching to new parent Visual

I'm new to WPF and trying to build my first application which is multiviewer of multi streams together for learning purpose.
I have 24 multimedia element on the main window and I want to Fullscreen selected multimedia element when there will be one more click to minimize this full screened media.
Code is like this
foreach (var item in MediaElements)
{
item.LoadedBehavior = MediaState.Manual;
item.MouseEnter += mediaElement1_MouseEnter;
item.MouseLeave += mediaElement1_MouseLeave;
item.Loaded += mediaElement1_Loaded;
item.MouseLeftButtonUp += (o, args) =>
{
if(!fullscreen)
{
ListOfMedia.Children.Remove(item);
this.Content = item;
this.WindowStyle = WindowStyle.None;
this.WindowState = WindowState.Maximized;
}
else
{
this.Content = ListOfMedia;
ListOfMedia.Children.Add(item);
this.WindowStyle = WindowStyle.SingleBorderWindow;
this.WindowState = WindowState.Normal;
}
fullscreen = !fullscreen;
};
}
When I click it the first time, it's working very well, the window is going on maximum screen size, but when I'm clicking it on next time to minimize it, there is an exception which is saying to me
System.ArgumentException: 'Must disconnect specified child from current parent Visual before attaching to new parent Visual.'
I checked some StackOverflow questions but can't find the correct solution, someone was talking about extension method to delete children from parents tree, I wrote this extension method but I don't know what is the problem and what idea is behind this problem? What I must delete from and what is happening at all.
Please tell me what is happening here.
The whole idea is that if an element already has a logical parent, then you cannot assign it as another elements child.
Imagine the following set up:
CtCtrl = ContentControl
StPnl = StackPanel
br1 = Border
if(CtCtrl.Content != null)
{
var br1 = CtCtrl.Content as Border;
StPnl.Children.Add(br1);
}
The above will result in System.InvalidOperationException:'Specified element is already the logical child of another elelemt. Disconnect it first.'
You can easily orphan that element before adding it to the StackPanel by the following code:
if(CtCtrl.Content != null)
{
var br1 = CtCtrl.Content as Border;
CtCtrl.Content = null;
StPnl.Children.Add(br1);
}
And the exception will be gone!

Find a windows control using partial NameProperty in windows automation

I'm trying to identify a windows static text control using a partial NameProperty. Here's the code I have:
// Get a reference to the window
AutomationElement epoWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "MsiDialog"));
// Get a reference to the control
AutomationElement epoControl = epoWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, controlText));
I currently need the full controlText string for this to work but I'd like to search for a part of that string and return any controls found.
How do I do this?
Thanks,
John
You can iterate on a child collection with the prefefined TrueCondition, like this:
foreach(AutomationElement child in epoWindow.FindAll(TreeScope.Subtree, Condition.TrueCondition))
{
if (child.Current.Name.Contains("whatever"))
{
// do something
}
}
PS: You want to carefully choose the TreeScope if you don't want to kill the performance of your app (if it has a big children hierarchy) or wait indefinitely...

Get Firefox URL with UI Automation

I am trying to get the value of the URL in Firefox using the following code. The problem is it only returns "Search or enter address" (see tree structure with Inspect.exe below). It looks like I need to go one level down. Can someone show me how to do this.
public static string GetFirefoxUrl(IntPtr pointer) {
AutomationElement element = AutomationElement.FromHandle(pointer);
if (element == null)
return null;
AutomationElement tsbCtrl = element.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Search or enter address"));
return ((ValuePattern)tsbCtrl.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}
For the tree structure, see:
It's not clear which element you are starting the search from, but you've got two elements with that name. One is a combo box control the other is an edit control. Try using using an AndCondition to combine multiple PropertyCondition objects:
var nameCondition = new PropertyCondition(AutomationElement.NameProperty, "Search or enter address");
var controlCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
var condition = new AndCondition(nameCondition, controlCondition);
AutomationElement editBox = element.FindFirst(TreeScope.Subtree, condition);
// use ValuePattern to get the value
If the search starts from the combo box, you could instead change TreeScope.Subtree to TreeScope.Descendants since Subtree includes the current element in the search.

Funky results when using UI Automation to get items in a ComboBox

We are using the code below to get a list of items out of a ComboBox inside another application's window. This code works (correctly retrieves the list of items) for ComboBoxes in any other application we've tested this code on, however for this particular application the Name property retrieved for each ListItem is garbled.
Here is the code:
using System.Windows.Automation;
var condition = new PropertyCondition(AutomationElement.NameProperty, "Change/Add/Delete Setting");
var condition2 = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
var condition3 = new AndCondition(new Condition[] {condition, condition2});
var window = AutomationElement.RootElement.FindFirst(TreeScope.Subtree, condition3);
condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox);
var combo = window.FindFirst(TreeScope.Subtree, condition);
condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem);
AutomationElementCollection children = combo.FindAll(TreeScope.Subtree, condition);
var comboItems = new List<string>();
foreach (AutomationElement child in children)
{
comboItems.Add(child.Current.Name);
}
And here is a screenshot of what we end up with for this one app.
What could cause the Name property to be garbled like this? Could this be an encoding problem?
How can we get the correct text for each item?
If this combobox has the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style, or the contained listbox has the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style. then the text isn't known by the control at all. When an app uses one of these styles, it gets WM_DRAWITEM messages whenever the control needs to draw, then it pulls the text from it's pocket and draws it wherever it was asked to.
This is a trick that allows an application to quickly and easily change the contents of a listbox or combobox on the fly, it's mostly used when the contents are volatile or when there are LOTS of items. It's one way to get around the limit on the number of items an listbox/combobox can hold.
Use Spy++ to check the styles on these windows.

Categories