Попытка изменить ячейки значения в фоновом рабочем потоке - PullRequest
0 голосов
/ 23 июля 2011

Я пытаюсь обновить ячейку Ultragridrow в фоновом режиме, но это вызывает исключение InvalidOperation, когда оно вызывается более 1 раза.

Здесь у вас есть метод, который запускает RunWorkerAsync.

    private void RefreshGridCacheStart()
    {
        try
        {
            if (this.uGridCache.Rows.Count == 0)
            {
                return;
            }

            if(!workerThread.IsBusy)
            {
                workerThread.DoWork += LookUpHostnames;
                workerThread.ProgressChanged += UpdateCacheHostCell;
                workerThread.RunWorkerCompleted += WorkerCompleted;
                workerThread.WorkerReportsProgress = true;
                workerThread.RunWorkerAsync();
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
        }
    }

Это метод DoWork:

    private void LookUpHostnames(object sender, DoWorkEventArgs e)
    {
        var rowValues = new object[2];

        try
        {
            foreach (UltraGridRow row in uGridCache.Rows)//here is were I get an invalid operation exception
            {
                string cellValue = row.Cells["Host"].Text;
                if (Globals.cNet.isValidIP(cellValue))
                {
                    rowValues[0] = row;
                    rowValues[1] = cellValue;

                    workerThread.ReportProgress(0, rowValues);

                    string resolvedHostname = Globals.cIPLookup.LookupHostFromIP(cellValue);
                    rowValues[1] = resolvedHostname;

                    workerThread.ReportProgress(0, rowValues);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
        }

    }

И это метод отчета о ходе выполнения:

    private void UpdateCacheHostCell(object sender, ProgressChangedEventArgs e)
    {
        var rowValues = e.UserState as object[];
        var row = (UltraGridRow) rowValues[0];
        var sMesage = (string) rowValues[1];

        row.Cells["Host"].Value = sMesage;
    }

Ответы [ 3 ]

0 голосов
/ 04 августа 2011

Похоже, что-то должно изменить базовую коллекцию строк, следовательно, сделать недопустимым ваше перечислимое значение.

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

foreach (UltraGridRow row in uGridCache.Rows.ToList())
{
    ....
    workerThread.ReportProgress(0, rowValues);
}

Вы должны знать, что если что-то еще изменится,строк в сетке, ваш ReportProgress может сообщать о прогрессе чего-то, чего больше нет в сетке, вы можете проверить в своем обработчике ReportProgress, действительны ли отчеты о прогрессе для этого элемента, прежде чем делать то, что вы делаете.

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

В документации MSDN по DoWork говорится следующее: «Вы должны быть осторожны, чтобы не манипулировать какими-либо объектами пользовательского интерфейса в обработчике событий DoWork. Вместо этого связывайтесь с пользовательским интерфейсом через события BackgroundWorker.».

Вы можете просмотреть полную информацию о методе DoWork здесь: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx

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

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

Обратите внимание, что на элементах управления Windows Form есть только несколько элементов, которые на самом деле являются потокобезопасными, и они описаны в разделе «Безопасность потоков для управления в MSDN»: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx

Безопасная, простая многопоточность в Windows Forms - это хороший ресурс для создания потоков в формах Windows, даже если он старше:

Как сделать потокобезопасные вызовы элементов управления Windows Forms также является хорошим ресурсом http://msdn.microsoft.com/en-us/library/ms171728.aspx

0 голосов
/ 23 июля 2011

Вы можете найти свой ответ здесь Другой вопрос, но в конечном итоге та же проблема.Вы изменяете данные в цикле foreach, который делает недействительным перечислитель.
Существует два возможных решения, которые я вижу, прочитав ваш код

  • Сохраните все изменения, которые необходимо внести в списокизменений и сообщать о прогрессе только один раз после цикла foreach.Это может быть не очень хорошим решением, поскольку вы работаете в фоновом режиме.Если запущен другой код, который также может изменить данные в сетке, вы снова получите ту же ошибку.
  • Поскольку вы не добавляете строки, вы можете легко изменить foreach на цикл for.Это также может привести к проблеме, если код в главном потоке может добавить или, что еще хуже, удалить строки
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...