Why doesn't delegate call the function? - c#

1: Can someone explain the last line of the first function to me?
2: The second function doesn't work. Please tell me why.The PHP script is fetching the data.
I edited the code to get this, but the app now crashes with a System nullreferenceexception.
Please help.
private void checkbutton_Click(object sender, RoutedEventArgs e)
{
statustext.Text = "Checking for new score";
var webclient = new WebClient();
webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(getscores_OpenReadCompleted);
webclient.OpenReadAsync(new Uri("http://example.com/get.php?"+DateTime.Now));
}
void getscores_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
StreamReader s = null;
Stream reply=null;
try
{
reply = (Stream)e.Result;
s = new StreamReader(reply);
}
catch
{
statustext.Text = "ERROR IN FETCHING";
}
scorebox.Text = s.ReadToEnd();
statustext.Text = "DoNE";
}

The last line of the first method is attaching a handler to an event. It is saying that when the OpenReadCompleted event fires, that is to say when the read completes, the getscores_OpenReadCompleted method should be called.
The getscores_OpenReadCompleted doesn't work because it's trying to access a UI element from a non-UI thread.
You're also adding the handler after starting the asynchronous operation, so while it's unlikely, it's certainly possible that the operation completes very quickly and the event is fired before you add the handler. While this situation would be very unusual, it's fixed very quickly and easily by simply adding the handler before you start the asynchronous operation.

There are a couple of issues here:
Register the delegate before the call to OpenReadAsync
Read the stream from the event arguments and close the stream when you're done.
private void checkbutton_Click(object sender, RoutedEventArgs e)
{
statustext.Text = "Checking for new score";
var webclient = new WebClient();
webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(getscores_OpenReadCompleted);
webclient.OpenReadAsync(new Uri("http://example.com/get.php?"+DateTime.Now));
}
void getscores_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
Stream reply = null;
StreamReader s = null;
string outputText = string.Empty;
try
{
reply = (Stream)e.Result;
s = new StreamReader(reply);
outputText = s.ReadToEnd();
}
finally
{
if (s != null)
{
s.Close();
}
if (reply != null)
{
reply.Close();
}
}
statustext.Text = outputText;
}
See the usage of the OpenReadAsync method here:
http://msdn.microsoft.com/en-us/library/system.net.openreadcompletedeventhandler(v=vs.110).aspx
and here
http://msdn.microsoft.com/en-us/library/ms144211(v=vs.110).aspx

Related

How to Execute a method once when the event triggers very first time?

