Find element after page reload - c#

Ok this one got me hitting my head on the wall for a while now.
I look at a list of web elements. I access that list like so
foreach (IWebElement link in driver.FindElementsByCssSelector("span.cn.mailbox > a"))
{
// Click at a lot of page and the page will reload eventually
}
The problem is, inside the loop, I need to change pages and stuff but at the end I get back to that page that has the link list.
As soon as I hit the second iteration, I get the following error :
Probably because I changed page and even thought the links in the collection I loop through are the same, the compiler doesn't seem to think it's the exact same collection.
Is there a way around this or a workaround I could use ?

The reason you're getting the exception is because the page the driver.FindElementsByCssSelector is referencing has been reloaded.
Something like this should work:
Create an array of link text. Iterate through the link text array, clicking each link.
string [] links = new string[driver.FindElementsByCssSelector("span.cn.mailbox > a").Count);
int i = 0;
foreach (IWebElement link in driver.FindElementsByCssSelector("span.cn.mailbox > a"))
{
links[i++] = link.Text;
}
for (int i = 0; i < driver.FindElementsByCssSelector("span.cn.mailbox > a").Count; i++)
{
driver.FindElementByLinkText(links[i]).Click();
}

Related

how to break out of a loop when a page is reloading

I have this code below where it goes through all of the links in a panel and once it is able find the relevant link, it will click it. The problem I have though is that when I select the link, the page reloads before it shows a new page. So I thought of adding a break to break out of the loop because if I don't add this, then it will give me a element is not attached to document error. I believe this error occurs because it is still trying to loop through the links whilst the page is reloading.
However, when adding the break and running the test, nothing happens as in it doesn't select a link. How can I break out of the loop after clicking the link?
I don't need to go back to the loop after the page has reloaded, I simply want to break out of the loop because the loop has done its job in finding the link and clicking.
public void SelectHomepageSearchPanelLink(string linkText)
{
var searchPanelLinks = _driver.FindElements(HomepageResponsiveElements.HomepageSearchPanelLinks);
foreach (var searchPanelLink in searchPanelLinks)
{
if (searchPanelLink.Text == linkText)
{
searchPanelLink.Click();
break;
}
else
{
throw new Exception($"{linkText} link not found by the responsive homepage search panel");
}
}
}
Try this:
public void SelectHomepageSearchPanelLink(string linkText)
{
var searchPanelLinks = _driver.FindElements(HomepageResponsiveElements.HomepageSearchPanelLinks);
var linkToClick;
foreach (var searchPanelLink in searchPanelLinks)
{
if (searchPanelLink.Text == linkText)
{
linkToClick = searchPanelLink;
break;
}
else
{
throw new Exception($"{linkText} link not found by the responsive homepage search panel");
}
}
linkToClick.Click();
}

WinForms Control Not working

I am trying to read in the first description in the first row. However, for some reason my if statement is never becoming true. Here is the html code that has the class im trying to read from. I gave a picture of it. Below that is the actual code im running. There is a first page that I login to and then input the part number. This then takes me to this page where you see the html code in the picture. I then need to grab the description of the part number. I included a picture of the website I am grabbing the description from. In order to give you a better Idea of what's happening. Also, I have a web browser component in my code that I am using. Can you point out why its not working? Thanks.
var secondPage = webBrowser1.Document;
foreach (HtmlElement element in secondPage.All)
{
if (element.GetAttribute("className") == "SE-Content-PartSearch-Grid-Row-Description")
{
messagebox.Show("Found it");
}
}
ActualWebsite
HTMLCODE
I suggest that you put a breakpoint on the "if" statement. It will perhaps be easier to see what is going on if you modify the code slightly:
var secondPage = webBrowser1.Document;
foreach (HtmlElement element in secondPage.All)
{
String className = element.GetAttribute("className");
if (className == "SE-Content-PartSearch-Grid-Row-Description")
{
messagebox.Show("Found it");
}
}

Difficulty with tabControl/tabitem refresh

I have a WPF window with a maintabWindow and several tabitems.
It normally works fine and the layout is this:
but when I BEFORE add the following window:
the result is this:
So the problem is related with the tabControl/tabItem refresh.
This is fairly obvious but even more because if I move the window or pass with the mouse on the a tabItem they get refreshed one by one.
I searched and found that here is a solution: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx
so I added:
this.MainTab.Refresh();
this.tabItem1.Refresh();
this.tabItem2.Refresh();
this.tabItem3.Refresh();
this.tabItem4.Refresh();
this.tabItem5.Refresh();
but that didn't change a thing.
Thanx for any help
Ok so in the end it has a quite a weird behavious. If I do
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
it works. But I have to set the 1st tabitem so if I add
tbcMain.SelectedIndex = 0;
it doesn't.
So the solution was put a sleep and it works again.
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
System.Threading.Thread.Sleep(250);
tbcMain.SelectedIndex = 0;
But that is not elegant at all. If anyone has a better solution pls let me know it.
Btw adding the tbcMain.SelectedIndex = 0; on the loaded event of the mainWindow is of no use.
You should be able to set your SelectedIndex first, and without having to include it in your loop:
tbcMain.SelectedIndex = 0;
Then, basing it off of your response, you should be able to either just do .UpdateLayout() on each of your TabItems:
MainTab.UpdateLayout();
tabItem1.UpdateLayout();
tabItem2.UpdateLayout();
tabItem3.UpdateLayout();
tabItem4.UpdateLayout();
tabItem5.UpdateLayout();
Or you should be able to do something like this in your loop:
MainTab.UpdateLayout();
for (int i = 0; i < tbcMain.Items.Count; i++)
{
TabItem tbi = (TabItem)this.FindControl("tabItem"+i);
tbi.UpdateLayout();
}
Updating/refreshing should have nothing to do with setting the selected one. Including the selection of the tab within the loop to i was your problem - not a race condition. Set the tbcMain.SelectedIndex = 0 outside of your loop and you should be fine. Sometimes, however, this doesn't work and you need to set it with Dispatcher:
Dispatcher.BeginInvoke((Action)(() => this.tbcMain.SelectedIndex = 0));
There's a write up/comments on a separate thread regarding why it needs to be sent to Dispatcher:
How to programmatically select a TabItem in WPF TabControl
Though, unfortunately for me, I had a similar issue where I was trying to refresh a ListView on a subtab. Neither .UpdateLayout(), nor .InvalidateVisual() (as I saw on this thread) worked. I just had to rebind my grid in the button event I was using on my main page, so that when the tab was clicked, it was refreshed manually. I added an x:Name property on the tab so I could call it using "dot" syntax, and it exposed the ListView. I simply added the DataTable of results back to that ListView's DataContext.

