Reputation: 769
I'm using BackgroundWorker for threading in my wpf application. But it makes the UI hung as I can't click anywhere of the UI. Here is my code snippet :
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
Dispatcher.Invoke(new Action(() => ConnectFtp()));
};
worker.RunWorkerAsync();
}
private void ConnectFtp()
{
try
{
int port = string.IsNullOrEmpty(txtport.Text) ? 21 : Convert.ToInt32(txtport.Text);
if (ftpserver1 == null)
{
ftpserver1 = new FtpClient(txtftpserver.Text, port);
ftpserver1.ServerResponse += new EventHandler<FtpResponseEventArgs>(ftpserver2_ServerResponse);
ftpserver1.ClientRequest += new EventHandler<FtpRequestEventArgs>(ftpserver2_ClientRequest);
ftpserver1.TransferProgress += new EventHandler<TransferProgressEventArgs>(ftpserver2_TransferProgress);
ftpserver1.TransferComplete += new EventHandler<TransferCompleteEventArgs>(ftpserver2_TransferComplete);
}
if (!ftpserver1.IsConnected)
{
Run r = new Run("Server1 Status: Resolving address of " + txtftpserver.Text + "\n" + "Server1 Status: Connection established, waiting for welcome message... \n");
r.Foreground = System.Windows.Media.Brushes.Black;
msg.Inlines.Add(r);
msgscroll.ScrollToBottom();
ftpserver2_OpenAsyncCompleted(ftpserver1, txtusername.Text, txtpassword.Password);
}
}
catch { }
}
In the ConnectFtp() method i'm connecting to a ftp server. The UI doesn't work when the connection state of ftp server is 'connecting'. but after completing the connection everything is okay! Please help me out ! thanks in advance!
Upvotes: 1
Views: 630
Reputation: 7249
You are dumping the complete method over to UI thread Dispatcher from the background worker. Here
Dispatcher.Invoke(new Action(() => ConnectFtp()));
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
ConnectFtp();
};
worker.RunWorkerAsync();
}
private void ConnectFtp()
{
// Here i'm connecting to a ftp server.
// Do some I/O operation
// Now time to update UI controls so we invoke on Dispatcher UI thread
Dispatcher.Invoke(new Action(() =>
{
lblMessage.Text = "Process finished";
// Some other UI updates..
}));
}
I suppose it would be better to take advantage of Task Parallel Api available in .NET 4.0 that works good on multi-core system i.e really parallel threading. Advantage of using TPL is that it uses closures on variables and UI elements so you can access the values on different thread and if it not work sometimes then create local variables before the Task starts and use it in Action method body and update UI controls using Dispatcher Invokes..
For example:
using System.Threading;
using System.Threading.Tasks;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Task TWorkOnFTP = new TaskFactory().StartNew(ConnectFtp);
}
private void ConnectFtp()
{
// Here i'm connecting to a ftp server.
// Do some I/O operation
// Now time to update UI controls so we invoke on Dispatcher UI thread
Dispatcher.Invoke(new Action(() =>
{
lblMessage.Text = "Process finished";
// Some other UI updates..
}));
}
Other related references:
As per updated question the TPL can be used as follows:
//Closures
var strPort = txtport.Text;
var strFTPServer = txtftpserver.Text;
var strUserName = txtusername.Text;
var strPassword = txtpassword.Password;
//Start Task thread
Task TProcessFTP = new TaskFactory().StartNew(new Action(() =>
{
try
{
int port = string.IsNullOrEmpty(strPort) ? 21 : Convert.ToInt32(strPort);
if (ftpserver1 == null)
{
ftpserver1 = new FtpClient(strFTPServer, port);
ftpserver1.ServerResponse += new EventHandler<FtpResponseEventArgs>(ftpserver2_ServerResponse);
ftpserver1.ClientRequest += new EventHandler<FtpRequestEventArgs>(ftpserver2_ClientRequest);
ftpserver1.TransferProgress += new EventHandler<TransferProgressEventArgs>(ftpserver2_TransferProgress);
ftpserver1.TransferComplete += new EventHandler<TransferCompleteEventArgs>(ftpserver2_TransferComplete);
}
if (!ftpserver1.IsConnected)
{
//Update UI Controls
Dispatcher.Invoke(new Action(() =>
{
Run r = new Run("Server1 Status: Resolving address of " + txtftpserver.Text + "\n" + "Server1 Status: Connection established, waiting for welcome message... \n");
r.Foreground = System.Windows.Media.Brushes.Black;
msg.Inlines.Add(r);
msgscroll.ScrollToBottom();
ftpserver2_OpenAsyncCompleted(ftpserver1, strUserName, strPassword);
}));
}
}
catch { }
}));
Upvotes: 1
Reputation: 10789
You are Invoking back onto the UI thread within the worker for the ConnectFTP
method. You need to have this...
BackgroundWorker _worker = new BackgroundWorker();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
ConnectFtp();
};
_worker.RunWorkerAsync();
}
private void ConnectFtp()
{
//here i'm connecting to a ftp server.
}
Upvotes: 7