Member 13801408 Ответов: 1

Недопустимая операция кросс-потока: управление 'form1' осуществляется из потока, отличного от потока, в котором оно было создано." + C# + winform


private void button2_Click(object sender, EventArgs e)
       {
           searchpattern = txtpatterns.Lines;
           searchpattern = searchpattern.Take(searchpattern.Count() - 1).ToArray();
           sourcepath = txtsourcepath.Text;
           destinationpath = txtUnzippath.Text;
           BuildingNames = txtbuildings.Lines;
           BuildingNames = BuildingNames.Take(BuildingNames.Count() - 1).ToArray();
           #region Validating Required Fields
           if (txtsourcepath.TextLength == 0)
           {
               MessageBox.Show("Please Enter the Search Directory path");
           }
           else if (txtpatterns.TextLength == 0)
           {
               MessageBox.Show("Please Enter the Start Date and End date to start the process");
           }
           else if (txtUnzippath.TextLength == 0)
           {
               MessageBox.Show("Please Enter the path to unzip the File");
           }
           else if (txtbuildings.TextLength == 0)
           {
               MessageBox.Show("Please Select the buildings from the list");
           }
           #endregion
           else
           {
               //SQL_Bulk_Copy oHelper = new SQL_Bulk_Copy();
               //string logFilePath = @"C:\Users\jqy9jzy\Desktop\Testing\SVRP0008C8B9\SVRP0008C8B9Unzip\DataFeed_20180419_6276.log";
               //oHelper.BulkInsertIntoDatabase(logFilePath);
               Task task = new Task(Callmethod);
               task.Start();
               task.Wait();
           }
       }

       public async void Callmethod()
       {
           Hide();

           foreach (var pattern in searchpattern)
           {
               var txtFiles = Directory.EnumerateFiles(sourcepath, pattern, SearchOption.AllDirectories);
               foreach (string filepath in txtFiles)
               {
                   zipfilepath.Add(filepath);
               }
           }
           Task<int> task = ReadFile.FILE_C(zipfilepath);
           int count = await task;
           if (count == zipfilepath.Count)
           {
               Directory.Delete(Unzip.destinationpath, true);
               bool directoryExists = Directory.Exists(Unzip.destinationpath);
               Close();
           }
       }



Код ReadFile :
public class ReadFile
   {
       protected internal static async Task<int> FILE_C(List<string> zipfilepath)
       {
           int count = 0;

           try
           {
               if (!Directory.Exists(Unzip.destinationpath))
               {
                   Directory.CreateDirectory(Unzip.destinationpath);
               }

               foreach (string filepath in zipfilepath)
               {
                   await Task.Run(()=> Unzip.data(filepath));
                   count += 1;
               }
           }
           catch (Exception ex)
           {
               throw ex;
           }
           return count;
       }
   }


Что я уже пробовал:

У меня есть список Zipfilepath, я создаю каталог, распаковываю его и загружаю в sql.

Это фактический процесс моего заявления.

Я хочу сделать это асинхронно, потому что у меня есть около 1500 файлов в этом списке.

Он должен распаковать, прочитать и загрузить файл в sql async,который имеет ожидание до тех пор, пока он не завершит цикл, после завершения цикла приложение должно автоматически закрыться.

Когда я пытаюсь работать с приведенным выше кодом, я получаю следующую ошибку.
Ошибка: "операция кросс-потока недопустима: элемент управления 'Form1' доступен из потока, отличного от потока, в котором он был создан." + c# + winform"


Заранее благодарю, любая помощь будет оценена по достоинству.

Gerry Schmitz

Я не вижу никакого смысла запускать эту асинхронность.

Это не похоже на то, что у вас есть 1500 "каналов".

Отдайте "все дело" фоновому работнику и займитесь другими делами.

1 Ответов

Рейтинг:
1

Richard Deeming

Сделай это async весь путь вниз:

private async void button2_Click(object sender, EventArgs e)
{
    ...
    else
    {
        await Callmethod();
    }
}

private async Task Callmethod()
{
    Hide();
    
    List<string> filesToZip = searchpattern
        .AsParallel()
        .SelectMany(pattern => Directory.EnumerateFiles(sourcepath, pattern, SearchOption.AllDirectories))
        .ToList()
    ;
    
    int count = await ReadFile.FILE_C(filesToZip);
    if (count == filesToZip.Count)
    {
        Directory.Delete(Unzip.destinationpath, true);
        bool directoryExists = Directory.Exists(Unzip.destinationpath);
        Close();
    }
}

public class ReadFile
{
    protected internal static async Task<int> FILE_C(IEnumerable<string> zipfilepath)
    {
        int count = 0;
        
        if (!Directory.Exists(Unzip.destinationpath))
        {
            Directory.CreateDirectory(Unzip.destinationpath);
        }

        foreach (string filepath in zipfilepath)
        {
            await Task.Run(()=> Unzip.data(filepath)).ConfigureAwait(false);
            count += 1;
        }
        
        return count;
    }
}

NB: Если ты действительно нужно повторно выбросить исключение, использовать throw;, нет throw ex; - последний уничтожает трассировку стека.

Однако в данном случае, поскольку все, что вы делаете,-это повторное выбрасывание исключения, нет никакого смысла ловить его в первую очередь.


Member 13801408

Привет Ричард,
Спасибо за помощь.

Когда я попытался запустить это, я получил правильный вывод, чего и ожидал. Но цикл foreach повторяется синхронно. Но я хочу, чтобы он работал асинхронно. Так что я могу улучшить производительность.

Спасибо заранее.

Это код распаковки:

защищенные внутренние статические пустые данные(string filepath)
{
пробовать
{
//Извлечь подкаталог из пути к файлу
Create_Sub_DirectoryUnzip = путь к файлу .Подстрока(MainForm.sourcepath.Длина+1);
Create_Sub_DirectoryUnzip = Path.GetDirectoryName(Create_Sub_DirectoryUnzip);
//Имя файла журнала без расширения
Log_Filename = Path.GetFileNameWithoutExtension(путь к файлу);
Log_Filename = Log_Filename.Удалить(Log_Filename.Длина - 4 м);
//Extract path для распаковки файла
Extract_Path = destinationpath + "\\" + Create_Sub_DirectoryUnzip + "распаковать" ;
Unzipfilepath = Extract_Path + "\\" + Log_Filename + ".log";

если (!файл.Существует(Unzipfilepath))
{
если (!Directory.Exists(Extract_Path))
{
Каталог.CreateDirectory(Extract_Path);
}
Zip-файл.ExtractToDirectory(путь к файлу, Extract_Path);
}

if (new FileInfo(Unzipfilepath).Длина > 0)
{
var contentvalid = File.ReadLines(Unzipfilepath).Skip(0).Take(1).First();
var content = File.ReadLines(Unzipfilepath).Skip(1).Take(1).First();

строка valid = contentvalid.Расщеплять('|').Пропустить(0).Взять(1).Сначала();
if (valid == "отметка времени")
{
строка RecordType = content.Расщеплять('|').Пропустить(7).Взять(1).Сначала();
if (RecordType == "10")
{
SQL_Bulk_Copy oHelper = новый SQL_Bulk_Copy();
logFilePath = Unzipfilepath;
охелпер.BulkInsertIntoDatabase(logFilePath);
}
еще
{
Файл.Удалить(Unzipfilepath);
}
}
еще
{
Файл.Удалить(Unzipfilepath);
}
}
еще
{
Файл.Удалить(Unzipfilepath);
}
}
поймать (исключение бывший)
{
бросок экс;
}
}
#endregion

Richard Deeming

Который foreach петля?

Я обновил ответ так, чтобы поиск в каталоге происходил параллельно.

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