Populating a listview from another thread

10,266

Solution 1

Usually I'm doing it like this:

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"));
    }   
    //...
    }
}

Solution 2

A simple search here on SO would have brought up many results that tell you that it is not allowed to change a GUI control from a thread other than the thread which created the control (cross-thread GUI access).

To do so, everything related to updating the ListView must be done using this.Invoke or this.Dispatcher.Invoke (in WPF).

EDIT
For example this thread here.

Sample code:

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
    }
}
Share:
10,266
XandrUu
Author by

XandrUu

Updated on August 04, 2022

Comments

  • XandrUu
    XandrUu over 1 year

    I'm trying to populate a listview from another class, but I'm geting this error: " Cross-thread operation not valid: Control 'listView1' accessed from a thread other than the thread it was created on. "

    In my class I declare my listview like this:

    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);
            }
        }
    }
    

    and in my MainForm I use this code:

    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();
            }
    

    What is wrong?