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
Next using LINQ approach
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.
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
Related
I am having this kind of structure in a Web Application where depending on the user's choices Table_1 or Table_2 is given visibility; they never can be both visible.
<table>
<tr><td>
<table id="Table_1" runat="server" visible="false">
<tr><td>...</td></tr>
<tr><td>
<asp:GridView>
<asp:Linkbutton>
<asp:FormView>
</td></tr>
</table>
<table id="Table_2" runat="server" visible="false">
<tr><td>...</td></tr>
<tr><td>
<asp:GridView>
</td></tr>
</table>
</td></tr>
</table>
The strange thing is that this works only if the hole code block for table 2 is on top. If I switch them back to the way described by the code, table_2 never will show up. I do not add anything more. Just by switching the two tables in the code, once the result is correct, while in the other case it isn't.
What can this be related to?
Martin
Code that controls visibility:
protected void GridView01_OnSelectedIndexChanged(object sender, EventArgs e)
{
FilterDDLResponsable.SelectedIndex = -1;
GridView3.Visible = true;
GridView3.EditIndex = -1;
Table_1.Visible = true;
Table_2.Visible = false;
GridView3.DataBind();
ButtonEditMode.Visible = false;
ButtonSendHWReminderSeries.Visible = false;
if (AdminUser.Text == "1")
{
AddButton.Visible = true;
}
LabelAuditID.Text = Convert.ToString(GridView01.SelectedValue);
if(ActivateTabletView.Checked == true)
{
GridView01.Columns[12].Visible = true;
GridView01.Columns[13].Visible = true;
GridView01.Columns[14].Visible = true;
}
else
{
GridView01.Columns[12].Visible = false;
GridView01.Columns[13].Visible = false;
GridView01.Columns[14].Visible = false;
}
FillGrid();
}
and the Grid's row LinkButton onClick method:
protected void OpenAudit(object sender, EventArgs e)
{
LinkButton btn = (LinkButton)(sender);
string AuditID = btn.CommandArgument;
Table_1.Visible = false;
Table_2.Visible = true;
LabelAuditID.Text = AuditID;
foreach (GridViewRow gvRow in GridView01.Rows)
{
if ((int)GridView01.DataKeys[gvRow.DataItemIndex].Value == Convert.ToUInt32(AuditID))
{
GridView01.SelectedIndex = gvRow.DataItemIndex;
break;
}
}
FillQuestionsGrid();
}
I am quite new to ASP and I have been stuck on an issue for about a week. The issue is probably something to do with the Asp Page Life Cycle but I am unable to find how this can be resolved. The issue is that skipto(..) is never called when I click the LinkButton (that were created on first Page Load), which means the LinkButtons are not rendered.
Sample Code below:
// Code Behind
protected void Page_Load(object sender, EventArgs e)
{
loadData();
if (!Page.IsPostBack)
{
skiptof();
}
}
public void loadData() {
// Loads from database
}
public void skipto(object sender, EventArgs e)
{
LinkButton btn = sender as LinkButton;
if (btn != null)
{
if (btn.CommandArgument != null && btn.CommandArgument != "0")
{
int currPage = 1;
int.TryParse(btn.CommandArgument, out currPage);
skiptof(currPage);
}
}
}
public void skiptof(int currPage = 1)
{
int lastPage = // calculate from LoadData()
string pageDisabled = "";
// pages
HtmlGenericControl ul = new HtmlGenericControl("ul");
while (pageCount <= lastPage)
{
// Disable the current page
pageDisabled = pageCount == currPage ? " class=\"disabled\"" : "";
HtmlGenericControl pagesli = new HtmlGenericControl("li");
if (pageDisabled != "")
{
pagesli.Attributes.Add("class", "disabled");
}
LinkButton pagesPageLink = new LinkButton();
pagesPageLink.Click += new EventHandler(skipto);
pagesPageLink.CommandArgument = pageCount.ToString();
pagesPageLink.Text = pageCount.ToString();
pagesli.Controls.Add(pagesPageLink);
ul.Controls.Add(pagesli);
pageCount += 1;
}
pagination.Controls.Add(ul);
}
// page
<asp:ScriptManager ID="ScriptManager1" runat="server"/>
<asp:UpdatePanel runat="server" id="UpdatePanel" UpdateMode="Conditional">
<ContentTemplate>
<div id="details" runat="server"></div>
<div class="pagination text-center" id="pagination" runat="server"></div>
</ContentTemplate>
</asp:UpdatePanel>
Your problem is:
You didn't bind the data again on postback, I've modified your code a little bit, there are several problems:
in the method skipof:
public void skiptof(int currPage = 1) {
//Clear the controls here then add them again
pagination.Controls.Clear();
int lastPage = // calculate from LoadData()
string pageDisabled = "";
HtmlGenericControl ul = new HtmlGenericControl("ul");
while (pageCount <= lastPage) {
// Disable the current page
pageDisabled = pageCount == currPage ? " class=\"disabled\"" : "";
HtmlGenericControl pagesli = new HtmlGenericControl("li");
if (pageDisabled != "") {
pagesli.Attributes.Add("class", "disabled");
}
LinkButton pagesPageLink = new LinkButton();
// you can directly assign the method to be called here, there is no need to create a new EventHandler
pagesPageLink.Click += PagesPageLink_Click;
pagesPageLink.CommandArgument = pageCount.ToString();
pagesPageLink.Text = pageCount.ToString();
pagesli.Controls.Add(pagesPageLink);
ul.Controls.Add(pagesli);
pageCount += 1;
}
pagination.Controls.Add(ul);
}
You didn't bind the data again in postback, so I modified it:
Page Load:
protected void Page_Load(object sender, EventArgs e) {
//Remove the Page.IsPostBack checking
skiptof();
}
Please take note that the controls you added dynamically will be cleared and you have to add it again on postback to avoid data lost.
Then you'll be able to get the value on PagesPageLink_Click event:
The whole sample is here:
http://pastie.org/10503291
I have the following repeater wrapped in an Update Panel
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="DropDownList1" EventName="SelectedIndexChanged" />
</Triggers>
<ContentTemplate>
<asp:Repeater ID="skillTable" runat="server">
<ItemTemplate>
<table class="table table-hover">
<tr>
<td>
<asp:ImageButton runat="server" AutoPostBack="True" ID="skillButton" OnClick="skillButton_Click" CommandArgument="<%# Eval(DropDownList1.SelectedValue)%>" class="addText btn btn-success" ImageUrl="~/img/addbut.png" /></td>
<td><asp:Label runat="server" id="skillName" Text='<%# DataBinder.Eval(Container.DataItem, DropDownList1.SelectedValue) %>'></asp:Label></td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
It kicks out the information from my database perfectly, and it has a button right before the text in each row.
The problem that i have is that I need each button on each row to, when clicked, add the specific line of code in that row to a textbox.
foreach (RepeaterItem item in skillTable.Items)
{
string skill = item.DataItem.ToString();
string text = skillList.Text;
if (!string.IsNullOrEmpty(text))
{
if (!text.Contains(skill))
{
text += " | " + skill;
skillList.Text = text;
}
}
else
{
text = skill;
skillList.Text = text;
}
}
UpdatePanel2.Update();
I have also tried this way,
protected void skillTable_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
int d = 0;
if(DropDownList1.SelectedValue == "Business and Finance")
{
d = 1;
}
else if(DropDownList1.SelectedValue == "Computers and Technology")
{
d = 2;
}
else if (DropDownList1.SelectedValue == "Education")
{
d = 3;
}
else if (DropDownList1.SelectedValue == "Customer Service")
{
d = 4;
}
DataRowView drv = (DataRowView)e.Item.DataItem;
string skill = drv[d].ToString();
Session["Table"] = skill;
}
protected void skillButton_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
string skill = (string)(Session["Table"]);
string text = skillList.Text;
if (!string.IsNullOrEmpty(text))
{
if (!text.Contains(skill))
{
text += " | " + skill;
skillList.Text = text;
}
}
else
{
text = skill;
skillList.Text = text;
}
UpdatePanel2.Update();
}
but neither one of them seems to work correctly. Any advice? I havent really used repeaters before this, so If there is any other tool that would work better, I'm open for suggestions.
Thanks in advance!
So I figured it out. What I was missing was a way for my site to specifically narrow down what i needed. I added the code blow to my click method and got rid of the ItemDataBound method and it worked like a charm.
Button button = (sender as Button);
string commandArgument = button.CommandArgument;
RepeaterItem item = button.NamingContainer as RepeaterItem;
var workText = (Label)item.FindControl("workName1") as Label;
string work = workText.Text;
string text = workDetails1.Text;
if (text == " ")
text = "";
if (text == "")
{
if (!text.Contains(work))
{
text +="\u2022 " + work;
workDetails1.Text = text;
}
}
else if (!string.IsNullOrEmpty(work))
{
if (!text.Contains(work))
{
text += "\n\u2022 " + work;
workDetails1.Text = text;
}
else
{
workDetails1.Text = text;
}
}
UpdatePanel4.Update();
Hope this helps someone!
I have populated my checkboxlist on the fly via callback like this:
<dx:ASPxComboBox ID="ASPxComboBox_Prot" runat="server" DataSourceID="SqlDataSource_Prot"
TextField="LIBELLE" ValueField="NO_PROT" ValueType="System.Int32">
<ClientSideEvents SelectedIndexChanged="function(s, e) { cbp_ProtOrdos.PerformCallback(s.GetValue());}" />
</dx:ASPxComboBox>
</td>
</tr>
</table>
<dx:ASPxCallbackPanel ID="ASPxCallbackPanel_ProtOrdo" runat="server"
ClientInstanceName="cbp_ProtOrdos" OnCallback="cbp_ProtOrdo_Callback">
<PanelCollection>
<dx:PanelContent>
<dx:ASPxCheckBoxList ID="CheckBoxList_Ordo" runat="server" ClientInstanceName="CheckBoxList_Ordo" ValueType="System.Int32" TextField="LIBELLE" ValueField="NO_ORDO">
</dx:ASPxCheckBoxList>
<dx:ASPxButton ID="ASPxButton_ProtOrdoGen" runat="server"
Text="Générer ordonnance & Planifier pour infirmier"
OnClick="ASPxButton_ProtOrdoGen_Click"
EnableDefaultAppearance="false" BackColor="Yellow" CssClass="bt" Theme="BlackGlass" ForeColor="Black">
</dx:ASPxButton>
</dx:PanelContent>
</PanelCollection>
</dx:ASPxCallbackPanel>
And on server side code:
protected void cbp_ProtOrdo_Callback(object sender, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
{
var panel = sender as ASPxCallbackPanel;
var cblist = panel.FindControl("CheckBoxList_Ordo") as ASPxCheckBoxList;
cblist.DataSource = Outils.Get_ProtOrdo(ASPxComboBox_Prot.Value.ToString());
cblist.DataBind();
}
It works fine, but now I want to get the value that had been checked by the user. So I add the button to do that.
protected void ASPxButton_ProtOrdoGen_Click(object sender, EventArgs e)
{
//TabPage oPage = ASPxPageControl_DosSoin.TabPages.FindByName("Surveillance");
//ASPxPanel oPanel = (ASPxPanel)oPage.FindControl("ASPxPanel_ListSurveil");
//ASPxRoundPanel oRoundPnl = (ASPxRoundPanel)oPanel.FindControl("ASPxRoundPanel_ProtOrdo");
//ASPxCallbackPanel ocbpPanel = (ASPxCallbackPanel)oRoundPnl.FindControl("ASPxCallbackPanel_ProtOrdo");
//ASPxCheckBoxList cblist = (ASPxCheckBoxList)ocbpPanel.FindControl("CheckBoxList_Ordo") as ASPxCheckBoxList;
List<string> selectItems_Ordo = new List<string>();
foreach (var oItem in CheckBoxList_Ordo.Items)
{
ListEditItem oNewChk = (ListEditItem)oItem;
if (oNewChk.Selected)
{
selectItems_Ordo.Add( oNewChk.Value.ToString());
}
}
foreach (var oItem in selectItems_Ordo)
{
if (DossierDuSoins.check_doublon_ordo(oItem.ToString(), Soin_Id) == 0)
DossierDuSoins.RamenerVal(DossierDuSoins.GetLibOrdo(oItem.ToString()), Soin_Id, oItem.ToString());
}
string TempId = "";
if (selectItems_Ordo.Count == 0)
{
lbl_err.Text = "Pas de médicament de sélectionné";
}
else
{
foreach (string selectItemId in selectItems_Ordo)
{
if (TempId != "")
TempId += ",";
TempId += selectItemId.ToString();
}
string AdrUrl = "Print_Ordo.aspx?SoinId=" + Soin_Id + "&SelId=" + TempId;
ClientScript.RegisterStartupScript(this.GetType(), "newWindow", String.Format("<script>window.open('{0}');</script>", AdrUrl));
}
}
The problem is that I can not get my checked value. Is that because the postback destroys all checkboxlists that I had constructed on the fly ?
Try this instead of using vars for selecting your checkbox list
foreach (ListItem yourItem in YourCheckBoxList.Items)
{
if (item.Selected)
{
// If the item is selected, Add to your list/ save to DB
}
else
{
// If item is not selected, do something else.
}
}
I've seen a lot of chatter on this topic. Though the examples and desired outcomes are always very specific and specialized. Any direction on this is appreciated.
In my Code: I am dynamically generated image and image URL.And add this image control in panel.I want to Put Image url in argument of temp() but i dont understand how can i do this
<td align="center" colspan="2" style="height: 200px; ">
<asp:Panel ID="Panel_pic1" runat="server">
</asp:Panel>
</td>
Code Behind:
var lasToThirteenthUploaded = ds.Tables["title"].Rows[ds.Tables["title"].Rows.Count - 13]["id"].ToString();
int ID13 = Convert.ToInt16(lasToThirteenthUploaded);//row.Field<int>("video_id");
Image img13 = new Image();
img13.ID = "image" + ID13;
string title13 = ds.Tables["title"].Rows[ds.Tables["title"].Rows.Count - 13]["title"].ToString();//row.Field<string>("title");
img13.ImageUrl = ds.Tables["title"].Rows[ds.Tables["title"].Rows.Count - 13]["path"].ToString();// ("image_path");
Panel_pic13.Controls.Add(img13);
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
if (Session["Name"] == null)
{
}
else
{
temp();
}
}
protected void temp()
{
}
Pass value from here
else
{
temp(img13.ImageUrl);
}
and grab it in
void temp(string imageurl)
{
}
you could use protected void temp(string imageurl) also