I have this following Event:
private void button1_Click(object sender, EventArgs e)
{
try
{
sPort = new SerialPort();
sPort.PortName = comboBox1.Text;
sPort.BaudRate = Convert.ToInt32(comboBox5.Text);
sPort.DataBits = Convert.ToInt32(comboBox3.Text);
sPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBox2.Text);
sPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox4.Text);
sPort.Handshake = Handshake.None;
sPort.RtsEnable = true;
sPort.DtrEnable = true;
sPort.DataReceived += new SerialDataReceivedEventHandler(sPort_datareceived);
sPort.Open();
}
catch (Exception err)
{
MessageBox.Show(err.Message, MessageBoxButtons.OK.ToString());
}
}
private void sPort_datareceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
datain = sp.ReadExisting();
this.Invoke(new EventHandler(idextraction));
}
public string namingid;
private void idextraction(object sender, EventArgs e)
{
Match matchid = Regex.Match(datain, #"\b\d{12}\b");
namingid = matchid.Value;
namingid = namingid.Substring(namingid.Length - 7);
this.Invoke(new EventHandler(writesyncdata));
}
private void writesyncdata(object sender, EventArgs e)
{
try
{
TextWriter tw = new StreamWriter(#"C:\\intdata\\" + namingid + ".txt");
tw.Write(datain);
tw.Close();
}
catch (Exception err)
{
MessageBox.Show(err.Message, MessageBoxButtons.OK.ToString());
}
}
Suppose this Event triggers X No. of times and then stops and then Triggers Again And the Cycle Goes On. The Time Interval is between 1-2 sec when the event triggers X no. of times. I want to Invoke My method once the very first time the event triggers and stop afterwards but My method should Execute once every time the Cycle Starts.
When idextraction() invokes it doesn't work because the data in buffer is less to process(it takes 1-2 sec to fill full data but my method invokes before that and that's the problem)
I Know the how to execute a method once but as the event triggers many times in short period of time so my method also and i don't want that. Does anybody know how to do it ?
Every time the event fires, you have no idea how much information will be available. It is your responsibility to buffer up all the data as it is received until you have something useful to do with it. There are a variety of ways to do this, like you could have a queue of bytes. When data is received, you add the data to the end of the queue and check if it is enough to process it. If it is, the call your processing routine. If it is not, then wait for more data to be received. You will need a separate queue for each serial port you open.

How do I show Progress Bar when Downloading a File?

I'm brand new to coding with c# so can someone tell me how I can include code into this to show the progress bar of file downloading?
private void button4_Click(object sender, EventArgs e)
{
using (var client = new WebClient())
{
MessageBox.Show("File will start downloading");
var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe");
client.DownloadFile("GOOGLE DRIVE LINK", path);
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
}
To update a progress bar while your WebClient downloads data you have to use a function that does this task in the background. WebClient has a useful function called DownloadFileAsync. This function does exactly that: It downloads in the background.
The code so with this change:
private void button4_Click(object sender, EventArgs e)
{
using (var client = new WebClient())
{
MessageBox.Show("File will start downloading");
var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe");
client.DownloadFileAsync(new Uri("GOOGLE DRIVE LINK"), path);
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
}
Unfortunately we have a problem now. The method starts the download in the background and your code immediately continues. This means you press your button, the first MessageBox pops up, the second MessageBox pops up right after the first one and if your download isn't completed when you close the second one your file is executed too early.
To avoid this WebClient has events. The one we need is called DownloadFileCompleted. As the name suggests it executes whatever you want when the download is completed. So let's look at the new code:
string path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe"); // We need our path to be global
private void button4_Click(object sender, EventArgs e)
{
using (var client = new WebClient())
{
client.DownloadFileCompleted += client_DownloadFileCompleted; // Add our new event handler
MessageBox.Show("File will start downloading");
client.DownloadFileAsync(new Uri("GOOGLE DRIVE LINK"), path);
}
}
private void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) // This is our new method!
{
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
Our next problem: client is inside a using block. This is great for foreground downloads but if we do it asynchronously (that's what doing it in the background is called) your client will be dead as soon as the block is left which is immediately after the download has been started. So let's make our client global to be able to destroy it later on.
string path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe");
WebClient client; // Here it is!
private void button4_Click(object sender, EventArgs e)
{
client = new WebClient(); // Create a new client here
client.DownloadFileCompleted += client_DownloadFileCompleted; // Add our new event handler
MessageBox.Show("File will start downloading");
client.DownloadFileAsync(new Uri("GOOGLE DRIVE LINK"), path);
}
private void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) // This is our new method!
{
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (client != null)
client.Dispose(); // We have to delete our client manually when we close the window or whenever you want
}
Now let's assume the user can press the button a second time before the download is completed. Our client would be overwritten then and the download would be canceled. So let's just ignore the button press if we're already downloading something and only create the new client if we don't have one. New code:
string path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe");
WebClient client;
private void button4_Click(object sender, EventArgs e)
{
if (client != null && client.IsBusy) // If the client is already downloading something we don't start a new download
return;
if (client == null) // We only create a new client if we don't already have one
{
client = new WebClient(); // Create a new client here
client.DownloadFileCompleted += client_DownloadFileCompleted; // Add our new event handler
}
MessageBox.Show("File will start downloading");
client.DownloadFileAsync(new Uri("GOOGLE DRIVE LINK"), path);
}
private void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) // This is our new method!
{
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (client != null)
client.Dispose(); // We have to delete our client manually when we close the window or whenever you want
}
Now that the boring part is done let's come to your problem: Viewing the progress in a progress bar. WebClient has got another event called DownloadProgressChanged. We can use it to update our progress bar.
Talking about progress bars: In Windows Forms you can create one by searching for ProgressBar in the tool bow window in Visual Studio. Then place it somewhere in your window. The ProgressBar component has a few properties which are important for its range. We're lucky, the default values are exactly what we need.
Our updated code (assuming your progress bar is called progressBar1:
string path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "SOMEFILENAME.exe");
WebClient client;
private void button4_Click(object sender, EventArgs e)
{
if (client != null && client.IsBusy) // If the client is already downloading something we don't start a new download
return;
if (client == null) // We only create a new client if we don't already have one
{
client = new WebClient(); // Create a new client here
client.DownloadFileCompleted += client_DownloadFileCompleted;
client.DownloadProgressChanged += client_DownloadProgressChanged; // Add new event handler for updating the progress bar
}
MessageBox.Show("File will start downloading");
client.DownloadFileAsync(new Uri("GOOGLE DRIVE LINK"), path);
}
private void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) // This is our new method!
{
MessageBox.Show("File has been downloaded!");
System.Diagnostics.Process.Start(path);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (client != null)
client.Dispose(); // We have to delete our client manually when we close the window or whenever you want
}
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) // NEW
{
progressBar1.Value = e.ProgressPercentage;
}
Notes:
You can create the FormClosing method by double clicking the FormClosing event in your window's property box.
Calling client.Dispose() is only necessary when your program doesn't exit after closing the window. In any other case you could get rid of the FormClosing stuff completely.
That's all finally. I hope this wasn't too long for you and I could help you. Feel free to ask for clarification. That's what comments are there for.

How do I check if WebClient download is completed before I execute a function?

