【问题标题】:UI is hung when BackgroundWorker() runs当 BackgroundWorker() 运行时 UI 挂起
【发布时间】:2012-09-06 05:39:24
【问题描述】:

我在我的 wpf 应用程序中使用 BackgroundWorker 进行线程化。但这会使 UI 挂起,因为我无法单击 UI 的任何位置。这是我的代码 sn-p :

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 { }
}

在 ConnectFtp() 方法中,我连接到一个 ftp 服务器。当 ftp 服务器的连接状态为“正在连接”时,UI 不起作用。但完成连接后一切正常! 请帮帮我! 提前致谢!

【问题讨论】:

  • 您可以尝试后台工作人员的ReportProgress 方法进行任何您想要的更改
  • @Shishir 你的问题现在解决了吗?
  • @HarshBaid 我发现了问题。是库导致问题。感谢您的建议!

标签: c# wpf multithreading backgroundworker


【解决方案1】:

您正在为ConnectFTP 方法调用回worker 内的UI 线程。你需要这个...

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. 
}

【讨论】:

  • 我不确定您在 ConnectFtp 方法中有什么。但是如果要显示任何结果,您可以使用args 参数设置结果,然后附加到工作人员的Completed 事件。
  • 我已经编辑了我的问题。我已经给出了完整的 ConnectFtp() 方法
【解决方案2】:

您正在将完整的方法从后台工作程序转储到 UI 线程 Dispatcher。 这里

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..
     }));
}

我想最好利用 .NET 4.0 中可用的 Task Parallel Api,它在多核系统上运行良好,即真正的并行线程。使用 TPL 的优点是它对变量和 UI 元素使用闭包,因此您可以访问不同线程上的值,如果有时它不起作用,则在 Task 启动之前创建局部变量并在 Action 方法主体中使用它并使用 Dispatcher 更新 UI 控件调用..

例如:

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..
     }));
}

其他相关参考:

更新

根据更新后的问题,TPL 可按如下方式使用:

    //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 { }
    }));

【讨论】:

  • 感谢回复!!我做过同样的事情!但问题仍然困扰着我!
  • 我认为评论msgscroll.ScrollToBottom(); 行并重试再次测试用户界面?
  • 您能否减少对 UI 控件(例如日志)的一些不需要的更新,并将它们更改为 StringBuilder 等内存变量,当您完成或达到某个字符串容量或阈值或条件时,然后将所有部分或全部转储转储到 UI在完成..
猜你喜欢
  • 2021-12-29
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 2021-08-22
  • 2014-07-12
  • 1970-01-01
  • 2015-03-25
  • 1970-01-01
相关资源
最近更新 更多