I expect to get a row count on the first page of 100 and examine each row once. Instead, I get a row count of ~120 (it changes between runs) and several rows seem to appear twice and/or out of order. For example, the last row I print out is "83, Maxilaku, $45.60, 5/12/2008, ". How can I accomplish my goal of examining each and every row of the current RadGridView page in the order they appear in the grid and once and only once?
I am using Test Framework 2011.2.928.0 and Silverlight 4.0.60831.0.
My code follows.
Thanks,
Ken
[Test]
public
void
SampleWebAiiTest()
{
Settings.Current.Web.EnableSilverlight =
true
;
// Launch a browser instance
Manager.LaunchNewBrowser(BrowserType.InternetExplorer);
// The active browser
ActiveBrowser.NavigateTo(
"http://demos.telerik.com/silverlight/#GridView/PagingLargeData"
);
SilverlightApp app = ActiveBrowser.SilverlightApps()[0];
int
verticalOffset = 0;
// Holds the current vertical offset in the viewport
int
viewPortHeight;
// The height of the visible part of the grid
int
extentHeight;
// The total height of the grid, visible plus non-visible
// Copy the RadGridView into a local variable as a shortcut
RadGridView grid = app.Find.ByAutomationId<RadGridView>(
"GridView"
);
// Grab the VirtualizingPanel contained in the RadGridView. This is used to control the viewable portion of the grid.
FrameworkElement virtualizingPanel = grid.Find.ByType(
"GridViewVirtualizingPanel"
);
// Detect the view port height and the extent height
viewPortHeight = (
int
)virtualizingPanel.GetProperty(
new
AutomationProperty(
"ViewportHeight"
,
typeof
(
int
)));
extentHeight = (
int
)virtualizingPanel.GetProperty(
new
AutomationProperty(
"ExtentHeight"
,
typeof
(
int
)));
// Make sure it is scrolled to the very top
// Walk through the entire grid verifying the data
virtualizingPanel.InvokeMethod(
"SetVerticalOffset"
, 0);
int
index;
int
totalCount = 0;
string
rowText;
while
(verticalOffset < extentHeight)
{
foreach
(GridViewRow r
in
grid.Rows)
{
totalCount++;
index = r.Index;
rowText =
string
.Join(
", "
, r.Cells.Select(item => item.Text));
}
// Scroll down one page
verticalOffset += viewPortHeight;
virtualizingPanel.InvokeMethod(
"SetVerticalOffset"
, verticalOffset);
}
}
7 Answers, 1 is accepted
One important detail to making your loop work properly is that you need to refresh your grid object after you scroll the container. Otherwise you're dealing with a stale grid object. I put together a complete sample as a coded step in a Test Studio test. You can take and and work it into an NUnit test:
[CodedStep(@
"New Coded Step"
)]
public
void
CountAllRows_CodedStep()
{
int
verticalOffset = 0;
// Holds the current vertical offset in the viewport
int
viewPortHeight;
// The height of the visible part of the grid
int
extentHeight;
// The total height of the grid, visible plus non-visible
SortedDictionary<
int
,
string
> data =
new
SortedDictionary<
int
,
string
>();
// Copy the RadGridView into a local variable as a shortcut
ActiveBrowser.RefreshDomTree();
RadGridView grid = ActiveBrowser.SilverlightApps()[0].Find.ByAutomationId<RadGridView>(
"GridView"
);
// Grab the VirtualizingPanel contained in the RadGridView. This is used to control the viewable portion of the grid.
FrameworkElement VirtualizingPanel = grid.Find.ByType(
"GridViewVirtualizingPanel"
);
// Detect the view port height and the extent height
viewPortHeight = (
int
)VirtualizingPanel.GetProperty(
new
AutomationProperty(
"ViewportHeight"
,
typeof
(
int
)));
extentHeight = (
int
)VirtualizingPanel.GetProperty(
new
AutomationProperty(
"ExtentHeight"
,
typeof
(
int
)));
// Make sure it is scrolled to the very top
VirtualizingPanel.InvokeMethod(
"SetVerticalOffset"
, 0);
// Walk through the entire grid scraping the data
while
(verticalOffset < extentHeight)
{
// Since the data can appear out of order, we need to sort it
foreach
(GridViewRow row
in
grid.Rows)
{
int
rowNum =
int
.Parse(row.Cells[0].Text);
if
(!data.ContainsKey(rowNum))
{
data.Add(rowNum, row.Cells[1].Text);
}
}
// Scroll down one page
verticalOffset += viewPortHeight;
VirtualizingPanel.InvokeMethod(
"SetVerticalOffset"
, verticalOffset);
grid.Refresh();
}
// Display the data we gathered
foreach
(KeyValuePair<
int
,
string
> kvp
in
data)
{
Log.WriteLine(kvp.Key.ToString() +
", "
+ kvp.Value);
}
}
Kind regards,
Cody
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Do you know if the data in one of the columns will be unique? Do you care whether or not the extracted data is in the same sorted order as displayed in the grid? The solution is pretty easy if you can answer Yes & No to the preceding questions.
The technical complication is that the order of the rows in Grid.Rows is not necessarily the same visual order. Under the covers Silverlight does some magic mapping the .Rows collection to the actual visually displayed order.
Also as you scroll through the data Silverlight has a bad habit of duplicating data in the .Rows collection which can cause duplicates during the extract process (which is why I inserted the if (!data.ContainsKey(rowNum)) line of code). Finally if the last scroll is only a partial row you'll still have N rows in the .Rows collection and have to figure out which are and are not duplicates.
If you have a guaranteed unique value you can use that value as the key when you push it into the dictionary. Also, if the sorting order does not matter, instead of using a SortedDictionary, you can use a simple Dictionary object.
On the other hand if all the data can be random AND you do care about the sorting order, there is a way to scrape it, but it gets complicated very quickly. If you really need this, let me know but give me about 3 days to put it together (along with my other work load).
Cody
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Thanks for working with me on this. I've got good news and bad news... :)
1) "Do you know if the data in one of the columns will be unique?"
I think for our application in particular, we can take the text from each column and hash them together and get a unique value to meet this assumption. I would like to test to ensure there aren't any duplicate rows in the data, but we can probably cover that test case through testing the backend services directly and our silverlight unit tests.
2) "Do you care whether or not the extracted data is in the same sorted order as displayed in the grid?"
It is important to get data out of the grid in the order they are displayed. We have some custom sort scenarios and I don't believe there is any other way to ensure the rows are sorted properly. As you say, Silverlight determines the display order and our data container wouldn't have any idea what the display order is for each row.
So, yes, I would be highly interested in your ideas, complicated or not.
Just to give you background on the purpose of our efforts, we are investigating Behavioral Driven Design techniques through use of SpecFlow and some automation of the UI. I'm trying to drive the UI for specific user scenarios, and ran into this difficulty in getting the data out of the grid. In the end, I'd like to determine what the data is and take further action based on the data, most likely selecting a specific row based on the contents, etc.
I have contemplated other ways to accomplish the need to extract data from the grid. My latest idea is develop a custom AutomationPeer for the grid. This would require us to derive a new control based on the RadGridView simply to override OnCreateAutomationPeer. The difficulty here is the RadGridViewAutomationPeer is sealed (I've never understand why people do this; in my mind, it goes against the spirit of the open-closed principle). I would need to wrap it or reimplement it's functionality. Both approaches are risky and something I would prefer not doing.
We will need to do the same thing for the RadTreeListView. I haven't yet begun to automate that part of our application but I assume the same difficulty would be encountered.
Again, thanks for your help.
Ken
Yes you've got it... the index order of grid.Rows does not necessarily equal the display order in a Silverlight virtualized container (listboxes, grids, etc.). The display order of grid.Rows may easily be something like:
14,16, 17, 18, 19, 13, 11,12;
To overcome this you'll need to use get the actual display position of the row. Fortunately every element in Silverlight has the GetIntRectangle() function. This function returns a System.Drawing.Rectangle object representing the actual bounding rectangle of the current screen coordinates of that rectangle. Using this data returned by this function you can determine the display order on the screen.
The last complication is handling the bottom most part of the rows. The problem here is the nature of scrolling itself. At scroll n-1 you'll have rows displayed like:
78,79,80,81,82
And then since you may be scrolling only a partial size of the view height, at the very bottom you'll have repeat rows like:
80,81,82,83,84,85
You'll have to implement smarts in the code to not include the duplicates being displayed during your scan. You might try to take advantage of the .Height property each Silverlight element has, which is the height in pixels of the element. You can use that to to get the height of an individual row and calculate what you've already done, and what portion of the screen is left to do.
Those are my pointers to get you started.
Cody
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.

On a related note, UISpy displays all 100 row elements as children of the GridViewVirtualizingPanel. All are of type ControlType.DataItem, and the 20 that the Telerik test framework says are there are of ClassName GridViewRow. I'm not seeing how to get all of the child elements that UISpy says are there. Does the framework provide a way to get to all of the elements? Or does it restrict me to just the 20 visible ones? I'm hoping if I can access the full collection of 100 children that I could use that as the true total count on that page.
Thanks,
Ken
You got me curious with your comment about UISpy. What I discovered is:
1) It's using the Active Accessibility model
2) UISpy has been replaced by Inspect
3) Even though you can see how many rows there are, you still cannot see the data in those rows as you can see in the attached screenshot. You still only get 20 usable rows of data.
Cody
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.