This is a migrated thread and some comments may be shown as answers.

Iterating over rows in RadGridView

7 Answers 321 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Ken
Top achievements
Rank 1
Ken asked on 03 Nov 2011, 09:42 PM
I need to iterate over the rows of a Silverlight RadGridView checking for duplicates and the total count.  I adapted the sample from http://www.telerik.com/automated-testing-tools/support/documentation/user-guide/write-tests-in-code/code-samples/silverlight/radgridview/scrolling.aspx.  I test against the telerik sample page here: http://demos.telerik.com/silverlight/#GridView/PagingLargeData.

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

Sort by
0
Cody
Telerik team
answered on 09 Nov 2011, 08:42 AM
Hi Ken,

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.
0
Ken
Top achievements
Rank 1
answered on 09 Nov 2011, 06:33 PM
Thank you Cody, that helps, but doesn't get me all the way there.  The example you show relies on the fact that the data row number is contained within one of the columns of the grid.  In the actual product I'm trying to automate, the row numbers are not displayed.  Any thoughts on how to accomplish my goal without displaying row numbers?
0
Cody
Telerik team
answered on 09 Nov 2011, 11:05 PM
Hi Ken,

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).

Kind regards,
Cody
the Telerik team

Check out Telerik Trainer, the state of the art learning tool for Telerik products.
0
Ken
Top achievements
Rank 1
answered on 10 Nov 2011, 05:02 PM
Hi Cody,

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
0
Accepted
Cody
Telerik team
answered on 10 Nov 2011, 06:10 PM
Hello 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.

Kind regards,
Cody
the Telerik team

Check out Telerik Trainer, the state of the art learning tool for Telerik products.
0
Ken
Top achievements
Rank 1
answered on 11 Nov 2011, 07:06 PM
Didn't think of the GetIntRectangle. (Didn't even realize it was there)  That'll get me where I need to go, Thanks!

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
0
Cody
Telerik team
answered on 12 Nov 2011, 12:29 AM
Hi 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.

Kind regards,
Cody
the Telerik team

Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Tags
General Discussions
Asked by
Ken
Top achievements
Rank 1
Answers by
Cody
Telerik team
Ken
Top achievements
Rank 1
Share this question
or