I'm having this wierd problem within the application I'm currently working on.
string searchText = "onMouseOver=\"CallList_onMouseOver(this);\" id=\"";
List<int> searchOrders = AllIndexesOf(scraper.clientBrowser.DocumentText, searchText);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < searchOrders.Count; i++)
{
string order = scraper.clientBrowser.DocumentText.Substring(searchOrders[i] + searchText.Length, 6);
scraper.clientBrowser.Document.GetElementById(order).InvokeMember("Click");
for (int j = 0; j < scraper.clientBrowser.Document.Window.Frames.Count; j++)
{
if (scraper.clientBrowser.Document.Window.Frames[j].Document != null && scraper.clientBrowser.Document.Window.Frames[j].Document.Body != null)
{
string orderText = scraper.clientBrowser.Document.Window.Frames[j].Document.Body.InnerText ?? "Nope";
//MessageBox.Show(j + Environment.NewLine + orderText);
if (!orderText.Contains("Nope"))
{
sb.AppendLine(orderText + Environment.NewLine);
}
}
}
}
Clipboard.SetText(sb.ToString());
The thing is, whenever I uncomment the MessageBox.Show, I can clearly see orderText is filled with another value than "Nope", the Stringbuilder gets filled, and the correct text is copied.
However if I comment the Messagebox.Show, the outcome of this loop is always "Nope". I'm stuck here, I have no idea what could cause something like this.
The scraper.clientBrowser is a System.Windows.Forms.WebBrowser.
Update:
Solved the issue by waiting for the document to be loaded, created this mechanism:
public bool DocumentLoaded
{
get { return documentLoaded; }
set { documentLoaded = value; }
}
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.DocumentLoaded = true;
this.clientBrowser = sender as WebBrowser;
}
void clientBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
this.DocumentLoaded = false;
}
Then in the class I'm using:
while(!scraper.DocumentLoaded)
{
System.Threading.Thread.Sleep(100);
}
It sounds like you need to ensure that the page is fully loaded, like there might be a race condition. I would suggest wiring up the WebBrowser.DocumentCompleted event, and then attempting your scrapping logic.
Update
I overlooked this initially, this certainly has something to do with your issue. The line where you are invoking a click, like so scraper.clientBrowser.Document.GetElementById(order).InvokeMember("Click");. This is done in the iteration, which will more than likely manipulate the DOM -- will it not? I suggest going about this problem entirely different. What are you trying to achieve exactly, (not how you're trying to do it)?
With this alone, I would suggest that you refer to this SO Q/A and look at how they're waiting for the click to finish.
Only one thing I can guest here:
When you uncomment MessageBox.Show, at the time the message box show the info, the clientBrowser use this time to finish loading page. Then when you press OK on message box, the page is load completed, so you get the result. When you comment it, you dont wai for page loaded, so the result is diffent.
Related
I'm writing a FlashCard app in Windows Form.
Right now I'm trying to do is read word from string array and pass it to label. Then asking user to write the translation of this word. And finally pass the result to label box.
Here is my code:
public partial class EnglishPolishScreen : Form
{
//English words array
string[] words = new string[] { "word1", "word2", "word3", "word4" };
// meanings words array
string[] wordB = new string[] { "slowo1", "slowo2", "slowo3", "slowo4" };
int element = 0;
Thread thread;
public EnglishPolishScreen()
{
InitializeComponent();
}
private void CloseAppEvent(object sender, FormClosingEventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
thread = new Thread(Threadd);
thread.Start();
}
private void Threadd()
{
englishWord.Text = words[element];
counterLabel.Text = element + 1 + " of " + words.Length;
if (answerBox.Text.Equals(wordB[element]))
{
resultLabel.Text = "Good";
element++;
}
else
resultLabel.Text = "Bad";
if (element == words.Length)
{
element = 0;
}
}
private void EnglishPolishScreen_Load(object sender, EventArgs e)
{
englishWord.Text = words[element];
}
Edited
Guys, Why I have to click two times in button to see next item from array? And why I can see "bad" answer straight after I click button? The "Good" answer shows up after second click.
Edited v2.xD
Sorted. Anyway is it good way to write code like this? If not how It could look better? Thanks
Regards
On button click, it is going through the whole for loop, i.e. the entire list of meanings, you would have to break the for loop as soon as a right match is found. So just use break; after resoultLabel.Text = "Good answer!";. Also as pointed out by #Neil, it is not good to use UI in a separate background thread.
By the way, I am not able to wrap my head around the logic of chances. For giving chances you would have to declare a global variable which would get added/subtracted when the a bad answer is found after Iterating through whole for loop, disallowing any further trial for the word.
I have been trying to finish this small application for counting the number of attempts if you fail to write the correct pin code.
This is my code so far, and I am not understanding why my code isn't working and it keeps on incrementing non stop.
private void btn_login_Click(object sender, EventArgs e)
{
int attempts = 0;
int pin_number;
do
{
pin_number = int.Parse(txt_pin.Text);
MessageBox.Show("Hi There");
if (pin_number != 1326)
{
attempts++;
MessageBox.Show($"pin code is incorrect you have {attempts} of 3 attempts left");
txt_pin.Text = "";
txt_pin.Focus();
}
} while (pin_number == 1326 && attempts < 3);
}
Every time you click the button is an "attempt", correct? Well, what's the first thing you do every time you click the button...
int attempts = 0;
So every attempt is the first attempt. Except when the user gets it right. Then what you have is an infinite loop because the pin_number is correct and attempts is never incremented.
First, get rid of the loop entirely. There's no need to repeatedly check the same input. Once it's checked, it's checked. Second, track the number of attempts outside the scope of each attempt, such as at the class level. Third, check the number of attempts. Perhaps something like this:
private int attempts = 0;
private void btn_login_Click(object sender, EventArgs e)
{
int pin_number;
pin_number = int.Parse(txt_pin.Text);
MessageBox.Show("Hi There");
if (attempts < 3 && pin_number != 1326)
{
attempts++;
MessageBox.Show($"pin code is incorrect you have {attempts} of 3 attempts left");
txt_pin.Text = "";
txt_pin.Focus();
}
}
Now it's at least checking the pin as expected. Though at this point you have some logic to reconsider for your program. Off the top of my head...
It never notifies the user if they got the pin right. Perhaps something else should happen?
After the number of attempts is exhausted, there's no warning to indicate this. It looks exactly as it does if the pin is correct.
The text implies that the number of attempts is counting down, but it's actually counting up.
Perhaps something like this might get you started:
private int attempts = 3;
private void btn_login_Click(object sender, EventArgs e)
{
int pin_number;
pin_number = int.Parse(txt_pin.Text);
MessageBox.Show("Hi There");
if (attempts <= 0)
{
MessageBox.Show($"No more attempts left");
}
else if (pin_number != 1326)
{
attempts--;
MessageBox.Show($"Pin code is incorrect you have {attempts} attempts left");
txt_pin.Text = "";
txt_pin.Focus();
}
}
Examine each statement in the logic. For your own logic, particularly around if blocks and loops and whatnot, perhaps even grab a piece of paper and draw out the different code paths and write down in each path what should happen there. Every detail is important, such as when to show a message or when to modify a value. There's a lot of polish that can be added to this code, and I imagine it's an academic exercise so I'll leave that to you.
Right now you have a loop inside your button click handler. You probably don't want that since you want to enable the user to enter a new pin code and click the Login button again.
But that also means that you need to store the number of attempts outside the click handler, since it needs to be saved from one click to the next.
So if you change your code to something like this, I think you'll get the functionality you're after
private int attempts = 0;
private void btn_login_Click(object sender, EventArgs e)
{
int pin_number;
pin_number = int.Parse(txt_pin.Text);
MessageBox.Show("Hi There");
if (pin_number != 1326)
{
attempts++;
MessageBox.Show($"pin code is incorrect you have {3-attempts} of 3 attempts left");
txt_pin.Text = "";
txt_pin.Focus();
}
if (attempts >= 3)
{
btn_login.Enabled = false;
}
}
Ok, so I have a program that checks a twitch url for whenever someone new follows the channel by comparing a certain string is different from a "temp" string that I use for reference. But instead of only outputting a message every time the string is different it gets stuck in a loop of outputting the latest follower and then second latest follower then latest follower again etc.
What am I missing? Also, is there a better way of checking if a certain string is updated?
private void DonationListen()
{
try
{
followers = this.donationClient.DownloadString("https://api.twitch.tv/kraken/channels/" + channel.Trim() + "/follows");
donationTimer.Interval = 10000;
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
donationTimer.Start();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void CheckUpdates(object source, ElapsedEventArgs e)
{
donationTimer.Stop();
int startIndex = followers.IndexOf("display_name\":") + 15;
int endIndex = followers.IndexOf(",\"logo", startIndex);
prevFollower = followers.Substring(startIndex, (endIndex - 1) - startIndex);
if (firstRun == true)
{
temp = prevFollower;
}
else if (prevFollower != temp)
{
//New follower detected
temp = prevFollower;
if (updateFollower != null)
{
updateFollower(prevFollower);
}
}
else
{
//Follower is the same as before
}
firstRun = false;
DonationListen();
}
I'm thinking it might have something to do with the downloadstring trying to get a new string from the url but failing since it's currently being updated and therefore the CheckUpdates doesn't have correct information or something?
Without a good code example, it is difficult to know for sure what the problem is. So we are left inspecting the code you did show us.
Based on that, it appears to me as though your "loop" is being caused by repeatedly subscribing to the same event.
In your DonationListen() method, you have this statement:
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
In the CheckUpdates() method (i.e. the handler you are subscribing), you have this statement (as the very last statement):
DonationListen();
In other words, every time the timer's Elapsed event is raised, you add another event handler instance to the event. For every handler you add, the CheckUpdates() method will be called.
Again, without a good code example, it is difficult to know for sure what the best fix would be. But given the code that is here, it appears to me that you could just remove that last statement from the CheckUpdates() method, as the DonationListen() method does not appear to do anything that needs doing again.
I am trying to update a textbox using the code behind in an ASP application like this:
protected void click_handler(object sender, EventArgs e)
{
Thread worker = new Thread(new ThreadStart(thread_function));
worker.Start();
}
protected void thread_function()
{
int i = 0;
while(true)
{
Textbox.Text = i.ToString();
i++;
}
}
The textbox shows one variable the first time but it doesn't get updated after that, what am I doing wrong? I searched and people are suggestin calling Textbox.Update or Textbox.Refresh but I think these are old as they don't exist anymore.
Thanks
You can't use server side code to update client side values in this manner. Anyway, you seem to be missing some kind of pause (e.g. Thread.Sleep) as currently your loop will run wildly out of control.
You need to look into using client side scripting (I.e. JavaScript) along with something like setTimeout:
https://developer.mozilla.org/en/docs/Web/API/window.setTimeout
Here's an example:
http://jsfiddle.net/PXN9K/
Apologies for the poor formatting and slightly lazy naming/refactoring, but I'm doing this on my phone.
Here's the code from the fiddle, copied here for future posterity.
var i = 0;
var updateTextbox =function()
{ document.getElementById('textbox').value = '' + i; }
var update = function() {
window.setTimeout(function() {
i++;
updateTextbox();
update();
}, 1000);
};
updateTextbox();
update();
I have a Quartz.NET application where I need the administrators to be able to modify the job details - mostly information in each jobs datamap, but also things like the triggers - here is my code I'm using
protected void ButtonSubmit_Click(object sender, EventArgs e)
{
JobDetail jobDetail = sched.GetJobDetail(hdnID.Value, hdnGroupID.Value);
jobDetail.JobDataMap["idname"] = txtName.Text;
jobDetail.JobDataMap["initialPath"] = TextBox1.Text;
jobDetail.JobDataMap["targetPath"] = TextBox2.Text;
jobDetail.JobDataMap["regex"] = TextBox3.Text;
jobDetail.JobDataMap["overrideemails"] = txtEmails.Text;
jobDetail.JobDataMap["flush"] = chkflush.Checked;
jobDetail.JobDataMap["impUsername"] = txtImpUsername.Text;
jobDetail.JobDataMap["impDomain"] = txtImpDomain.Text;
jobDetail.JobDataMap["impPassword"] = txtImpPassword.Text;
Trigger[] triggers = sched.GetTriggersOfJob(hdnID.Value, hdnGroupID.Value);
if (ddlScheduleType.SelectedIndex == 0)
{
foreach (SimpleTrigger trigger in triggers.OfType<SimpleTrigger>())
{
if (ddlInterval.SelectedIndex == 0)
{
trigger.RepeatInterval = TimeSpan.Parse("00:00:01");
}
else if (ddlInterval.SelectedIndex == 1)
{
trigger.RepeatInterval = TimeSpan.Parse("00:01:00");
}
else if (ddlInterval.SelectedIndex == 2)
{
trigger.RepeatInterval = TimeSpan.Parse("00:00:01");
}
}
}
else
{
foreach (CronTrigger trigger in triggers.OfType<CronTrigger>())
{
trigger.CronExpressionString = txtCron.Text;
}
}
}
(I know what I'm doing with the foreach loops is stupid, but there is only ever one trigger with a job and it's a snippet of code I recieved here).
Problem is, the page posts back fine and the new values still stay in the textboxes. But when I go view the job again, nothing changes at all. What am I doing wrong? It's confusing as there are no errors at all.
Note the hiddenfields are also correctly set.
Thanks
The ButtonSubmit_Click event is certainly working as I've debugged the program and the program goes through that.
The instance you get by calling sched.GetTriggersOfJob and sched.GetJobDetail are clones of the real triggers / jobs.
Your changes to those objects are not used by the scheduler until you reschedule the changed trigger or add a the changed job with the changed trigger.
I think you should be able to use RescheduleJob if you only change the triggers and you could remove the original trigger and add a new one.