2012-05-13 6 views
2

Я хочу, чтобы получить свойство элемента управления из BackgroundWorker в моей форме:Получить свойство элемента управления из другого потока

foreach (ListViewItem i in ListView.CheckedItems) { //error: Cross-thread operation not valid: Control 'ListView' accessed from a thread other than the thread it was created on. 
    //do something with i 
} 

Может кто-нибудь предложить самый простой и самый простой способ сделать это?

+0

Возможный дубликат: http://stackoverflow.com/questions/6092519/winforms-thread-safe-control-access – zmbq

+0

Если вы можете использовать 'BackgroundWorker' каждого элемента управления в вашей форме уже является читаемым ... – Marco

+0

Покажите нам код, который вы используете, пожалуйста ... – Marco

ответ

2

Позвольте мне сделать еще один удар в этом ...

1.) Перетащите ListView на Форме

2.) Перетащите BackgroundWorker на Форме

3.) Создайте метод сделать итерацию по коллекции ListViewItem

private void LoopThroughListItems() 
{ 
    foreach (ListViewItem i in listView1.CheckedItems) 
     DoSomething(); 

} 

4.) Добавить код для вызова LoopThroughListItems() внутри

BackgroundWorker в DoWork Event
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    LoopThroughListItems(); 
} 

5.) В вашей загрузке формы - выполнить код на главном потоке (он работает), то на backgroundWorkder нити (она не)

private void Form1_Load(object sender, EventArgs e) 
{ 
    // Try it on the UI Thread - It works 
    LoopThroughListItems(); 

    // Try it on a Background Thread - It fails 
    backgroundWorker1.RunWorkerAsync(); 

} 

6.) Изменить код, чтобы использовать IsInvokeRequired/Invoke

private void LoopThroughListItems() 
{ 

    // InvokeRequired == True when executed by non-UI thread 
    if (listView1.InvokeRequired) 
    { 
     // This will re-call LoopThroughListItems - on the UI Thread 
     listView1.Invoke(new Action(LoopThroughListItems)); 
     return; 
    } 

    foreach (ListViewItem i in listView1.CheckedItems) 
     DoSomething(); 
} 

7.) Запустите приложение еще раз - теперь он работает с потоком пользовательского интерфейса и потоком, отличным от UI.

Это решение проблемы. Проверка IsInvokeRequired/Invoking - это общий шаблон, который вы привыкнете к большому количеству (именно поэтому он включен во все элементы управления). Если вы делаете все это за место, вы можете сделать что-то умное и обернуть все это - как описано здесь: Automating the InvokeRequired code pattern

1

Попробуйте что-то вроде этого:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void OnClick(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void OnDoWork(object sender, DoWorkEventArgs e) 
     { 
      foreach (ListViewItem i in GetItems(listView1)) 
      { 
       DoSomething(i); 
      } 
     } 

     private IEnumerable<ListViewItem> GetItems(ListView listView) 
     { 
      if (InvokeRequired) 
      { 
       var func = new Func<ListView, IEnumerable<ListViewItem>>(GetItems); 
       return (IEnumerable<ListViewItem>)Invoke(func, new[] { listView }); 
      } 
      // Create a defensive copy to avoid iterating outsite UI thread 
      return listView.CheckedItems.OfType<ListViewItem>().ToList(); 
     } 

     private void DoSomething(ListViewItem item) 
     { 
      if (InvokeRequired) 
      { 
       var action = new Action<ListViewItem>(DoSomething); 
       Invoke(action, new[] { item }); 
       return; 
      } 
      // Do whatever you want with i 
      item.Checked = false; 
     } 
    } 
} 

Однако, ваш вопрос был действительно вообще. Возможно, было бы проще или лучше, если бы вы делились более подробными сведениями.

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