Invalid currentpageindex value. it must be >= 0 and the < pagecount

I have an application that was throwing the error message below:
Invalid currentpageindex value. it must be >= 0 and the < pagecount
This issue happens if I go to the second page in my application and then try to filter the results by entering a search term.
After some research I thought I had fixed the issue by adding this line to my code
gridResult.CurrentPageIndex = 0;
So the code block now looks like this:
private void gridResult_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
gridResult.CurrentPageIndex = e.NewPageIndex;
FillGrid(tbSearch.Text);
gridResult.CurrentPageIndex = 0;
}
This stops the original issue with the error I was encountering explained above. However now if I navigate to the second page in my paging and then click to go back to the first page the data is not refreshed it just holds on to the data in the second page.
I have been struggling to find any solution for this, any ideas would be appreciated.

How to move items from a checkedListBox to another checkedListBox

I made a program which adds checkedListBox.Items from a text written in a TextBox . Regarding this, to make everything more esthetic , I made a rule so that if the number of Items added in CheckedListBox1 is bigger than a number I set, it will go to a second CheckedListBox and so on.
I can also save my Entries in a .txt file so I have easy access to my previous references. So naturally I also made a Load References which ,obviously, load the file I saved.
Anyhow, my dillemma is the following : When I press the Load References button it loads ALL the references (Lines) in the text into the first checkedListBox. I want it to respect the previous law. If I click Load References I want that if there are more than, lets say, 10 entries, all the other ones will go into the other checkedListBox ,by consequence, if the limit number is passed from the second checkedListBox the rest will go into the third one and so on.
I have searched StackOverflow and the Web for several solutions ,some of the more relevant ones :
First found link semi-regarding the subject
Second found link
So to not get it wrong I will state that I want to have all the entries that pass the limit be MOVED to another checkedlistBox ,not copied like the links would suggest.
This is the Line of code for my Load Reference button :
private void button8_Click(object sender, EventArgs e)
{
string fileData = File.ReadAllText(#" To-Do References .txt");
checkedListBox1.Items.AddRange(fileData.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
}
Also I tried several methods but this one seemed to be the closest ,even though I got almost no satisfactory result :
var i = checkedListBox1.Items.Count;
if (i >= 10)
checkedListBox2.Items.Insert(0, checkedListBox1.Items);
Regarding this line of code : It does get an entry send into the second checkedList Box it is just that the entry is called (Collection) and has nothing to do with my references.
I hope I made myself clear and thank you for support!
UPDATE
The marked answer works perfectly for this kind of program. As I have not found anything similar I believe this is most likely the best way to implement the separation of text lines into different checkedListBoxes.
if you populate listboxes properly there will be no need to move items
private void button8_Click(object sender, EventArgs e)
{
int limit = 10;
string[] fileData = File.ReadAllText(#" To-Do References .txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
// this loop adds items to the 1st list until limit is reached
for(int i =0; i<limit && i<fileData.Length; i++)
checkedListBox1.Items.Add(fileData[i]);
// if there extra items, 2nd loop adds them to list №2
for(int i =limit; i<fileData.Length; i++)
checkedListBox2.Items.Add(fileData[i]);
}
Set a limit, and maybe a multiplier to control the checkedList the data will be added to.
int limit = 10;
int checkList = 1;
string[] fileData = File.ReadAllText(#" To-Do References .txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < fileData.Length; i++)
{
if (i == limit * checkList)
{
checkList++;
}
switch (checkList)
{
case 1: checkedListBox1.Items.Add(fileData[i]); break;
case 2: checkedListBox2.Items.Add(fileData[i]); break;
case 3: checkedListBox3.Items.Add(fileData[i]); break;
}
}
As big as your text file gets, adding data to a checkedListBox just requires you to add a new line to the switch statement.
Well, my head is stuck in wpf land, so I would just bind it to a list of lists, in an itemscontrol, or something similar. Reading back, of course, it appears you are using winforms, so this may not be applicable...but i'll post anyways, because it can still be done this way using the WinForms DataRepeater control.
List<List<string>> mainList = new List<List<string>>();
int listIndex = 0;
string[] fileData = File.ReadAllText(#" To-Do References.txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for(int i = 0; i<=fileData.Length; i++)
{
mainList[listIndex].Add(fileData[i]);
if (i%10 == 0)
{
listIndex++;
}
}
Then bind the mainList to the control and configure your ItemTemplate.
There was lots of info on binding to the DataRepeater, but here's one link:
https://msdn.microsoft.com/en-us/library/cc488279.aspx

Categories

Resources