2013-11-11 2 views
0

Я улучшаю приложение форм C# win forms, которое взаимодействует с SalesForce CRM через webservices.не может сделать многопоточные безопасные вызовы для управления формами окон

У меня есть следующий код, чтобы сделать «Потокобезопасную» обновление метки на моей форме:

delegate void SetTextCallback(string text); 

private void SetText(string text) 
    { 
     // InvokeRequired required compares the thread ID of the 
     // calling thread to the thread ID of the creating thread. 
     // If these threads are different, it returns true. 
     if (this.lblAccessStatus.InvokeRequired) 
     { 
      SetTextCallback d = new SetTextCallback(SetText); 
      this.Invoke(d, new object[] { text }); 
     } 
     else 
     { 
      this.lblAccessStatus.Text = text; 
      this.lblAccessStatus.Refresh(); 
     } 
    } 

Моей формы (так называемой SFDetachifier.cs) имеет кнопку выполнить, который принимает даты два календарных управления, то звонки:

lblAccessStatus.Visible = true; 
picProgress.Visible = true; 

string fromDate = dtManualFromDate.Value.ToString("yyyy-MM-dd") + fromTime; 
string toDate = dtManualToDate.Value.ToString("yyyy-MM-dd") + toTime; 
string[] arg = new string[] { "S1", fromDate, toDate }; 
SFCtrl._SessionLog.Append("Manual detach requested on " + SFOrgName + "\n"); 
SFCtrl._SessionLog.Append("Date range requested: " + fromDate + " to " + toDate + "\n"); 

bgProcessing_Production.RunWorkerAsync(arg); 

bgProcessing_Production имеет код ниже для фона рабочего, который включает в себя вызов setText

private void bgProcessing_Production_DoWork(object sender, DoWorkEventArgs e) 
    { 
     String[] args = (String[])e.Argument; 
     e.Result = args[0]; 

     // clear the datagrid view 
     gvTaskCases.DataSource = null; 
     //gvTaskCases.Rows.Clear(); 

     //if (gvTaskCases.Rows.Count != 0) 
     // { 
     // gvTaskCases.Rows.Clear(); // .Update(); 
     // } 

     SetText("login to SalesForce (on " + SFOrgName + ") ...please wait"); 

Теперь, когда я запускаю свое приложение, я устанавливаю несколько дат, затем выполняю приведенный выше код, нажав кнопку «Выполнение», он выполняет свою работу (вызывая веб-службы SalesForce XML) и помещает результаты в сетку.

, что все работает нормально, проблема occurrs, когда я пытаюсь запустить процедуру еще раз (например, с разными датами)

Тогда я получаю ошибку «операции Cross-нить не действует: Control„“доступа из нить, кроме потока, на котором она была создана. '

Я не понимаю, у меня есть настройка делегата?

Что я делаю неправильно - я предполагаю, что когда рабочий стол снова запускается, он запускается на новом потоке, тем самым будучи небезопасным.

Как исправить эту ошибку, пожалуйста?

+2

Просто проверка - может ли 'gvTaskCases.DataSource = null;' возникнуть исключение? –

+2

Интересно, что имя элемента управления в сообщении об ошибке равно '' –

+0

, но оба хороших пункта выше, однако, 'gvTaskCases.DataSource = null;' не проблема (хотя я получил некоторые проблемы с потоками безопасности с этим элементом управления в прокомментированном коде выше вызов 'setText' –

ответ

1

вы можете сократить вещи немного с помощью анонимных делегатов, как это:

private void removeGridDS() 
    { 
     this.gvTaskCases.Invoke((MethodInvoker)delegate 
     { 
      if (this.gvTaskCases.DataSource != null) 
      { 
       this.gvTaskCases.DataSource = null; 
      } 
     }); 
    } 

    private void clear_gvTaskCases() 
    { 
     this.gvTaskCases.Invoke((MethodInvoker)delegate 
     { 
      if (this.gvTaskCases.Rows.Count != 0) 
      { 
       this.gvTaskCases.Rows.Clear(); 
      } 
     }); 
    } 

Теперь вам не нужно жестко зашитых делегатов. Кроме того, вы не использовали переданные в bools.

0

вот что я сделал, чтобы обойти эту проблему, как один из предложенных выше комментариев, похоже, что это вызовы элементу управления gvTaskCases, который бросает ошибку, поэтому я создал метод безопасного потока призывает этот контроль тоже:

delegate void SetTextCallback(string text); 
delegate void clear_gvTaskCasesCallback(bool clearIt); 
delegate void remove_gvTaskCasesDSCallback(bool removeDS); 

private void removeGridDS(bool removeDS) 
    { 
     // InvokeRequired required compares the thread ID of the 
     // calling thread to the thread ID of the creating thread. 
     // If these threads are different, it returns true. 
     if (this.gvTaskCases.InvokeRequired) 
     { 
     remove_gvTaskCasesDSCallback d = new remove_gvTaskCasesDSCallback(removeGridDS); 
     this.Invoke(d, new object[] { removeDS }); 
     } 
     else 
     { 
      if (this.gvTaskCases.DataSource !=null) 
      { 
      this.gvTaskCases.DataSource=null; 
      } 
     } 
    } 

    private void clear_gvTaskCases(bool clearIt) 
    { 
    // InvokeRequired required compares the thread ID of the 
    // calling thread to the thread ID of the creating thread. 
    // If these threads are different, it returns true. 
    if (this.gvTaskCases.InvokeRequired) 
    { 
     clear_gvTaskCasesCallback d = new clear_gvTaskCasesCallback(clear_gvTaskCases); 
     this.Invoke(d, new object[] { clearIt }); 
     } 
     else 
     { 
     if (this.gvTaskCases.Rows.Count != 0) 
     { 
     this.gvTaskCases.Rows.Clear(); 
     } 
    } 
} 
+1

Ну, не делайте этого. Просто сбросьте привязку данных, прежде чем вы вызовете RunWorkerAsync. Не имеет значения, просто намного меньше кода. То же самое относится к установке текста метки, нет очевидной причины сделать это от работника, поэтому может также сделать это миллисекундой раньше. –

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