When you need to make a long task, as calling remote WS, the best way to do not hang the client is using a thread in background and to be notified at the end of result.
With windows form application(main thread) you cannot update the form's control from the thread because it is a secondary thread.
It's important to make a thread safe programming using delegate and InvokeRequired/Control.Invoke methodology.
Eg.(c#):
//delegate per safe Progress bar invocation
private delegate void InvokeWithParam(int value); //the delegate signature need to be the same of method to call
public void UpdateProgressSafeParam(int value)
{
if (progress1.InvokeRequired) // this routine is calling from a main or secondary thread?
{
InvokeWithParam safeMethod=new InvokeWithParam(UpdateProgressSafeParam);
object[] par=new object [](value);
progressbar1.Invoke(safeMethod,par); // force the UpdateProgressSafeParam() function [recursion]
// to run in the same thread of the control(main).
//So will go in a queue to be recall from the main thread and in that situation it fall down in the else branch!
}
else progressbar1.value=value; //I'm in main thread so can update the progressbar control directly!
}
Eg.(VBNET) working with the main form(me.invoke) instead of a control:
delegate Function GetTextDelegate(ByVal ctrl as Control) as String
'This method might run on a non-UI thread (eg: in a timer event of one instance of System.Timers.Timer)
Sub PerformTask()
'read the Text property of txtUserName UI control
Dim userName as String
if Not Me.InvokeRequired then
userName = GetText(txtUserName) 'direct access is safe
else
' Call the method indirectly by using a delegate
Dim args() as Object = {txtUserName} ''the parameters are passed as an array of objects
userName = CStr(Me.Invoke(New GetTextDelegate(GetText), args))
end if
' userName now contains the value of txtUserName.Text
...
...
End Sub
Function GetText(ByVal ctrl as Control) As String
Return ctrl.Text
End Function