2014-01-29 5 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);    

только один доступ к ГИП «вар myItems = myWpfDataGrid.SelectedItems;» и только для чтения! Функция «DoLoooongWork()» имеет доступ к последовательным портам и т. Д. Это разделенная функция SDK, которая не имеет доступа к графическому интерфейсу. Я знаю, что «Dispatcher.BeginInvoke» немного избыточен, но я не знаю, что я могу сделать, или что я делаю неправильно. Единственная причина для этого кода - освободить GUI, пока выполняется «DoLoooongWork()», но графический интерфейс заморожен!

Что не так с этим кодом?

редактировать

Благодаря @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

Замораживание происходит, когда вы заменяете DoLoooongWork на Thread.Sleep? – 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.

[UPDATE] Вы упоминали в комментариях, что код внутри 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); 
     // ... 
    } 
} 

Это будет совсем другая история. Оставьте комментарий, если это так, и вас все еще интересует какое-то решение.

Смежные вопросы