OpenNetCF class multithreading issue
I currently have something like:
public partial class Form1 : Form
{
delegate void StringDelegate(string value);
private FTP m_ftp;
public Form1()
{
InitializeComponent();
}
private void connect_Click(object sender, EventArgs e)
{
OnResponse("Connecting");
m_ftp = new FTP(server.Text);
m_ftp.ResponseReceived += new FTPResponseHandler(m_ftp_ResponseReceived);
m_ftp.Connected += new FTPConnectedHandler(m_ftp_Connected);
m_ftp.BeginConnect(user.Text, password.Text);
}
void m_ftp_Connected(FTP source)
{
// when this happens we're ready to send command
OnResponse("Connected.");
}
void m_ftp_ResponseReceived(FTP source, FTPResponse Response)
{
OnResponse(Response.Text);
}
private void OnResponse(string response)
{
if (this.InvokeRequired)
{
this.Invoke(new StringDelegate(OnResponse), new object[] { response } );
return;
}
}
private void getFileList_Click(object sender, EventArgs e)
{
FTPFiles files = m_ftp.EnumFiles();
fileList.Items.Clear();
foreach (FTPFile file in files)
{
fileList.Items.Add( new ListViewItem( new string[] { file.Name, file.Size.ToString() } ));
}
tabs.SelectedIndex = 1;
}
private void upload_Click(object sender, EventArgs e)
{
FileStream stream = File.OpenRead("\\My Documents\\My Pictures\\Waterfall.jpg");
m_ftp.SendFile(stream, "waterfall.jpg");
stream.Close();
}
What works well - this example was taken from samples. However, after a recent return visit, I have a question. In this particular case, since the OnResponse () function does not update the UI, there seems to be no purpose here. I removed it (like all of its calls) and it still works like it did before. Did I miss something?
After reading more about multithreading with forms, I realized that this mechanism (demonstrated in the code above) is to make sure the UI is responsive.
So, if we need to say by updating a UI element (like a textbox, a label, etc.), we would execute an OnResponse like this:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(!InvokeRequired)
{
button1.Text = dummy;
}
else
Invoke(new StringDelegate(OnResponse),new object[] {enabled});
}
If this function is implemented as:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(InvokeRequired)
{
Invoke(new StringDelegate(OnResponse),new object[] {dummy});
return;
}
}
How to use it? Is it absolutely necessary?
And another question: is there an ftp object running on its own thread here?
a source to share
The FTP object definitely runs on its own stream. How should I know? This line:
m_ftp.BeginConnect(user.Text, password.Text);
This is an asynchronous method. Once you call this, the FTP component will use the .NET threadpool to do all the work. This dedicated thread is the one used to "boost" events. Ultimately, a "raised event" is just one or more method calls for all delegates added to the list of event calls; it is this dedicated thread that is deployed by the Begin method that calls these methods. This thread is not the same thread as the thread that launches the UI and therefore invokes Invoke calls.
If you want the FTP component to use the UI thread, you must use the Connect method instead of the BeginConnect method. This means that your events won't work either, and your UI is unresponsive to interaction - which is completely expected because a thread can only do one thing: either serve the UI at the same time or execute FTP code. This is why you need a second thread.
Make sense?
-Oisin
a source to share