I am trying to get to JSON files from different URLs. How do I make sure both files are downloaded completely before I try to execute something else.
My code looks something like this:
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
DoSomethingWithJson();
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
}
Right now, what happens is json1 and json2 returns null values whenever I try to display them in a MessageBox inside DoSomethingWithJson(), and I am assuming this might be because they haven't been downloaded completely.
The DownloadStringAsync() method is returning before the string is downloaded because it's an asynchronous method. If you move the DoSomethingWithJson() method to your completed handlers then it will be called once the request is completed. You may want to add logic to the DoSomethingWithJson() method so that it only does it's work if all the variables it needs are populated (If indeed you need them all to be populated before you start doing anything else).
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
var json1Done = false;
var json2Done = false;
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
json1Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
json2Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
Alternatively, if you are using .Net 4.5 then you could use the new async/await features:
WebClient Url1 = new WebClient();
var json1Task = Url1.DownloadStringTaskAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
var json2Task = Url2.DownloadStringTaskAsync(new Uri("http://anotherexample.com"));
json1 = await json1Task;
json2 = await json2Task;
DoSomethingWithJson();

web client DownloadFileCompleted get file name

I tried to download file like this:
WebClient _downloadClient = new WebClient();
_downloadClient.DownloadFileCompleted += DownloadFileCompleted;
_downloadClient.DownloadFileAsync(current.url, _filename);
// ...
And after downloading I need to start another process with download file, I tried to use DownloadFileCompleted event.
void DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
throw e.Error;
}
if (!_downloadFileVersion.Any())
{
complited = true;
}
DownloadFile();
}
But, i cannot know name of downloaded file from AsyncCompletedEventArgs , I made my own
public class DownloadCompliteEventArgs: EventArgs
{
private string _fileName;
public string fileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}
public DownloadCompliteEventArgs(string name)
{
fileName = name;
}
}
But I cannot understand how call my event instead DownloadFileCompleted
Sorry if it's nood question
One way is to create a closure.
WebClient _downloadClient = new WebClient();
_downloadClient.DownloadFileCompleted += DownloadFileCompleted(_filename);
_downloadClient.DownloadFileAsync(current.url, _filename);
This means your DownloadFileCompleted needs to return the event handler.
public AsyncCompletedEventHandler DownloadFileCompleted(string filename)
{
Action<object, AsyncCompletedEventArgs> action = (sender, e) =>
{
var _filename = filename;
if (e.Error != null)
{
throw e.Error;
}
if (!_downloadFileVersion.Any())
{
complited = true;
}
DownloadFile();
};
return new AsyncCompletedEventHandler(action);
}
The reason I create the variable called _filename is so that the filename variable passed into the DownloadFileComplete method is captured and stored in the closure. If you didn't do this you wouldn't have access to the filename variable within the closure.
I was playing around DownloadFileCompleted to get the file path/file name From the event. I've tried the above solution also but It was not like my expectation then i fond the solution by adding Querystring value, Here i would like to share the code with you.
string fileIdentifier="value to remember";
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler (DownloadFileCompleted);
webClient.QueryString.Add("file", fileIdentifier); // here you can add values
webClient.DownloadFileAsync(new Uri((string)dyndwnldfile.path), localFilePath);
And the event can be defined as like this:
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string fileIdentifier= ((System.Net.WebClient)(sender)).QueryString["file"];
// process with fileIdentifier
}

How can I get the URL in OpenReadCompletedEvent when I use webclient

How can I get the URL in OpenReadCompletedEvent when I use webclient.
WebClient webClient = new WebClient();
webClient.OpenReadAsync(url); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
string strStream = reader.ReadToEnd();
}
}
}
Thank you!
WebClient webClient = new WebClient();
webClient.BaseAddress = "http://hhh.com";
webClient.OpenReadAsync(new Uri("http://hhh.com")); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
And:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
var client = sender as WebClient;
if (client != null)
{
var url = client.BaseAddress; //returns hhh.com
}
string strStream = reader.ReadToEnd();
}
}
Anton Sizikov's solution is good, but will only work if the URL is absolute (like http://hhh.com). If using a relative URL, .NET will automatically merge the base address with the relative URL (therefore potentially resulting in an invalid URL).
To send a value to the OpenReadCompleted event handler, you're supposed to use this OpenRead overload to provide a custom token (in this case, your URL): http://msdn.microsoft.com/en-us/library/ms144212(v=vs.95).aspx
WebClient webClient = new WebClient();
webClient.OpenReadAsync(new Uri("http://hhh.com"), "http://hhh.com");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
Then to retrieve the value:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
var url = (string)e.UserState;
string strStream = reader.ReadToEnd();
}
}
}
For me even a simpler variation from the above works fine
private void CardInfoDown_Completed(object sender, DownloadStringCompletedEventArgs e)
{
string url;
if (e.Error == null)
{
url = (string)e.UserState;
}
// ...
}

Categories