2014-01-29 82 views
4

我在TPL世界是新的,而我做了代码:为什么我的GUI冻结?

var myItems = myWpfDataGrid.SelectedItems; 

    this.Dispatcher.BeginInvoke(new Action(() => 
    { 
     var scheduler = new LimitedConcurrencyLevelTaskScheduler(5); 
     TaskFactory factory = new TaskFactory(scheduler); 

     foreach (MyItem item in myItems) 
     { 
      Task myTask = factory.StartNew(() => 

      DoLoooongWork(item)     

       ).ContinueWith((t) => 
       { 
        Debug.WriteLine(t.Exception.Message); 
        if (t.Exception.InnerException != null) 
        { 
         Debug.WriteLine(t.Exception.InnerException.Message); 
        } 
       }, 
       TaskContinuationOptions.OnlyOnFaulted); 
     } 
    }), null);    

唯一一个进入GUI是 “VAR myItems = myWpfDataGrid.SelectedItems;” ,它是只读的!函数“DoLoooongWork()”可以访问串口等。它是一个独立的SDK函数,不能访问GUI。我知道“Dispatcher.BeginInvoke”有点多余,但我不知道我能做什么,或者我做错了什么。此代码的唯一原因是在执行“DoLoooongWork()”时释放GUI,但GUI被冻结!

该代码有什么问题?

编辑

感谢@Euphoric的帮助,我才发现,类似于职位的问题: COM Interop hang freezes entire COM system. How to cancel COM call

+1

您是否尝试过在没有工厂的情况下做例如。只是新的任务和开始?没有调度员。像http://blog.yojimbocorp.com/2012/05/22/using-task-for-responsive-ui-in-wpf/ – Euphoric

+0

@Euphoric是的,我做了。事实上,我的原始代码没有工厂,也没有调度程序。我加入了我的绝望:) –

+1

当你用Thread.Sleep替换DoLoooongWork时,冻结是否会发生? – Euphoric

回答

1

我预感到一些与串口工作会尝试使用应用程序的事件循环做它的工作。所以它实际上绕过了整个调度程序和线程系统并阻塞了应用程序。我在这个领域没有经验,所以我不知道如何解决它,但这是不同的问题。

3

我认为DoLoooongWork中的一些对象需要线程关联和消息抽取。试试我的ThreadWithAffinityContext,看看是否有帮助,像这样使用:

private async void Button_Click(object sender, EventArgs e) 
{ 
    try 
    {   
     using (var staThread = new Noseratio.ThreadAffinity.ThreadWithAffinityContext(
      staThread: true, pumpMessages: true)) 
     { 
      foreach (MyItem item in myItems) 
      { 
       await staThread.Run(() => 
       { 
        DoLoooongWork(item); 
       }, CancellationToken.None); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
    } 
} 

More info about ThreadWithAffinityContext

[更新]您在评论里面DoLoooongWork的代码看起来像这样提到:

zkemkeeper.CZKEM axCZKEM1 = new zkemkeeper.CZKEM(); 
axCZKEM1.Connect_Net(ip, port); 

我从来没有听说过“zkemkeeper”之前,但我做了一个简单的搜索,发现this question。显然,只有Connect_Net建立连接并启动一个会话,而整个通信逻辑通过一些事件是异步进行的,因为这个问题表明:

bIsConnected = axCZKEM1.Connect_Net("192.168.0.77", Convert.ToInt32("4370")); 
if (bIsConnected == true) 
{ 
    iMachineNumber = 1; 
    if (axCZKEM1.RegEvent(iMachineNumber, 65535)) 
    { 
     this.axCZKEM1.OnFinger += new kemkeeper._IZKEMEvents_OnFingerEventHandler(axCZKEM1_OnFinger); 
     this.axCZKEM1.OnVerify += new zkemkeeper._IZKEMEvents_OnVerifyEventHandler(axCZKEM1_OnVerify); 
     // ... 
    } 
} 

这将是一个完全不同的故事。如果是这种情况,请发表评论,并且您仍对某些解决方案感兴趣。