Reputation: 22662
I have a WebBrowser in Windows Forms project. It navigates all links in a table element. It is working fine; however it uses break
inside a loop. How to achieve this functionality without break
statement?
Note: In my real scenario, all the links will redirect to a login page if we give a Navigate command with that link. So, storing all urls and doing a Navigate afterwards will not work for me, in my actual scenario.
C# Code
public partial class Form1 : Form
{
string websiteUrl = @"C:\Samples_L\MyTableTest.html";
List<string> visitedUrls = new List<string>();
string currentUrl = String.Empty;
private void ExerciseApp(object sender, EventArgs e)
{
Thread.Sleep(1000);
if (currentUrl != websiteUrl)
{
currentUrl = websiteUrl;
wb.Navigate(websiteUrl);
}
HtmlElement tableElement = wb.Document.GetElementById("four-grid");
if (tableElement != null)
{
foreach (HtmlElement e1 in tableElement.All)
{
string x = e1.TagName;
String idStr = e1.GetAttribute("id");
if (!String.IsNullOrWhiteSpace(idStr))
{
if (idStr.Contains("catalogEntry_img"))
{
string url = e1.GetAttribute("href");
if (!visitedUrls.Contains(url))
{
currentUrl = url;
visitedUrls.Add(url);
e1.InvokeMember("Click");
//Use break when the first match is found
break;
}
}
}
}
}
}
private System.Windows.Forms.WebBrowser wb = null;
private Button button1 = null;
private ListBox listBox1 = null;
public Form1()
{
// button1
button1 = new Button();
button1.Location = new Point(20, 430);
button1.Size = new Size(90, 23);
button1.Text = "Load and Test";
button1.Click += new EventHandler(this.button1_Click);
// listBox1
listBox1 = new ListBox();
listBox1.Location = new Point(10, 460);
listBox1.Size = new Size(460, 200);
// Web Browser
wb = new WebBrowser();
wb.Location = new Point(10, 10);
wb.Size = new Size(1000, 400);
//Subscribing for the Document Completed Event
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(ExerciseApp);
// Form1
this.Text = "Web Browser Test";
this.Size = new Size(5000, 7100);
this.Controls.Add(wb);
this.Controls.Add(button1);
this.Controls.Add(listBox1);
currentUrl = websiteUrl;
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Add("Loading Web app under test into WebBrowser control");
wb.Url = new Uri(websiteUrl);
}
}
HTML Used
<html>
<head>
<style type="text/css">
table {
border: 2px solid blue;
}
td {
border: 1px solid teal;
}
</style>
</head>
<body>
<table id="four-grid">
<tr>
<td>
<a href="https://stackoverflow.com/users/696627/lijo" id="catalogEntry_img63664" class="itemhover"
onfocus="showPopupButton('category_63664');"
onkeydown="shiftTabHidePopupButton('category_63664',event);">
<img src="ssss"
alt="G" width="70" />
</a>
</td>
<td>
<a href="http://msdn.microsoft.com/en-US/#fbid=zgGLygxrE84" id="catalogEntry_img63665" class="itemhover"
onfocus="showPopupButton('category_63665');"
onkeydown="shiftTabHidePopupButton('category_63665',event);">
<img src="ssss"
alt="Y" width="70" />
</a>
</td>
</tr>
<tr>
<td>
<a href="https://www.wikipedia.org/" id="catalogEntry_img63666" class="itemhover"
onfocus="showPopupButton('category_63666');"
onkeydown="shiftTabHidePopupButton('category_63666',event);">
<img src="ssss"
alt="B" width="70" />
</a>
</td>
<td>
<a href="http://www.keralatourism.org/" id="catalogEntry_img63667" class="itemhover"
onfocus="showPopupButton('category_63667');"
onkeydown="shiftTabHidePopupButton('category_63667',event);">
<img src="ssss"
alt="A" width="70" />
</a>
</td>
</tr>
</table>
</body>
</html>
Reference
Upvotes: 0
Views: 855
Reputation: 23011
If you iterate over a range of values and want to exit as soon as you found one which satisfies a condition, it is common to use break:
foreach(var a in list) {
if(test(a)) {
// use a
break;
}
}
Sometimes it may be undesired and you can just use this:
bool found = false;
foreach(var a in list) {
if(found && test(a)) {
// use a
found = true;
}
}
or even:
bool found = false;
foreach(var a in list) {
if(test(a)) {
if(found) {
// use a
found = true;
}
}
}
The first version can skip iterating once a suitable element is found. The other two variants keep iterating or even checking all elements. In almost all cases this just wastes processing power. But have a look here for a case where you actually might want to use the third variant: http://en.wikipedia.org/wiki/Timing_attack
Upvotes: 0
Reputation: 203832
You could refactor it into a query, making the intentions of the code somewhat clearer:
var nextElement = tableElement.All
.Where(element => element.GetAttribute("id") != null &&
element.GetAttribute("id").Contains("catalogEntry_img") &&
!visitedUrls.Contains(element.GetAttribute("href")))
.FirstOrDefault();
if(nextElement != null)
{
visitedUrls.Add(nextElement.GetAttribute("href"));
nextElement.InvokeMember("Click");
currentUrl = nextElement.GetAttribute("href");
}
I'd also suggest changing visitedUrls
to a HashSet
, rather than a list, as it is a more efficient data structure for simply determining if an item is in a set of items.
Upvotes: 4