2014-12-17 3 views
0

Мне показалось, что я понял, что для того, чтобы отдельный поток вносил изменения в графический интерфейс в приложении winforms, необходимо вызвать метод. Тем не менее, я написал метод для асинхронного заполнения combobox, и это показывает мне, что в истории больше.При каких условиях необходимо вызывать метод?

Вот соответствующий код, с информацией компании опущена:

private List<string> ids = new List<string>(); 
private BindingSource bindingSource = new BindingSource(); 
//... 
cboIds.DataSource = bindingSource; 

private void GetAvailableIds() 
{ 
    Task idTask = new Task(
     () => 
     { 
      bindingSource.Add("Searching..."); //This always updates the UI 
                //without invoking 

      if (cboIds.InvokeRequired)  
      { 
       Invoke((MethodInvoker)delegate 
       {        //This sometimes updates the UI without 
        cboIds.Enabled = false;  //invoking, but sometimes fails, so I              
       });        //added the check 
      } 
      else 
       cboIds.Enabled = false; 

      List<string> temp = GetUpcomingIds(); 

      Invoke((MethodInvoker)delegate 
      { 
       cboIds.Enabled = true; 
       bindingSource.Clear(); 
       foreach (string str in temp) 
        bindingSource.Add(str); //This never works without invoking. 
      });        //Why, if the same operation above 
     });         //always works without invoking? 
    idTask.Start(); 
} 

Почему это, что начальное дополнение к BindingSource не нуждается в Invoke, установив combobox.enabled ложь иногда нуждается в Invoke , и окончательные добавления к BindingSource всегда нужно вызвать? Если они все в одной и той же ветке, не должны ли они вести себя одинаково? Неужели я ошибаюсь в своем предположении, что все они в одной теме?

+0

Когда вы получаете доступ к форме управления winform, поток, который не создал элемент управления, который вам нужно вызвать. – dotctor

+1

'Задача' <>' Thread'. –

+0

Так вот проблема, которую я вижу здесь из-за использования задачи, а не Thread? – charlieparker

ответ

0

Насколько когда Invoke() требуется, или когда его асинхронный эквивалент BeginInvoke() требуется: вы должны использовать его, когда вы хотите, чтобы взаимодействовать с любым Control класса объекта в потоке, чем поток, который владеет этого объекта. Control Объекты принадлежат потоку, в котором они были созданы (это право собственности связано с родственным сродством потоков для собственных структур данных, которым обладает управляемый объект Control).

Если, в отличие от приведенного примера кода, вы прикрепляли объект BindingSource к некоторому элементу управления, тогда вам нужно будет использовать Invoke() при выполнении любого члена этого объекта, который изменяет связанные данные, если вы выполняете этот член в нить, отличную от той, которая владеет элементом управления, которому привязан BindingSource. Это связано с тем, что объект BindingSource будет вызывать события, управляемые элементом управления; что взаимодействие должно происходить в потоке, которому принадлежит элемент управления, и единственный способ выполнить это - переместить выполнение обновления BindingSource в собственный поток с помощью Invoke(). метод.

Если объект BindingSource не подключен к элементу управления, а затем подключен позже, вам не нужно Invoke() для любой модификации объекта до, но не после, момента времени, к которому он прикреплен к элементу управления , Если случается, что ваш пример кода не завершен, и вы действительно присоединяете экземпляр bindingSource, который вы создали для элемента управления, но после первого вызова метода Add() это объясняет, почему вам требуется Invoke() позже, но не для первоначальный вызов Add().

Теперь, имея все это в виду & hellip;

Обратите внимание, что в случае связывания DataSource вы не получите то же самое InvalidOperationException, изменяя BindingSource, как если бы вы попытались обновить элемент управления напрямую. Вместо этого связывание задерживает обновление элемента управления до тех пор, пока оно не способно, то есть BindingSource обновляется в потоке, которому принадлежит элемент управления.

Это означает, что в вашем примере кода, в то время как управление не обновляется сразу при вызове первой Add() метод, вы не замечаете это, потому что вы вернуться к владеющим нити сразу же после этого, в которой время управления может быть обновлено. То есть технически вы do необходимо использовать Invoke() для этого первого обновления, но все происходит так быстро, что вы просто не замечаете разницы между тем, как делать это «правильным путем» и делать это «неправильно».

+0

Объект BindingSource привязан к cboIds до вызова. Я обновлю свой пример, чтобы показать это. – charlieparker

+0

А, ладно ... Я уточню свой ответ в нужном порядке. –

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