0

In my code I am using await Task.Run so the form does not freeze while uploading files to SFTP

I got similar error when I was trying to write to textbox and fixed it with LogUpload function

but now I get this error when I try to access ListView items

System.InvalidOperationException: 'Cross-thread operation not valid: Control 'lvwFiles' accessed from a thread other than the thread it was created on.'

I wonder how can I fix that

here is my code

 await Task.Run(() =>
            {
                using (SftpClient client = new SftpClient(host, port, username, password))
            {
                client.Connect();
                if (client.IsConnected)
                {
                    LogUpload("I'm connected to the client" + "\r\n");
                    foreach (ListViewItem item in lvwFiles.Items)   //<<---- Causing the error
                    {
                        string fileName = item.SubItems[0].Text;
                        string uploadFile = item.SubItems[1].Text;

and the function to LogUpload is

    private void LogUpload(string txt)
    {
        if (txtLog.InvokeRequired)
        {
            txtLog.Invoke(new MethodInvoker(delegate { txtLog.Text = txt + txtLog.Text; }));
        }
    }
asmgx
  • 7,328
  • 15
  • 82
  • 143
  • 1
    Regarding the use of `InvokeIfRequired`, you can check out [this](https://stackoverflow.com/questions/70748796/running-a-background-task-and-waiting-for-its-result-without-blocking-the-ui-thr/70749085#70749085) recent answer by Stephen Cleary. [This](https://stackoverflow.com/questions/70775692/await-a-thread-wont-work-when-dispatch-inside-of-the-thread/70778354#70778354) is also interesting. – Theodor Zoulias Jan 21 '22 at 06:03
  • 1
    If that's Reci.SshNet's SFTPClient, there's an [async extension](https://github.com/JohnTheGr8/Renci.SshNet.Async) -- BTW, you can just pass the values coming from the ListView to the method you `Task.Run()`, instead of using the Control (which you shouldn't anyway) and report progress using an `IProgress` delegate to update the UI. – Jimi Jan 21 '22 at 06:31
  • Misspelled: [Renci SSH.NET](https://github.com/sshnet/SSH.NET/) + [Async Extension](https://www.nuget.org/packages/Renci.SshNet.Async/) – Jimi Jan 21 '22 at 09:05

1 Answers1

1

The error is occurring because you are trying to read the items from the ListView from within the Task, which is running on another thread. Instead of reading the items within the Task.Run call, copy them into an array on the line above Task.Run and reference that array instead.

The CopyTo method provides an easy way to copy the ListViewItems to an array. It would look something like this:

// instantiate new array to hold copy of items
var copyOfItems = new  ListViewItems[lvwFiles.Items.Count];
// copy items
lvwFiles.Items.CopyTo(copyOfItems, 0);

Now just reference copyOfItems within your Task!

John Glenn
  • 1,469
  • 8
  • 13