线程冻结主UI

时间:2014-08-09 15:03:51

标签: c# .net wpf multithreading dispatcher

您好,我正在编写服务器监控应用程序

    public class Server
    {
            public string SERVERNAME;
            public string ENVIRONMENT;
            public string VERSION;

            public string CPU_PERCETAGE;
            public string CPU_NAME;
            public string CPU_DESCRIPTION;
            public string CPU_VOLTAGE;
    }

我目前有一个Page wihtin我的主窗口,我在那里Exucute并填写数据:
方法

try
 {
   {
    Thread test = new Thread(() =>
    {
     datagrid_Disks.Dispatcher.BeginInvoke(
      new Action(() =>
      {
        datagrid_Disks.ItemsSource = Server.GetDisksInfo(textbox_Username.Text,
                                                           textbox_password.Password,
                                                           textbox_IP.Text,
                                                           textbox_Domain.Text);
      }));
     });
     test.Start();
  }
  catch (UnauthorizedAccessException)
  {
    Worker.ShowModernBox("Onjuiste gebruiksersnaam" + Environment.NewLine + "of wachtwoord.");
  }
  catch (ManagementException)
  {
   Worker.ShowModernBox("Server geeft geen Response." + Environment.NewLine + "Controleer Aub de instelling.");
  }

问题

  

我的mainThread等待线程完成,似乎无法弄清楚为什么会发生这种情况。

所有帮助表示赞赏!

1 个答案:

答案 0 :(得分:8)

问题是Dispatcher.Invoke阻止了UI线程,因此任何Invoke都应该尽可能小。

将您耗时的代码放在调用之外以解决问题。

正如@RohitVals指出的那样,你无法从后台线程访问UI控件,所以你必须使用2个调用 - 一个用于获取文本值,一个用于设置ItemsSource

Thread test = new Thread(() =>
{
    String text, password, ipText, domainText;

    // !!!!!!This one should be simple Invoke because otherwise variables may not get their         
    // values before calls. Thanks @ScottChamberlain.!!!!!!
    datagrid_Disks.Dispatcher.Invoke(
      new Action(() =>
      {
          text = textbox_Username.Text;
          password = textbox_password.Password;
          ipText = textbox_IP.Text,
          domainText = textbox_Domain.Text
      }));


     var result = Server.GetDisksInfo(text, 
         password, 
         ipText,
         domainText);

     datagrid_Disks.Dispatcher.BeginInvoke(
      new Action(() =>
      {
        datagrid_Disks.ItemsSource = result;
      }));
 });

 test.Start();

或(感谢@RohitVals)

您可以在运行线程之前获取这些值以避免双重调度:

text = textbox_Username.Text;
// ...

Thread test = ...

您可能想尝试MVVM模式 - http://msdn.microsoft.com/en-us/magazine/dd419663.aspx。它可能看起来令人生畏,而且过于复杂,一开始没有优势或没有什么优势,但随着时间的推移你会看到它的优点。

这篇特别的文章涉及MVVM和Dispathcer - http://msdn.microsoft.com/en-us/magazine/dn630646.aspx

P.S。:如果您的GetDisksInfo方法使用延迟执行(如LINQ),那么您应该在使用之前枚举结果:

 var result = Server.GetDisksInfo(text, 
         password, 
         ipText,
         domainText).ToArray();