1

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!

Mushfiq
  • 759
  • 1
  • 8
  • 41

2 Answers2

7

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. 
}
aqwert
  • 10,559
  • 2
  • 41
  • 61
  • I am not sure what you have in the `ConnectFtp` method. But if want to display any results you can use the `args` param to set the result and then attach to the `Completed` event of the worker. – aqwert Sep 06 '12 at 05:45
  • I've edited my question. I've given the full ConnectFtp() method – Mushfiq Sep 06 '12 at 05:55
1

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:

Update

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 { }
    }));
Community
  • 1
  • 1
Harsh Baid
  • 7,199
  • 5
  • 48
  • 92
  • 2
    thanks for reply !! the same thing I've did! but the problem still hitting me !! – Mushfiq Sep 06 '12 at 06:50
  • I think comment the `msgscroll.ScrollToBottom();` line and retry the to test UI again ? – Harsh Baid Sep 06 '12 at 08:26
  • Can you reduce some unwanted update to UI controls such as logs and change them to memory variable like StringBuilder and when you finish or reach some String capacity or Threshold or condition then dump to UI all partial or full dump at finish.. – Harsh Baid Sep 06 '12 at 10:02