benny dayag
benny dayag

Reputation: 139

Why i'm getting cross thread exception while updating label in backgroundworker progresschanged event?

I have a backgroundworker dowork where inside I start a new backgroundworker

DirectoryInfo MySubDirectory;
List<FileInfo> l;
object[] CurrentStatus;

private void _FileProcessingWorker_DoWork(object sender, DoWorkEventArgs e)
{
    int countmore = 0;
    try
    {
        DirectoryInfo[] MySubDirectories = (DirectoryInfo[])e.Argument;
        for (int i = 0; i < MySubDirectories.GetLength(0); i++)
        {
            MySubDirectory = MySubDirectories[i];

            l = new List<FileInfo>();
            if (_FileCountingWorker.IsBusy == false)
                _FileCountingWorker.RunWorkerAsync();

            CurrentStatus = new object[6];
            int totalFiles = l.Count;
            CurrentStatus[3] = i.ToString();
            countmore += totalFiles;
            CurrentStatus[4] = countmore;
            _FileProcessingWorker.ReportProgress(0, CurrentStatus);

            string CurrentDirectory = "Current Directory: " + MySubDirectory.Name;

            foreach (FileInfo MyFile in l)
            {
                CurrentStatus = new object[6];
                if (_FileProcessingWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                 }

                 if (MyFile.Extension.ToLower() == ".cs" || MyFile.Extension.ToLower() == ".vb")
                 {
                     string CurrentFile = "Current File: " + MyFile.Name;
                     string CurrentFileWithPath = MyFile.FullName;

                     CurrentStatus[0] = CurrentDirectory;
                     CurrentStatus[1] = CurrentFile;
                     _FileProcessingWorker.ReportProgress(0, CurrentStatus);

                     List<string> Result = SearchInFile(CurrentFileWithPath, "if");

                     if (Result != null && Result.Count > 0)
                     {
                         CurrentStatus[2] = Result;
                         _FileProcessingWorker.ReportProgress(0, CurrentStatus);
                      }
                  }
              }
          }
      }
      catch (Exception err)
      {
          return;
      }
  }

I'm checking the other backgroundworker is not busy if not start it

if (_FileCountingWorker.IsBusy == false)
    _FileCountingWorker.RunWorkerAsync();

In the new backgroundworker dowork event

private void _FileCountingWorker_DoWork(object sender, DoWorkEventArgs e)
{
    CountFiles(MySubDirectory, l);
}

In CountFiles

int countingFiles = 0;
private void CountFiles(DirectoryInfo di, List<FileInfo> l)
{
    try
    {
        l.AddRange(di.EnumerateFiles());
    }
    catch
    {
        string fff = "";
    }

    try
    {
        if (di.FullName != BasePath)
        {
            IEnumerable<DirectoryInfo> subDirs = di.EnumerateDirectories();
            if (subDirs.Count() > 0)
            {
                foreach (DirectoryInfo dir in subDirs)
                {
                    CountFiles(dir, l);
                    countingFiles += 1;
                    if (countingFiles == 8382)
                    {
                        string hhhhh = "";
                    }
                    CurrentStatus[5] = countingFiles;
                    _FileCountingWorker.ReportProgress(0,CurrentStatus);
                }
            }
        }
    }
    catch 
    {
        string yyy = "";
    }
}

Then in the second backgroundworker progresschanged

private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (typeof(object[]) == e.UserState.GetType())
    {
        object[] StatusMsg = (object[])e.UserState;
        if (6 == StatusMsg.GetLength(0))
        {
            if (StatusMsg[5] != null)
            {
                lblCountingFiles.Text = StatusMsg[5].ToString();
            }
        }
    }
}

The exception is on the line:

lblCountingFiles.Text = StatusMsg[5].ToString();

Cross-thread operation not valid: Control 'lblCountingFiles' accessed from a thread other than the thread it was created on

I'm updating the label in the ProgressChanged event. Why am I getting the exception?
And how should I solve it?

Upvotes: 0

Views: 545

Answers (2)

T.Andy
T.Andy

Reputation: 106

You are calling _FileCountingWorker.RunWorkerAsync(); in DoWork from another BackgroundWorker thread. So when _FileCountingWorker reports progress it wont come back to the UI thread because it is not started from UI thread. That's why you are getting cross thread exception.

Try to call _FileCountingWorker.RunWorkerAsync() from UI thread or from _FileProcessingWorker_ProgressChanged event.

Otherwise you can use:

private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread
    {
        Dispatcher.Invoke(new Action<object, ProgressChangedEventArgs>(_FileCountingWorker_ProgressChanged), sender, e);
        return;
    }
    if (typeof(object[]) == e.UserState.GetType())
    {
        object[] StatusMsg = (object[])e.UserState;
        if (6 == StatusMsg.GetLength(0))
        {
            if (StatusMsg[5] != null)
            {
                lblCountingFiles.Text = StatusMsg[5].ToString();
            }
        }
    }
}

Upvotes: 3

paparazzo
paparazzo

Reputation: 45096

I think the problem is on the main thread you have

object[] CurrentStatus;

in the background you could be newing it before reports progress gets to it (or at the same time)

kill the above
just create the object in the do_work

object[] CurrentStatus = new object[6];

Upvotes: 1

Related Questions