Заполнение списка из другого потока - PullRequest
2 голосов
/ 08 февраля 2012

Я пытаюсь заполнить представление списка из другого класса, но получаю эту ошибку: «Операция с несколькими потоками недопустима: доступ к элементу управления listView1 осуществляется из потока, отличного от потока, в котором он был создан».

В моем классе я объявляю свой просмотр списка следующим образом:

class CheckBlankPages
{

    public String[] pdfFiles
    { get; set; }

    ListView _ListVireRef;
    public int NrCRT = 1;


    public CheckBlankPages(String[] pdfFiles = null, ListView listView = null)
    {
        this.pdfFiles = pdfFiles;
        _ListVireRef = listView;

    }
    public void StartCheckingPDF()
    {
        foreach (string pdf in pdfFiles)
        {
            String[] itm = { (NrCRT++).ToString(), pdf };
            ListViewItem item = new ListViewItem(itm);
            _ListVireRef.Items.Add(item);
        }
    }
}

и в своей MainForm я использую этот код:

DialogResult rezultat = openFileDialog1.ShowDialog();
        if (rezultat == DialogResult.OK)
        {

            CheckBlankPages ck = new CheckBlankPages(openFileDialog1.FileNames, listView1);
            Thread CheckPDFs = new Thread(new ThreadStart(ck.StartCheckingPDF));
            CheckPDFs.Start();
        }

Что не так?

Ответы [ 5 ]

6 голосов
/ 08 февраля 2012

Обычно я делаю это так:

using System;
using System.Windows.Forms;

namespace TestWinFormsThreding
{
    class TestFormControlHelper
    {
        delegate void UniversalVoidDelegate();

        /// <summary>
        /// Call form control action from different thread
        /// </summary>
        public static void ControlInvoke(Control control, Action function)
        {
            if (control.IsDisposed || control.Disposing)
                return;

            if (control.InvokeRequired)
            {
                control.Invoke(new UniversalVoidDelegate(() => ControlInvoke(control, function)));
                return;
            }
            function();
        }
    }

    public partial class TestMainForm : Form
    {
    // ...
    // This will be called from thread not the same as MainForm thread
    private void TestFunction()
    {
        TestFormCotrolHelper.ControlInvoke(listView1, () => listView1.Items.Add("Test"));
    }   
    //...
    }
}
2 голосов
/ 08 февраля 2012

Простой поиск здесь в SO привел бы ко многим результатам, которые сообщали бы вам, что нельзя изменять элемент управления GUI из потока, отличного от потока, который создал элемент управления (доступ через графический интерфейс между потоками).

Для этого все, что связано с обновлением ListView, должно быть выполнено с использованием this.Invoke или this.Dispatcher.Invoke (в WPF).

РЕДАКТИРОВАТЬ
Например эта тема здесь .

Пример кода:

private delegate void MyDelegate(string s);

public void UpdateControl(Control targetControl, string text)
{
    if (targetControl.InvokeRequired)
    {
        // THIS IS STILL THE IN THE CONTEXT OF THE THREAD
        MyDelegate call = new MyDelegate(UpdateControl);
        targetControl.Invoke(call, new object[] { text });
    }
    else
    {
        // do control stuff
        // THIS IS IN THE CONTEXT OF THE UI THREAD
    }
}
0 голосов
/ 04 апреля 2017

Это разумная вещь, потому что часто в приложении вы хотите, чтобы обновления ListView и т. Д. Происходили без задержек вашего кода.

Я установил системы сообщений между пользовательскими элементами управления, содержащими элемент управления IЯ хочу обновиться на заднем плане, и это может стать довольно грязным, потому что вам в конечном итоге придется сообщать / событие намного больше, чем просто заполнение / обновления, грязный код - это глючный код, поэтому я попробовал другие способы.

Есть хороший, аккуратный способ, медленная часть заполнения / обновления ListView обычно заключается в создании ListViewItems, и вы можете полностью подготовить их в своем собственном потоке.

Так что теперь, для такого рода приложений (с заполнением или обновлением ListView, когда мне не нужно ждать, пока он будет готов, прежде чем мой код сможет продолжить), мой отдельный поток создает / подготавливает ListViewItems, а затем добавляет подготовленные элементы в ListView, когда потокЭто делается очень быстро, поэтому окончательное обновление ListView может быть выполнено для пользовательского события, едва заметного для пользователя.Добавьте к этому «Добавляйте только тех, кого видите», и это действительно мгновенно.С парой дополнительных строк, поэтому при запуске прокрутки вы можете добавить еще пару.(Возможно, вы заметили, что браузер изображений youtube / facebook / windows all делает это так).Поскольку в нашем случае мы уже подготовили ListViewItems, добавить их в список очень просто.

0 голосов
/ 23 апреля 2016

Уловка, позволяющая избежать дублирования кода или сбоя при вызове функции как из потока пользовательского интерфейса, так и из других потоков:

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


        void AddItems( string[] items )
        {
            if(InvokeRequired)
            {
                Invoke((MethodInvoker) delegate { this.AddItems(items); });
                return;
            }
            ListViewItem[] range = (items.Select<string, ListViewItem>(item => new ListViewItem(item))).ToArray();
            listView1.Items.AddRange(range);
        }
    }
}

При первом входе функции в другой поток вызывается invoke, и функция просто вызывает себя снова, на этот раз в контексте нужного потока. Фактическая работа записывается только один раз после блока if ().

0 голосов
/ 08 февраля 2012

Вы пытаетесь обновить поток графического интерфейса из фонового потока.Вам нужно будет использовать Invoke на элементе управления, который вы хотите обновить.Вы можете проверить свойство InvokeRequired этого элемента управления, чтобы увидеть, нужно ли вам использовать Invoke для обновления элемента управления

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...