After trying out several solutions, I am in desperate need for help.
I tried several approaches, before finally copying and still being stuck with the solution from Getting full contents of a Datagrid using UIAutomation.
Let's talk code, please consider the comments:
// Get Process ID for desired window handle
uint processID = 0;
GetWindowThreadProcessId(hwnd, out processID);
var desktop = AutomationElement.RootElement;
// Find AutomationElement for the App's window
var bw = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ProcessIdProperty, (int)processID));
// Find the DataGridView in question
var datagrid = bw.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "dgvControlProperties"));
// Find all rows from the DataGridView
var loginLines = datagrid.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem));
// Badumm Tzzz: loginLines has 0 items, foreach is therefore not executed once
foreach (AutomationElement loginLine in loginLines)
{
var loginLinesDetails = loginLine.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));
for (var i = 0; i < loginLinesDetails.Count; i++)
{
var cacheRequest = new CacheRequest
{
AutomationElementMode = AutomationElementMode.None,
TreeFilter = Automation.RawViewCondition
};
cacheRequest.Add(AutomationElement.NameProperty);
cacheRequest.Add(AutomationElement.AutomationIdProperty);
cacheRequest.Push();
var targetText = loginLinesDetails[i].FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "TextBlock"));
cacheRequest.Pop();
var myString = targetText.Cached.Name;
}
}
I can neither fetch a GridPattern
, nor a TablePattern
instance from datagrid
, both results in an exception:
GridPattern gridPattern = null;
try
{
gridPattern = datagrid.GetCurrentPattern(GridPattern.Pattern) as GridPattern;
}
catch (InvalidOperationException ex)
{
// It fails!
}
TablePattern tablePattern = null;
try
{
tablePattern = datagrid.GetCurrentPattern(TablePattern.Pattern) as TablePattern;
}
catch (InvalidOperationException ex)
{
// It fails!
}
The rows were added to the DataGridView
beforehand, like this:
dgvControlProperties.Rows.Add(new object[] { false, "Some Text", "Some other text" });
I am compiling to .Net Framework 4.5. Tried both regular user rights and elevated admin rights for the UI Automation client, both yielded the same results described here.
Why does the DataGridView
return 0 rows?
Why can't I get one of the patterns?
Kudos for helping me out!
Update:
James help didn't to the trick for me. The following code tough returns all rows (including the headers):
var rows = dataGrid.FindAll(TreeScope.Children, PropertyCondition.TrueCondition);
Header cells can then be identified by their ControlType
of ControlType.Header
.
Your code looks fine though this could be a focus issue.
Even though you are getting a reference to these automation element objects you should set focus on them (using the aptly named SetFocus method) before using them.
Try:
and if that does not work try explicitly focusing on the dataGrid prior to calling "FindAll" on it i.e.
I run into this problem too, after researching, i figured out that you can only access data grid view with
LegacyIAccessible
. However, .NET does not support this. So, here are the steps:=> as said here, using
tblimp.exe
(go along with Windows SDK) to generate a COM wrapper around the unmanaged UIA API, so we can call from C#.I have done it here
Inspect.exe
to see.The code is:
Why does the DataGridView return 0 rows?
The DataGridViewRows have a ControlType of ControlType.Custom. So I modified the line
To
That gets you all the rows within the DataGridView. But your code has that within the loop.
What pattern is supported by DataGridView (not DataGrid)?
LegacyIAccessiblePattern. Try this-
As I commented on @James answer, there is no support for UIA for DataGridView (again, not DataGrid).
If you search in google with terms: "UI Automation DataGridView" the first result has an incomplete answer. Mike replies with what provider class (Obviously one that extends DataGridView)to create within the source, unfortunately I have no clue as to how to make UIA load that class a provider. If anyone can shed some clues, Phil and I will be extremely pleased!
EDIT
Your DataGridView should implement the interfaces in that link above. Once you do that the ControlType of Row will be ControlType.DataItem instead of ControlType.Custom. You can then use it how you'd use a DataGrid.
EDIT
This is what I ended up doing -
Creating a Custom DataGridView like below. Your datagridview could subclass this too. That will make it support ValuePattern and SelectionItemPattern.
The complete code can be found @ this msdn link.
Once I did that, I played a bit with visualUIVerify source. Here is how I can access the gridview's cell and change the value. Also, make note of the commented code. I didn't need that. It allows you to iterate through rows and cells.
Hopefully this helps.
The code that you are copying is flawed. I just tested this scenario with an adaptation of this sample program factoring in your code above, and it works.
The key difference is that the code above is using
TreeScope.Children
to grab the datagrid element. This option only grabs immediate children of the parent, so if your datagrid is nested it's not going to work. Change it to useTreeScope.Descendants
, and it should work as expected.Here is a link to how the various Treescope options behave. Also, I don't know how your binding the rows to the grid, but I did it like this in my test scenario and it worked flawlessly.
Hopefully this helps.