Is there any existing plumbing to run WCF calls in batches in a BackgroundWorker?
Obviously since all Silverlight WCF calls are async - if I run them all in a backgroundworker they will all return instantly.
I just don't want to implement a nasty hack if theres a nice way to run service calls and collect the results.
Doesnt matter what order they are done in
All operations are independent
I'd like to have no more than 5 items running at once
Edit: i've also noticed (when using Fiddler) that no more than about 7 calls are able to be sent at any one time. Even when running out-of-browser this limit applies. Is this due to my default browser settings - or configurable also. obviously its a poor man's solution (and not suitable for what i want) but something I'll probably need to take account of to make sure the rest of my app remains responsive if i'm running this as a background task and don't want it using up all my connections.
I think your best bet would be to have your main thread put service request items into a Queue that is shared with a BackgroundWorker thread. The BackgroundWorker can then read from the Queue, and when it detects a new item, initiate the async WCF service request, and setup to handle the AsyncCompletion event. Don't forget to lock the Queue before you call Enqueue() or Dequeue() from different threads.
Here is some code that suggests the beginning of a solution:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace MyApplication
{
public class RequestItem
{
public string RequestItemData { get; set; }
}
public class ServiceHelper
{
private BackgroundWorker _Worker = new BackgroundWorker();
private Queue<RequestItem> _Queue = new Queue<RequestItem>();
private List<RequestItem> _ActiveRequests = new List<RequestItem>();
private const int _MaxRequests = 3;
public ServiceHelper()
{
_Worker.DoWork += DoWork;
_Worker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
while (!_Worker.CancellationPending)
{
// TBD: Add a N millisecond timer here
// so we are not constantly checking the Queue
// Don't bother checking the queue
// if we already have MaxRequests in process
int _NumRequests = 0;
lock (_ActiveRequests)
{
_NumRequests = _ActiveRequests.Count;
}
if (_NumRequests >= _MaxRequests)
continue;
// Check the queue for new request items
RequestItem item = null;
lock (_Queue)
{
RequestItem item = _Queue.Dequeue();
}
if (item == null)
continue;
// We found a new request item!
lock (_ActiveRequests)
{
_ActiveRequests.Add(item);
}
// TBD: Initiate an async service request,
// something like the following:
try
{
MyServiceRequestClient proxy = new MyServiceRequestClient();
proxy.RequestCompleted += OnRequestCompleted;
proxy.RequestAsync(item);
}
catch (Exception ex)
{
}
}
}
private void OnRequestCompleted(object sender, RequestCompletedEventArgs e)
{
try
{
if (e.Error != null || e.Cancelled)
return;
RequestItem item = e.Result;
lock (_ActiveRequests)
{
_ActiveRequests.Remove(item);
}
}
catch (Exception ex)
{
}
}
public void AddRequest(RequestItem item)
{
lock (_Queue)
{
_Queue.Enqueue(item);
}
}
}
}
Let me know if I can offer more help.
Related
I have an winform application which consumes windows service, i user ChannelFactory
to connect to service, problem is when i call service method using channel the memory usage increase and after
method execute memory not go down(even after form close), i call GC.Collect but no change
channel Create class
public class Channel1
{
List<ChannelFactory> chanelList = new List<ChannelFactory>();
ISales salesObj;
public ISales Sales
{
get
{
if (salesObj == null)
{
ChannelFactory<ISales> saleschannel = new ChannelFactory<ISales>("SalesEndPoint");
chanelList.Add(saleschannel);
salesObj = saleschannel.CreateChannel();
}
return salesObj;
}
}
public void CloseAllChannels()
{
foreach (ChannelFactory chFac in chanelList)
{
chFac.Abort();
((IDisposable)chFac).Dispose();
}
salesObj = null;
}
}
base class
public class Base:Form
{
public Channel1 channelService = new Channel1();
public Channel1 CHANNEL
{
get
{
return channelService;
}
}
}
winform class
Form1:Base
private void btnView_Click(object sender, EventArgs e)
{
DataTable _dt = new DataTable();
try
{
gvAccounts.AutoGenerateColumns = false;
_dt = CHANNEL.Sales.GetDatatable();
gvAccounts.DataSource = _dt;
}
catch (Exception ex)
{
MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
finally
{
CHANNEL.CloseAllChannels();
_dt.Dispose();
//GC.Collect();
}
}
You're on the right track in terms of using ChannelFactory<T>, but your implementation is a bit off.
ChannelFactory<T> creates a factory for generating channels of type T. This is a relatively expensive operation (as compared to just creating a channel from the existing factory), and is generally done once per life of the application (usually at start). You can then use that factory instance to create as many channels as your application needs.
Generally, once I've created the factory and cached it, when I need to make a call to the service I get a channel from the factory, make the call, and then close/abort the channel.
Using your posted code as a starting point, I would do something like this:
public class Channel1
{
ChannelFactory<ISales> salesChannel;
public ISales Sales
{
get
{
if (salesChannel == null)
{
salesChannel = new ChannelFactory<ISales>("SalesEndPoint");
}
return salesChannel.CreateChannel();
}
}
}
Note that I've replaced the salesObj with salesChannel (the factory). This will create the factory the first time it's called, and create a new channel from the factory every time.
Unless you have a particular requirement to do so, I wouldn't keep track of the different channels, especially if follow the open/do method/close approach.
In your form, it'd look something like this:
private void btnView_Click(object sender, EventArgs e)
{
DataTable _dt = new DataTable();
try
{
gvAccounts.AutoGenerateColumns = false;
ISales client = CHANNEL.Sales
_dt = client.GetDatatable();
gvAccounts.DataSource = _dt;
((ICommunicationObject)client).Close();
}
catch (Exception ex)
{
((ICommunicationObject)client).Abort();
MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
The code above gets a new ISales channel from the factory in CHANNEL, executes the call, and then closes the channel. If an exception happens, the channel is aborted in the catch block.
I would avoid using Dispose() out of the box on the channels, as the implementation in the framework is flawed and will throw an error if the channel is in a faulted state. If you really want to use Dispose() and force the garbage collection, you can - but you'll have to work around the WCF dispose issue. Google will give you a number of workarounds (google WCF Using for a start).
I am using a System.Threading.Timer in a CF project (Windows Embedded CE 6.0), VS2005 C#, .NET 2.0.
This timer is desired because there is no possibility of reentrancy when used like this:
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e)
{
// other initializations
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick),
null, 100, Timeout.Infinite);
}
Which is to say, dueTime parameter is used but period is not. As long as period is Timeout.Infinite, the timer will fire once only. The timer is made thread-safe by checking for the form's InvokeRequired property. Note the check for null. It relates to my question, which I am getting to quickly.
private void timerMain_Tick(object stateInfo)
{
if (mainTimer != null)
{
if (this.InvokeRequired)
{
this.Invoke((ThreadStart)delegate
{
TimerProcess();
});
}
else
{
TimerProcess();
}
}
}
The timer must restart itself before it exits.
private void TimerProcess()
{
try
{
// do work here
}
finally
{
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
The problem I am having is gracefully stopping this darn thing.
private void MainForm_Closing(object sender, CancelEventArgs e)
{
// shut down timer
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
About 3 times in 10, the timer fires anyway, and I get an Object Disposed error. The timer code is trying to invoke the timer method AFTER the check for null.
I suspect that the timer fires, and its thread is suspended while the form is closing. I tried a state machine enumeration:
Normal state Running
Form_Closing sets Stopping state and waits in a Thread.Sleep() loop for Stopped state
Timer sees Stopping and sets Stopped state (rather than retriggering itself)
Problem I had with this is that the timer thread would not preempt the form closing method, so get stuck in endless loop.
How to fix this problem? Note that in CF, there is no Dispose(WaitHandle) method.
Interesting problem. There do not seem to be many options with the Timer in the Compact Framework.
I'm not sure how your specific code works, so adding a single static Boolean value may or may not fix your issues.
Here is how I changed your code to accept a timerOK value. If this does not solve your problem, it could give you ideas on how to approach this.
private static bool timerOK;
private static long mainTimerInterval = 200;
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e) {
timerOK = true;
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick), null, 100, Timeout.Infinite);
}
private void MainForm_Closing(object sender, CancelEventArgs e) {
timerOK = false;
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
private void timerMain_Tick(object stateInfo) {
if (timerOK && (mainTimer != null)) {
if (this.InvokeRequired) {
this.Invoke((ThreadStart)delegate {
TimerProcess();
});
} else {
TimerProcess();
}
}
}
private void TimerProcess() {
if (!timerOK) return;
try {
// do work here
} finally {
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
I'm using MVP so my layout is a little different, but essentially I had the same two problems to fix:
Stop the timer firing after targets in the process method are disposed
Stop the timer firing DURING disposal
First one is easily fixed as pwrgreg007 shows above, just shutdown and null the timer sometime in your 'closing' process (before the form targets are disposed) and then do a null check at the start of your timer processing event.
Second issue is a bit trickier, even if the timer (and your form) are running at the start of your processing loop, nothing stops it getting shutdown mid way through the process as it is running on a different thread. To prevent this I created a lock to be used both during the timer execution AND the timer shutdown.
//simplified presenter
public class Presenter
{
private const int REFRESH_TIME_MILLISECONDS = 5000;
private view _view;
private Timer _timer;
private object _timerLock = new object();
//CTOR
public Presenter()
{
_view = new View();
Startup();
}
//spin up presenter
public void Startup(){
//bind view shutdown event
_view.ViewClosing += Shutdown;
//start timer
_timer = new Timer(DoTimerStuff, null, REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
//spin down presenter
public void Shutdown()
{
//wait for any DoTimerStuff locks to expire
lock (_timerLock)
{
//stop the timer
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
}
//close the view
_view.Shutdown();
}
//timer tick
private void DoTimerStuff(object state)
{
//grab a lock so we can ensure the timer doesn't get shutdown mid way through
lock (_timerLock)
{
//make sure the timer isn't shutdown (from form closing)
if (_timer == null) return;
//do your stuff here
_view.SomeInvokedCheckedProperty = "SomeValue";
//etc...
//schedule next timer execute (runs every runtime + refresh time)
_timer.Change(REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
}
}
//simplified view
public class View : Form
{
//view properties (make sure they are invoke checked)
public SomeInvokedCheckedProperty {get;set;}
//Bound to ViewClosing
private void View_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//stop the view closing itself
e.Cancel = true;
//tell the presenter to handle closing instead
if (ViewClosing != null) ViewClosing.Invoke();
}
}
That way..
The timer will wait to shutdown (holding up your form close) if DoTimerStuff() has the lock and is currently running
Conversely, DoTimerStuff() will wait if the timer shutdown has the lock and when it gets to continue it will correctly see the timer is shutdown (and do nothing).
Just getting my head around WCF, so forgive me for the inelegant coding.
The issue I'm having is I seem to be submitting data twice to my service (see screenshot), even though (I think) I'm only doing it once.
Could someone please let me know what I might be doing wrong? Or even just suggest a better way to do it if I'm doing it inefficiently.
Code follows:
public void EndOfLevel()
{
GlobalVariable.TotalQuestionsAsked = 10;
GlobalVariable.CorrectDecimal = GlobalVariable.Correct / GlobalVariable.TotalQuestionsAsked;
//Show loading screen
UploadingScreen.Visibility = Visibility.Visible;
//Submit this levels results.
Service1Client client = null;
client = new Service1Client();
//Gather the results and details
Result thislevel = new Result();
thislevel.Datetime = DateTime.Now;
thislevel.result = GlobalVariable.CorrectDecimal;
thislevel.TimesTable = GlobalVariable.NeedsHelpWith;
//submit them
try
{
client.SubmitResultAsync(thislevel);
}
catch
{
MessageBox.Show("Error uploading data");
}
finally
{
client.Close();
Results r3 = new Results();
this.NavigationService.Navigate(r3);
}
}
WCF Test Client:
Cheers,
Nick
If I may, here's a pattern for managing our asynchronous calls between our WPF applications and our WCF Services.
In this section we have a public accessor to our service client that ensures that the connection to the client is open prior to calling a service method:
public static MyServiceClient Client
{
get
{
return GetMyServiceClient();
}
}
private static MyServiceClient client;
private static MyService.MyServiceClient GetMyServiceClient()
{
VerifyClientConnection();
return client;
}
private static void VerifyClientConnection()
{
if (client == null || client.State == System.ServiceModel.CommunicationState.Closed)
{
client = new MyService.MyServiceClient();
}
}
And in this section is an example of our asynchronous call and callback pattern (this example shows the delegate and callback we're using for passing exception data to our service):
public delegate void LogExceptionCompletedEvent();
public static LogExceptionCompletedEvent LogExceptionCompleted;
public static void LogExceptionAsync(SilverlightException exception)
{
string json = JsonConvert.SerializeObject(exception);
Client.LogExceptionCompleted -= client_LogExceptionCompleted;
Client.LogExceptionCompleted += client_LogExceptionCompleted;
Client.LogExceptionAsync(json);
}
private static void client_LogExceptionCompleted(object sender, AsyncCompletedEventArgs e)
{
if (LogExceptionCompleted != null)
{
LogExceptionCompleted();
}
}
In this example, a view model could attach an event handler to the LogExceptionCompleted delegate and in turn receive the result of the callback when it returns from the service.
We basically repeat this pattern for the asynchronous WCF service calls we need to make from our application and it keeps them very organized as well as unit testable.
I have created sample application and implemented threading. basically aim to craete this application is i would like to
If any process(s) are runnig then User Interface should Notify
[DONE]
Handle dynamically created thread with ProgressBar [DONE]
Provide addition functionality to Start, Pause and Stop thread from
available progress list. [NEED YOUR HELP]
Note:- I don't have much knowledge about Threading and Delegates, so please let me know best solution for existing code.
Files and Controls are used:-
Basically three files are used in this demo application
ProgressForm.cs (Window Form)
which conatains Button for creating new progress and Container whic will hold all the created progressbars
ProgressClass.cs
Which contains Dynamic Threading and Delegates to Notify UI without locking or hanging user interface
ProgressControl.cs (User Control)
Which contains
Progressbar (to display process done)
Precent Label (display percentage of completed progress)
Start/Pause button (for play/pause a thread)
Stop button (stop running thread and remove progress from list)
StartTime Label (display process started time)
EndTime label (display time of process completed)
MaxValue Lable (generate random number between 25 to 100)
CODE SNIPPET:-
1. ProgressForm .cs
public partial class ProgressForm : Form
{
Random randomMaxValue = new Random();
public ProgressForm()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressClass m_clsProcess;
ProgressControl progress = new ProgressControl();
progress.StartedAt = DateTime.Now;
progress.MinValue = 0;
progress.CurrentValue = 0;
progress.MaxValue = randomMaxValue.Next(25, 100);
AddControl(progress);
m_clsProcess = new ProgressClass(progress, this, new ProgressClass.NotifyProgress(DelegateProgress));
m_clsProcess.Start();
}
private void DelegateProgress(int CurrentValue, ProgressControl Progress)
{
ProgressBar p = (ProgressBar)Progress.Controls.Find("pgbPercent", false)[0];
p.Minimum = Progress.MinValue;
p.Value = CurrentValue;
p.Maximum = Progress.MaxValue;
Label percent = (Label)Progress.Controls.Find("lblPercent", false)[0];
percent.Text = string.Format("{0:#00} %", Convert.ToInt16((CurrentValue * 100) / Progress.MaxValue));
Label start = (Label)Progress.Controls.Find("lblStart", false)[0];
start.Text = string.Format("{0:HH:mm:ss}", Progress.StartedAt);
if (CurrentValue == Progress.MaxValue)
{
Label complete = (Label)Progress.Controls.Find("lblComplete", false)[0];
complete.Text = string.Format("{0:HH:mm:ss}", DateTime.Now);
Progress.Status = ProgressControl.ProgressStatus.Completed;
}
Label max = (Label)Progress.Controls.Find("lblMaxValue", false)[0];
max.Text = string.Format("{0:#00}", Progress.MaxValue);
Button btnstartstop = (Button)Progress.Controls.Find("btnStartStop", false)[0];
btnstartstop.Click += new EventHandler(ProgressStartStop);
}
private void AddControl(Control ctl)
{
tableLayoutPnl.RowCount += 1;
tableLayoutPnl.RowStyles.Add(new RowStyle());
ctl.Dock = DockStyle.Fill;
tableLayoutPnl.Controls.Add(ctl, 0, tableLayoutPnl.RowCount - 1);
}
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
//
}
}
2. ProgressControl.cs
public partial class ProgressControl : UserControl
{
public enum ProgressStatus
{
Initialize,
Running,
Paused,
Completed
}
public DateTime StartedAt { get; set; }
public DateTime CompletedAt { get; set; }
public int MinValue { get; set; }
public int CurrentValue { get; set; }
public int MaxValue { get; set; }
public ProgressStatus Status { get; set; }
public ProgressControl()
{
InitializeComponent();
this.Status = ProgressStatus.Initialize;
}
}
3. ProgressClass.cs
public class ProgressClass
{
private int ThreadWaitTime = 100;
private ProgressControl m_progress;
private NotifyProgress m_clsNotifyDelegate;
private System.Threading.Thread m_clsThread;
private System.ComponentModel.ISynchronizeInvoke m_clsSynchronizingObject;
public delegate void NotifyProgress(int PercentComplete, ProgressControl Progress);
public ProgressClass(ProgressControl Progress, System.ComponentModel.ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
{
m_progress = Progress;
m_clsSynchronizingObject = SynchronizingObject;
m_clsNotifyDelegate = NotifyDelegate;
}
public void Start()
{
m_clsThread = new System.Threading.Thread(DoProcess);
m_clsThread.Name = "Background Thread";
m_clsThread.IsBackground = true;
m_progress.Status = ProgressControl.ProgressStatus.Running;
m_clsThread.Start();
}
private void DoProcess()
{
for (int i = m_progress.MinValue; i <= m_progress.MaxValue; i++)
{
NotifyUI(i);
Thread.Sleep(ThreadWaitTime);
}
}
private void NotifyUI(int Value)
{
object[] args = new object[2];
args[0] = Value;
args[1] = m_progress;
m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
}
}
I am not asking for write whole code instead of provide hint.
I would like to start/pause relevent thread from list, os what should i do for that?
I would like hind in following function:
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
}
UPDATED:
You will want to use a ManualResetEvent or ManualResetEventSlim to create the pause and resume behavior in the thread. The idea is to check the state of the event in the worker thread at safe points. This is done via the WaitOne or Wait methods. If the event is signaled then the calls will return immediately allowing the thread to proceed. If the event is unsignaled then the calls block until the event is signaled via the Set method. So to pause the thread you would call Reset to unsignal the event and to resume the thread you would call Set.
Just remember to place calls to WaitOne or Wait at safe points in the instruction sequence of the worker thread. In other words, do not call these methods inside a lock or something like that. At the beginning or end of a loop is often a good start.
Also, it looks like you use the Invoke method for updating the UI. That is all fine and good, but for simply updating the UI with progress information there is a better option. It is better to publish the progress information to a shared data structure and then have the UI thread pick it up via a timer. For those that monitor my answers I harp about this a lot, I know. But, this strategy has a lot of advantages.
It breaks the tight coupling between the UI and worker threads that Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
It avoids the subtle race conditions that can occur when trying to gracefully end the worker thread.
It is more efficient since Invoke is an expensive operation.
Update:
Here is the general idea regarding the changes that could be made to ProgressStartStop.
private Dictionary<int, ThreadInfo> threads = new Dictionary<int, ThreadInfo>();
void ProgressStartStop(object sender, EventArgs e)
{
Button button = sender as Button;
int index = GetThreadIndexFromButton(button);
if (!threads.ContainsKey(index))
{
// The thread has not been started yet so do it now.
var thread = new Thread(RunThread);
thread.Start();
var mres = new ManualResetEventSlim(true);
var info = new ThreadInfo { Thread = thread, ProceedSignal = mres };
threads.Add(index, info);
// Change the button image here.
}
else
{
ThreadInfo info = threads[index];
if (info.ProceedSignal.Wait(0))
{
// The event is signaled which means the thread is running. Pause it.
info.ProceedSignal.Reset();
// Change the button image here.
}
else
{
// The event is unsignaled which means the thread is paused. Resume it.
info.ProceedSignal.Set();
// Change the button image here.
}
}
}
private class ThreadInfo
{
Thread Thread { get; set; }
ManualResetEventSlim ProceedSignal { get; set; }
}
It is generally considered bad practice to Suspend threads (though it is possible). The right way to pause and terminate threads is through the cooperation with the job that the thread is doing. The job should check a variable in a loop, and pause or exit accordingly. The controlling program can set that variable, and if you need feedback the background thread can call a notification method before exiting or sleeping.
Currently, I 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();
}
Which works fine - this example was taken from the samples. However, after a recent re-visit I have a question. In this particular case since OnResponse() function doesn't update the UI, it seems to serve no purpose here. I removed it (as well as all the calls to it) and it still works like before. Am I missing something?
After reading up more about multi threading with forms, I came to understand that this mechanism (demonstrated in the code above) is there to make sure the UI is responsive.
So in case when we need to say, update a UI element (such as textbox, label etc) we would have OnResponse implemented as follows:
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;
}
}
What's the use to have it at all? Is it absolutely necessary?
And another question: is ftp object running on its own thread here?
The FTP object is definitely running on its own thread. How do 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 a thread from the .NET threadpool to do all of the work. This dedicated thread is the one that is used to "raise" the events. Ultimately a "raised event" is just one or more method calls to all of the delegates added to the event invocation list; it is this dedicated thread spun up by the Begin method that calls these methods. This thread is not the same thread as the thread that runs the UI, hence the need for the Invoke calls.
If you want the FTP component to use the UI thread, you'd use the Connect method instead of the BeginConnect method. This means your events wont work either, nor will your UI respond to interaction - this is completely expected because a thread can only do one thing at a time: it's either servicing the UI, or executing the FTP code. This is why you need a 2nd thread.
Make sense?
-Oisin