im making a Coded UI test in Visual Studio 2010 for a web application in C# and i wish to click a button in the 6th column of a table based on the inner text of column 1? is this possible?
So for instance i have a table with Names in column one and other info and then a button in column 6. All auto generated.
Im assuming if i can get the Row number from the cell with say "John Smith" in it i can then press the button for this row in column 6.
Any ideas? i have tried googling and looking at what parameters i can pass in but im coming up stumped.
Something based on the following may help.
Access the HTML table by copying code from that generated by the Coded UI recorder for an assertion or a click on the cells. You should have something like:
HtmlCell theTable = new HtmlCell(this.UItheWindow.UItheTable.UIItemTable);
Cells of the table can be accessed by adding properties such as:
theTable.FilterProperties[HtmlCell.PropertyNames.RowIndex] = "0";
theTable.FilterProperties[HtmlCell.PropertyNames.ColumnIndex] = "6";
UITestControl cell = theTable.Find();
HtmlCell wantedCell = (HtmlCell)cell;
The above might be used as the body of a method returning the value of wantedCell. The name should now be available as:
wantedCell.InnerText;
Accessing the button to be clicked should follow a similar approach.
Another approach uses the GetChildren method to traverse the table. Start by getting theTable as above. Then have something like
UITestControlCollection children = theTable.GetChildren();
Loop through the children checking row properties. When the required row is found, call the GetChildren of that row and get the loop through them to find the required column. Some points: You may need to loop on columns before looping over rows. You may be able to directly index into the UITestControlCollection for the rows and the columns rather than needing to loop and check values. Depending on exactly how the table was written there may be additional levels between the table and the wanted cells, so you may need to examine children, grand children, great grand children, great great ..., and so on.
I have a couple of extension methods that I use to tackle content in tables(Hand coding, rather than using the recorder) -
This extension method for a table gets the first row in the table that contains the requested text in one of its cells or controls
public static HtmlRow GetRow(this HtmlTable table, string cellContent)
{
if((UITestControl)table == (UITestControl)null)
throw new ArgumentNullException("table");
if(cellContent.Length > 80)
cellContent = cellContent.Substring(0, 80); //Our table cells only display the first 80 chars
//Locate the first control in the table that has the inner text that I'm looking for
HtmlControl searchControl = new HtmlControl(table);
searchControl.SearchProperties.Add(PropertyNames.InnerText, cellContent);
//Did we find a control with that inner text?
if(!searchControl.TryFind())
{
//If not, the control might be an HtmlEdit with the text
HtmlEdit firstTableEdit = new HtmlEdit(table);
//Get all of the HtmlEdits in the table
UITestControlCollection matchingEdits = firstTableEdit.FindMatchingControls();
//Iterate through them, see if any have the correct text
foreach (UITestControl edit in matchingEdits)
{
if(cellContent == ((HtmlEdit)edit).Text)
searchControl = (HtmlControl)edit;
}
}
//We have(hopefully) found the control in the table with the text we're searching for
//Now, we spiral up through its parents until we get to an HtmlRow
while (!(searchControl is HtmlRow))
{
searchControl = (HtmlControl)searchControl.GetParent();
}
//The control we're left with should be an HtmlRow, and should be an Ancestor of a control that has the correct text
return (HtmlRow)searchControl;
}
Once you're able to get the correct row, it becomes relatively easy to get the correct control in that row(Or the correct control in a given cell in that row)
In your example, you've got a button in the 6th column of the row. The button probably has some properties associated with it, but even without them if we can correctly limit our search it will still work. Assume our table is named UITableCustomers - Declare a new button and limit it to only the 6th(Index 5) cell in the row containing "John Smith"
Mouse.Click(new HtmlInputButton(UITableCustomers.GetRow("John Smith").Cells[5]));
Obviously, this call is going to fail if the given text doesn't exist in a control in the table.
Your question is not very clear to me but check out the documentation on jQuery.trigger
This method will let you emulate a clickevent. I hope this is what you need.
Related
I'm having trouble trying to figure out why accessing row 0, col 3 on an HTML table isn't working. I'm using C# and Visual Studio.
While debugging if we let it pass by once and then set it back to the same line that grabs it as a variable then it would work. But never the first time through, if I went for row 1, col 3, being the next cell down one, it would grab it fine and so on with any others except for row 1 (being index 0).
Segments of the code are as follows, but we couldn't figure out why it wasn't working on specifically the first row, we even tried adding a delay to make sure the page was fully loaded and still wasn't returning any value. To remind you, it worked on every row but the first, even when the item in the first row was changed. The item in the first row, fourth col will always be changing so there is no specific class or identifier I can just access it by every time.
Any clue why it's not working for the first row and any fixes would be greatly appreciated. I have a work around, but it would just be easier to do it like this:
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
var browser = BrowserWindow.Launch("https://blah.com/");
var cell = GetCell(browser, 2, 3);
Console.WriteLine(cell.Value.ToString());
HtmlCell GetCell(UITestControl parent, int row, int column)
{
var cell = new HtmlCell(parent);
cell.SearchProperties.Add(HtmlCell.PropertyNames.RowIndex, row.ToString());
cell.SearchProperties.Add(HtmlCell.PropertyNames.ColumnIndex, column.ToString());
return cell;
}
Allen,
You may want to make sure that the header row of your table is of the same form as the remaining rows.
You are correct that row indexes start at 0.
You may want to try creating a debugging method. Remember that a cell is a child of a row. Pass in a table as a ui parent object and iterate through each row, then iterate through each cell and see what the debugger is showing you as values for these objects (including their types).
My suspicion is it'll be something to do with the header structure or that a element has a different object type than rather than HtmlCell
Environment: Web Development in Visual Studio
Language: ASP.NET
I'm afraid I already know the answer, but it can't hurt to ask. I have an application that gets data from SAP and can return specific results or a list of possible results for each row of a DataGridView. So the user might enter "abcd" and get "1234" as a result or he might get "1234 or 2345 or 3456" as a result. For each row I would like to have each column where multiple results were returned as a combobox. The rest should stay fixed though, since having the table littered with comboboxes that only have one result would be annoying.
Is there any trick to do this? I know you can "convert" an entire column into a column of comboboxes using DataGridViewComboBoxColumn like in this blog:
http://mytactics.blogspot.de/2014/01/convert-datagridview-column-to-combo-box.html
.Is there any way to have a combobox only for specific cells though? I know I could put a combobox next to each row of the table and let the user choose from that one or I could have a combox in every single row and maybe lock the ones with only one result. I'm not happy about either of those solutions though.
You can try and add a ComboBox to yourDataGridViewCell.Controls and make the label.Visible = false; or remove it. It would be something like:
yourDataGridViewCell.Controls.Clear();
yourDataGridViewCell.Controls.Add(new ComboBox());
yourDataGridViewCell.Controls[0].DataSource = yourList;
//set the value member etc.
I'd like to get a grid with ability to add subheader (one or several rows) according to value of certain column (data source is grouped sorted by this column). Within my inherited GridView I override OnRowDataBind method: If value of considering column on current call of OnRowDataBind is not equal to previous values, then special header row is inserted before current row.
Table tbl = this.Controls[0] as Table; //this - pointer to CustomGridView
tbl.Controls.AddAt(rowIndex + add_counter + 1, NewSubHeaderRow); /*rowIndex - RowIndex of current row, add_counter - amount of already added SubHrader rows */
All works right. But problem occures on postback, when GridView restores it's state. First row and all its controls into every group (other words, first row after each dynamically added subheader row) comes without any attributes. But second row in group keeps both its own attributes and attributes of first row.
Some help will be very usefull. Maybe there is another (and right) way to add row into GridView. Then please, provide me with links to tutorials or articles.
Dynamic controls disappear on postback because on postback framework doesn't have information about such controls. It's programmer's responsibility to keep track of these dynamic controls and recreate them after postback...
Please refer to following post for re-creating dynamic controls on postback:
FAQ: Why do dynamic controls disappear on postback
Thanks for Waqas.
Here is my decision.
I override CreateChild(datasource, isBinding) and create list where put index of row, before which you should add subheader row. On SaveViewState i add this list to sealized object. On Load ViewState i load this list and if it's not null create subheader rows by saved indexes.
Maybe, there is a simpler and more natural way. But it's hidden from me securely )))
I'm constructing a GUI that allows the user to manipulate XML data. A helpful fellow named Peter was able to point me to a direction leading me to question why my cell values were null even when the user selects a value in the combobox.
I've read up on a few things: the comboboxcolumn's value member, display member, data source, and datapropertyname. I've figured out what display and value members do, but decided to stick with a data source so I wouldn't have to specify a display member and value member; I believe it made things easier and plus the choices in the combobox are stored in a string array.
The premise is, the user enters in choices into a rich text box. Then, the textbox is read line by line and every line becomes a choice in the combo box. I then create a new combobox column in the datagridview and the choices are available for the user to choose. After the user is done, I have a button called "save with combo column..." which creates a new datacolumn in the datatable that the datagridview is displaying and I try to copy the values over via this code: (since I cannot directly merge the combobox column with a datatable)
int size = dataGridView1.Rows.Count - 1;
DataColumn column = new DataColumn(combo.HeaderText);
data_set_array[(int)IndexNumber.Value].Tables[(int)TableNumber.Value].Columns.Add(column);
for (q = 0; q < size; q++)
{
data_set_array[(int)IndexNumber.Value].Tables[(int)TableNumber.Value].Rows[q][combo.HeaderText] = dataGridView1["combo", q].Value;
}
when that is all said and done, the new column is created and a message is displayed. However, the datatable's values are null, which means the cell values are also null. This implies that the item that the user selected in the combo box wasn't copied over to the cell value. What am I doing wrong? I set the datasource to the string of arrays where the strings are the user's choices for the combobox, and yet when the I selected choices from the combobox and tried to save it, the values are null. I also read that I did not need to worry about value member or display member since setting the datasource would provide me valid display text and valid values.
If any additional information is needed please ask. Thanks in advance.
.NET 3.5 SP1, Visual Studio 2008 C#.
Sincerely,
tf.rz
I am not sure
However I think you will find that the datarows have been created using the old column definitions.
when you add a new column i doubt it is resizing the arrays for each row to add a column.
Although if this was true i would expect an index out of range exceptions.
you need to break that big line of code up so so that it is easier to debug.
IE when you leave the loop does the cell have the value you expect? Or has the assign failed?
It will tell you where things are going wrong.
If it is assigning then you lose the data later then you need to expand your search (this could happen if you have somehow assumed a value type was a reference type for instance)
you may finid you need to create a new data table with the correct column definitions and then copy the old data into the new one ... but first you need to establish where it is failing - you are currently doing too much in 1 line of code.
Are you sure the value syou are getting from the combo box are not null?
So I have an <asp:Gridview> and in my C# file, I am setting the datasource to some database table, and doing .DataBind().
However, I want to hide a column in the table based on a Boolean variable.
Something like this:
gridview.Columns['Field5'].Visible = false;
Or perhaps:
int c = gridview.Rows.Count();
for(int i = 0; i < c; i++){
gridview.Rows['Field5'].Remove();
}
Perhaps I cannot make it invisible, but I'm sure I can at least loop through and remove all rows related to the column "field5". I don't know how to go about doing this.
Does anyone perhaps have a proper link to using the GridView Class and how all the methods are suppose to be used because it's not clear, perhaps not written by microsoft?
Sorry if this is simplistic, the internet seems to lack a lot of C# documentation (or maybe it's just cluttered with too much useless ASP.net information).
No problem, the trick is that you have to reference the column by its index, not its name.
grid.Columns[1].Visible = false;
In your case you should loop through gridview and set cells you want to hide Visible=false
foreach (GridViewRow gvr in gv.Rows)
{
//here specify cell you want to hide
//also you may put any conditions
gvr.Cells[0].Visible = false; // Hide cell
}
To hide column you should go like that:
//here specify column you want to hide
grv.Columns[0].Visible = false; // Hide column
Also check this article http://www.codeproject.com/KB/webforms/Datagrid_Col_Example.aspx
I found a good method for doing something like that.
((DataControlField)gridView.Columns
.Cast<DataControlField>()
.Where(fld => (fld.HeaderText == "Title"))
.SingleOrDefault()).Visible = false;
I found it in below link
GridView Hide Column by code
The gridview is fine if you just want to quickly display some data, but don't need to modify it in any way. However if you do want to customize it, it is unpractical. It is easier and faster to build the table dynamically in your codebehind and you get all of the control you need.
Check out the first answer to this post: How to show pop up menu from database in gridview on each gridview row items?