I have created a web page used for spelling exercises.
I display everything from SQL like this:
public void FillPageSpelling()
{
ArrayList videoList1 = new ArrayList();
if (!IsPostBack)
{
videoList1 = ConnectionClass.GetSpelling(1);
}
else
{
int i = Convert.ToInt32(DropDownList1.SelectedValue);
videoList1 = ConnectionClass.GetSpelling(i);
}
StringBuilder sb = new StringBuilder();
foreach (Spelling sp in videoList1)
{
sb.Append(
string.Format(
#"<table class='VideoTable'>
<tr>
<td align='center'><font face='Verdana'> <font size='3'>Level:</font> <font size='2'>{3}</font></font></td>
</tr>
<tr>
<td align='center'><font face='Verdana'> <font size='3'>Sentence:</font> <font size='2'>{1}</font></font></td>
</tr>
<tr>
<td align='center'><font size='3'>Sound:<audio controls><source src=sound/{2}></audio>
<font face='Verdana'> <font size='2'> </font> </font></td>
</tr>
<tr>
<tr><td align='center'><font face='Verdana'> <font size='3'>Write the word here: <input type=text id=TextBox1></font></font> </td> </tr>
<td><input type=button value='Check' class='p-userButton' onClick='ButtonClick(document.getElementById(""TextBox1"").value, document.getElementById(""TextBox2"").value);'/></td>
<td><input type=button value='Cheat' class='p-userButton' onClick='Cheat(document.getElementById(""TextBox2"").value);' </td>
</tr>
<tr>
<td align='center'><font face='Verdana'><input type=text style=display:none id=TextBox2 value={4}></td>
</tr>
</br>
</table>", sp.SID, sp.Sentence, sp.Audio, sp.Level, sp.Word));
lblOutput.Text = sb.ToString();
}
This is how it looks like when I choose level 2 on the dropdown list:
This is the javascript function that checks whether the word is good or not:
<script type="text/javascript">
function ButtonClick(a, b)
{
if (a.toString() == b.toString())
{
alert("Correct!");
}
else
{
alert("Wrong!");
}
}
</script>
This is how I create the button and call the function:
<input type=button value='Check' class='p-userButton' onClick='ButtonClick(document.getElementById(""TextBox1"").value, document.getElementById(""TextBox2"").value);'/>
Now, this works great with the first sentence, but when I go to the second sentence underneath, and when I type in the word in the textbox, it checks only the first sentence, not the second.
Any ideas on how can I solve this?
Multiple page elements are not supposed to have the same 'id'. That is why you keep getting the first element when using the 'id' to grab the textbox because the 'id's on the textboxes are all the same. You can create an iterator that increments on each pass through the loop and use that to put a unique number on the end of each textbox id (in both the textbox itself and the generated javascript).
Related
I know, I suck because I am using a table and not div tags but I could not get the div tags to display properly and my deadline was some time last week...
I am trying to layout a bunch of devices along with their statuses and other simple options and yet I cannot get the ìf statements to work. Here is my code:
#if (CurrentSystem == null)
{
<p><em>Loading...</em></p>
}
else
{
#foreach (Device thisDevice in CurrentSystem.LocalDevices)
{
menuCounter++;
divCounter++;
if (divCounter == 1)
{
//Starting with the first column
<tr><td class=cardBox>
}
else
{
//Starting with the last column
<tr><td class=outSideColumns></td>
<td></td>
<td class=cardBox>
}
targetName = "target" + #menuCounter;
targetNameWithDot = "." + #targetName;
menuId = "contextMenu" + #menuCounter;
modalID = "modalWindow" + #menuCounter;
<table>
<tr>
<td></td>
<td>
<div class="targetName" style="text-align:right;justify-content:right;">
...
</div>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<h3>
thisDevice.DeviceName
</h3>
<img src="#ReturnDeviceImage(thisDevice)" class=deviceImage />
#if (thisDevice.CurrentStatus == Device.DeviceStatus.Alert)
{
<h4 Class="cardAlert">Status: Alert</h4>
}
else if (thisDevice.CurrentStatus == Device.DeviceStatus.Inactive)
{
<h4 Class="cardInactive">Status: Inactive</h4>
}
else if (thisDevice.CurrentStatus == Device.DeviceStatus.Unknown)
{
<h4 Class="cardUnknown">Status: Unknown</h4>
}
else if (thisDevice.CurrentStatus == Device.DeviceStatus.Normal)
{
<h4 Class=cardNormal>Status: Normal</h4>
}
else if (thisDevice.CurrentStatus == Device.DeviceStatus.Updating)
{
<h4 Class=cardUpdating>Status: Normal</h4>
}
else
{
<h4>Status: thisDevice.CurrentStatus</h4>
}
<TelerikContextMenu IdField="#menuId" Selector="#targetNameWithDot" Data="#MenuItems" OnClick="#((ContextMenuItem item) => OnItemClick(item, #thisDevice.DeviceIDHash))">
</TelerikContextMenu>
</td>
</tr>
<tr>
<td class=nameDivs>
Device Type:
</td>
<td>
#thisDevice.DeviceType
</td>
</tr>
<tr>
<td class=nameDivs>
Hostname:
</td>
<td>
#thisDevice.DeviceHostname
</td>
</tr>
<tr>
<td class=nameDivs>
Communications:
</td>
#if (thisDevice.UsingEncryption)
{
<td class=cardNormal>Are Encrypted</td>
}
else
{
<td> class=cardAlert>Are Not Encrypted</td>
}
</tr>
<tr>
<td class=nameDivs>
Anomaly Response Level:
</td>
<td>
#thisDevice.AnomalyResponse
</td>
</tr>
</table>
if (divCounter == 1)
{
//Ending the first column
</td>
<td></td>
<td class=outSideColumns></td>
</tr>
}
else
{
//Ending the last column
</td></tr>
divCounter = 0;
}
}
</table>
}
The beginning if statement and the if statements that run the CurrentStatus and UsingEncryption seem to be working, however the last if statement is simply writing text to the screen.
If I add # signs to the first and/or last if statements, I get a ton
of errors about not having closing tags, objects not being defined,
etc...
If I remove the # signs from the CurrentStatus and UsingEncryption if
statements, those statements stop working.
If I remove the # from the foreach statement, nothing prints out.
What am I doing wrong?!?
To use tag helpers, your html structure must mirror your control flow. You can't just start a tag inside an if test without also closing it within that if test.
While you can escape unmatched html tags with #: (eg Razor doesn't understand unclosed html tags), with a little effort, you can eliminate your unmatched tags;
<tr>
#if(divCounter != 1)
{
//Starting with the last column
<td class=outSideColumns></td>
<td></td>
}
<td class=cardBox>
While Jeremy provided an excellent answer. I ended up running into issues where I absolutely needed open tags and, in fact, I had to re-write everything back into DIV tags to make things work.
That is when I discovered my new bestest friend - the MarkupString - that I can use to insert any HTML code I desire without blowing up the IDE!
Here is a link that explains how to use it - https://www.meziantou.net/rendering-raw-unescaped-html-in-blazor.htm
I'm trying to confirm a Login Page with a C# Tool and I noticed a pretty strange behavior. I'can set the username put not the password.
It's a very simple page with only 3 inputs in one form.
<form action="j_security_check" method="POST">
<td align="right"><p class="bold">Username:</p></td>
<td><input size="15" maxlength="15" type="text" name="j_username"></input></td>
</tr>
<tr>
<td align="right"><p class="bold">Password</p></td>
<td><input type="password" size="15" maxlength="15" name="j_password"></input></td>
</tr>
<tr>
<td align="right">
</td>
<td>
<input type="submit" name="btnSubmit" value="Login" />
</td>
</tr>
</form>
As I said setting the username works fine but i can't set the password.
My C# code looks like this^
private void btn_upload_Click(object sender, EventArgs e)
{
for (int i = 0; i < _webBrowser.Document.Forms.Count; i++)
{
HtmlElement element = _webBrowser.Document.Forms[i];
if (element != null)
{
_webBrowser.Document.All["j_username"].SetAttribute("value", txt_username.Text);
_webBrowser.Document.All["j_password"].SetAttribute("value", txt_password.Text);
var test = _webBrowser.Document.GetElementsByTagName("input").Count;
_webBrowser.Document.Forms[i].InvokeMember("btnSubmit");
element = _webBrowser.Document.Forms[i];
}
}
}
Do I have to do something special cause it is a type=password ?
try changing the type to 'text'
This is the function that I use to display the row from the database. The default value is level 1, SID 1. If the user chooses from the dropdown list, the level can change, but the ID stays the same because I didn't know what to do here. I want to get one record at a time, but when I press the next button, I want to get the next row with the selected level. If that is possible, can you give me some tips on how to do this? Thank you in advance.
public void FillPageSpelling()
{
ArrayList videoList1 = new ArrayList();
if (!IsPostBack)
{
videoList1 = ConnectionClass.GetSpelling(1,1);
}
else
{
int i = Convert.ToInt32(DropDownList1.SelectedValue);
videoList1 = ConnectionClass.GetSpelling(i,1);
}
StringBuilder sb = new StringBuilder();
foreach (Spelling sp in videoList1)
{
sb.Append(
string.Format(
#"<table class='VideoTable'>
<tr>
<td align='center'>
<font face='Verdana'>
<input type=text style=display:none id=TextBox3 value={0}>
</td>
</tr>
<tr>
<td align='center'>
<font face='Verdana'>
<font size='3'>Level:</font>
<font size='2'>{3}</font>
</font>
</td>
</tr>
<tr>
<td align='center'>
<font face='Verdana'>
<font size='3'>Sentence:</font>
<font size='2'>{1}</font>
</font>
</td>
</tr>
<tr>
<td align='center'>
<font size='3'>Sound: <audio controls><source src=sound/{2}></audio>
<font face='Verdana'>
<font size='2'></font>
</font>
</td>
</tr>
<tr>
<tr>
<td align='center'>
<font face='Verdana'>
<font size='3'>Write the word here: <input type=text id=TextBox1>
</font>
</font>
</td>
</tr>
<td>
<input type=button value='Check' class='p-userButton' onClick='ButtonClick(document.getElementById(""TextBox1"").value, document.getElementById(""TextBox2"").value);'/>
</td>
<td>
<input type=button value='Cheat' class='p-userButton' onClick='Cheat(document.getElementById(""TextBox2"").value);'
</td>
<td>
<input type=button value='Next' class='p-userButton'
</td>
</tr>
<tr>
<td align='center'>
<font face='Verdana'>
<input type=text style=display:none id=TextBox2 value={4}>
</td>
</tr>
</br>
</table>", sp.SID, sp.Sentence, sp.Audio, sp.Level, sp.Word));
lblOutput.Text = sb.ToString();
}
}
Here is the method that returns one record based on the level and ID:
public static ArrayList GetSpelling(int level, int sid)
{
ArrayList list = new ArrayList();
string query = string.Format("SELECT * FROM Spelling WHERE Level LIKE '{0}' and SID LIKE '{1}'", level, sid);
try
{
conn.Open();
command.CommandText = query;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int SID = reader.GetInt32(0);
string Sentence = reader.GetString(1);
string Word = reader.GetString(2);
int Level = reader.GetInt32(3);
string Audio = reader.GetString(4);
Spelling lst = new Spelling(SID, Sentence, Word, Level, Audio);
list.Add(lst);
}
}
finally
{
conn.Close();
}
return list;
}
}
I don't necessarily have an answer to your problem but I do have a few topics for you to research.
As someone else suggested, research proper binding of forms to server side code. If MVC (which I recommend), model binding from the View to the Controller is where you would need to focus.
Research MVC.
Research Object Relational Mappings - if you like .NET, try Entity Framework 5.
Also, look into third party data grids and data pagers.
I need to grab a timesheets from a website. I want to store/add this timesheet to a data table in my C# Application.
The structure of the data table looks like this:
1. | Day | Time | Status |
2. ..1.......7:00.........IN
3. ..1.......9:45.......OUT
4. ..1......10:15........IN
5. ..1......15:45......OUT
6. ..1.......8:45.....TOTAL
7. ..2 .. ..
My C# code for the DataTable:
DataTable table = new DataTable("Worksheet");
table.Columns.Add("Day");
table.Columns.Add("Time");
table.Columns.Add("Status");
I tried different variants and I always mess up with all the data.
For testing purpose I made a new Winform with a "textbox" (for the sitepath) and "button"(to start the process)
Then I want HTMLAgilityPack to get all the data. one example:
public string[] GREYsource;
public Form1()
{
InitializeComponent();
}
private void btnSubmit_Click(object sender, EventArgs e)
{
var doc = new HtmlAgilityPack.HtmlDocument();
var fileName = txtPath.Text; // I downloaded the HTML-File
doc.Load(fileName);
string strGREYInner;
foreach (HtmlNode td in doc.DocumentNode.SelectNodes("//tr[#class=\"tblDataGreyNH\"]"))
{
strGREYInner = td.InnerText.Trim();
string shorted = strGREYInner.Replace("\t", ""); string shorted2 = shorted.Replace("\n\n\n\n", "\n\n\n"); string shorted3 = shorted2.Replace("\n\n\n", "\n\n"); string shorted4 = shorted3.Replace("\n\n", "\n");
GREYsource = shorted4.Split(new Char[] { '\n', });
}
foreach (string str in GREYsource)
{
...
}
}
Problem: the result contains a lot of tabs(/t) and newlines(/n) I need to trim.
Problem: This isn't a good way to do it, IMO. And this would just grab the Totaltimes.
It can be done better.
This is just a example I tried (other codes just went a pile of junk)
I attached the HTML-structure below:
Overview(picture):
A bit more in depth:
<html>
<head>
</head>
<style type="text/css">
</style>
<body id="body" onload="handleMenuOverlapLogo();onload_column_expand();;firstElementFocus();">
<.. some (java)scripts> /* has to be ignoered. not necessary */
<.. some other divs> /* has to be ignoered. not necessary */
<div id="rowContent"> /* This <div> contains the content i need */
<div id="titleTab"> /* Title is not necessary */
</div>
<div id="rowContentInner"> /* Here the content starts */
<table class="tblList">
<tbody>
<tr> /* not necessary */
<tr class="tblHeader"> /* not necessary */
<tr class="tblHeader"> /* not necessary */
<tr class="tblDataWhiteNH"> /* IN : */
<td class="tblHeader" style="font-weight: bold; text-align: right"> In </td>
<td nowrap=""> /* "tblDataWhiteNH" always contains 7 "td nowrap"
<td nowrap="">
<td nowrap=""> /* Example: if it contains a value */
<table width="100%" border="0" align="center">
<tbody>
<tr>
<td width="25%" align="left"> </td>
<td nowrap="" width="50%" align="center"> 7:53 </td> /* value = 7:53 (THIS!) */
<td width="25%" align="right"> </td>
</tr>
</tbody>
</table>
</td>
<td nowrap="">
<td nowrap=""> /* Example: if it contains no value */
<table width="100%" border="0" align="center">
<tbody>
<tr>
<td width="25%" align="left"> </td>
<td nowrap="" width="50%" align="center"> /* no value = 0:00 (THIS!) */
<td width="25%" align="right"> </td>
</tr>
</tbody>
</table>
</td>
<td nowrap="">
<td nowrap="">
<tr class="tblDataWhiteNH"> /* OUT : */
<td class="tblHeader" style="font-weight: bold; text-align: right"> Out </td>
<td nowrap=""> /* "tblDataWhiteNH" always contains 7 "td nowrap".
<td nowrap="">
<td nowrap=""> /* Example: if it contains a value */
<table width="100%" border="0" align="center">
<tbody>
<tr>
<td width="25%" align="left"> </td>
<td nowrap="" width="50%" align="center"> 7:53 </td> /* value = 7:53 (THIS!) */
<td width="25%" align="right"> </td>
</tr>
</tbody>
</table>
</td>
<td nowrap="">
<td nowrap=""> /* Example: if it contains no value */
<table width="100%" border="0" align="center">
<tbody>
<tr>
<td width="25%" align="left"> </td>
<td nowrap="" width="50%" align="center"> /* no value = 0:00 (THIS!) */
<td width="25%" align="right"> </td>
</tr>
</tbody>
</table>
</td>
<td nowrap="">
<td nowrap="">
<tr class="tblDataGreyNH"> /* IN : */
<tr class="tblDataGreyNH"> /* OUT : */
... /* "tblDataGreyNH" is built up the same way like "tblDataWhiteNH".
... /* sometimes there could be more "tblDataWhiteNH" and "tblDataGreyNH". */
... /* Usally there are just the "tblDataWhiteNH"(IN/OUT) */
<tr class="tblHeader"> /* not necessary */
/* It continues f.egs. with "tblDataWhite" if the last above header was a "tblDatagrey" */
/* and versa vice ("grey" if there was a "white" before.) */
<tr class="tblDataWhiteNH"> /* Worked : */
<td class="tblHeader" style="font-weight: bold; text-align: right"> Total Time </td>
<td> 07:47 </td> /* value = 7:47 (THIS!) */
<td> 04:48 </td>
<td> 00:00 </td> /* no value = 0:00 (THIS!) */
<td> 00:00 </td>
<td> 07:42 </td>
<td> 00:00 </td>
<td> 00:00 </td>
</tr>
<tr class="tblDataGreyNH"> /* Total : */
<td class="tblHeader" style="font-weight: bold; text-align: right"> Regular Time </td>
<td> 07:47 </td> /* value = 7:47 (THIS!) */
<td> 04:48 </td>
<td> </td> /* no value = 0:00 (THIS!) */
<td> </td>
<td> 07:42 </td>
<td> </td>
<td> </td>
</tr>
<tr class="tblHeader"> /* not necessary */
<tr valign="top"> /* not necessary */
</tbody>
</table>
</div>
</div>
</body>
</html>
a copy of the original HTML: http://time.wnb.dk/123/
I Hope anyone could help me get this to work.
Okay let me explain it with a picture. https://www.abload.de/img/eeeqnuwu.png
On the Picture you see the website + a table below, how the result should look like.
Declaring the Datatable isnt the problem.
The main problem is I can't get htmlagility to spit out right results and if it did, its almost buggy.
Some of the selectnodes I tried got the output messed up after a while. As yet I wasn't able to get "all" data from the table on the website, just some values, but often buggy.
So I'm actually searching for someone who could take a look on this and maybe help me to find the right selectnodes.
Not sure I fully understand what you want to do but here is a sample code that should help you get started. I strongly suggest you have a look at XPATH to understand it.
HtmlDocument doc = new HtmlDocument();
doc.Load(yourFile);
// get all TR with a specific class name, starting from root (/), and recursively (//)
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//tr[#class='tblDataGreyNH' or #class='tblDataWhiteNH']"))
{
// get all TD below the current node with a specific class name
HtmlNode inOrOut = node.SelectSingleNode("td[#class='tblHeader']");
if (inOrOut != null)
{
string io = inOrOut.InnerText.Trim();
Console.WriteLine(io.ToUpper());
if (io.Contains("Time"))
{
// normalize-space gets rid or whitespaces (\r,\n, etc.)
// text() gets the node's inner text
foreach (HtmlNode td in node.SelectNodes("td[normalize-space(#class)='' and normalize-space(text())!='' and normalize-space(text())!='00:00']"))
{
Console.WriteLine("value:" + td.InnerText.Trim());
}
}
}
// gets all TD below the current node that define the NOWRAP attribute
HtmlNodeCollection tdNoWraps = node.SelectNodes("td[#nowrap]");
if (tdNoWraps != null)
{
foreach (HtmlNode tdNoWrap in tdNoWraps)
{
string value = tdNoWrap.InnerText.Trim();
if (value == string.Empty)
continue;
Console.WriteLine("value:" + value);
}
}
}
It will output this from your sample page:
IN
value:7:47
value:7:46
value:7:45
value:7:51
OUT
value:15:35
value:15:33
value:12:38
value:8:59
IN
value:12:38
value:8:59
OUT
value:15:35
TOTAL TIME
value:07:48
value:07:47
value:07:50
value:01:08
REGULAR TIME
value:07:48
value:07:47
value:07:50
value:01:08
I have this piece of html code. I want to get the text inside the <div> tag using WatiN. The C# code is below, but I'm pretty sure it could be done way better than my solution. Any suggestions?
HTML:
<table id="someId" cellspacing="0" border="1" style="border-collapse:collapse;" rules="all">
<tbody>
<tr>
<th scope="col"> </th>
</tr>
<tr>
<td>
<div>Some text</div>
</td>
</tr>
</tbody>
</table>
C#
// Get the table ElementContainer
IElementContainer diagnosisElementContainer = (IElementContainer)_control.GetElementById("someId");
// Get the tbody element
IElementContainer tbodyElementContainer = (IElementContainer)diagnosisElementContainer.ChildrenWithTag("tbody");
// Get the <tr> children
ElementCollection trElementContainer = tbodyElementContainer.ChildrenWithTag("tr");
// Get the <td> child of the last <tr>
IElementContainer tdElementContainer = (IElementContainer)trElementContainer.ElementAt<Element>(trElementContainer.Count - 1);
// Get the <div> element inside the <td>
Element divElement = tdElementContainer.Divs[0];
Based on the given, something like this is how I'd go for IE.
IE myIE = new IE();
myIE.GoTo("[theurl]");
string theText = myIE.Table("someId").Divs[0].Text;
The above is working on WatiN 2.1, Win7, IE9.