Если вызываю DataAdapter.Fill(datatable) в отдельном потоке, то в связанной через BindingSource сетке ничего не отображается.
Однако обнаружил, что если просто щёлкнуть на к-л заголовке столбца в сетке, данные появляются. Но как это сделать програмно? Пытался в конце вызывать Refresh, update, ResumeBinding, ResetBinding, а так же заключать вызов в beginInit, suspendBinding, suspendLayout — ничего не помогает, сетка полюбому пустая.
А всё это мне нужно только для того, чтоб показать Progress bar при ыполнении длительного запроса. Нужно чтоб Progress bar просто крутился не отражая реальный % выполнения запроса. Progress bar приходится выполнять в основном потоке(по таймеру через Invoke), иначе появляется ошибка InvalidOperationException.
Если DataAdapter.Fill(datatable) выполняю в основном потоке, то он его полностью занимает и пока не выполнится, прогресс не идёт.
В общем что ни пытюсь сделать — натыкаюсь на непреодолимый тупик.
Неужели такую простую вещь как Progress bar невозможно сделать?
Re: DataAdapter.Fill(datatable) в отдельном потоке
T>Если DataAdapter.Fill(datatable) выполняю в основном потоке, то он его полностью занимает и пока не выполнится, прогресс не идёт.
Дело видимо, в том, что если вы делаете Fill в параллельном потоке, то и события для обновления прибинденных контролов расходятся синхронно в параллельном потоке. Это вообще плохо.
T>В общем что ни пытюсь сделать — натыкаюсь на непреодолимый тупик. T>Неужели такую простую вещь как Progress bar невозможно сделать?
Попробуйте делать в параллельном потоке Fill в отсоединенный от контролов DataSet, а потом в основном потоке подключать его к гриду или куда там вы его подключаете.
Re[2]: DataAdapter.Fill(datatable) в отдельном потоке
iT>Попробуйте делать в параллельном потоке Fill в отсоединенный от контролов DataSet, а потом в основном потоке подключать его к гриду или куда там вы его подключаете.
В BindingSource перед этим зануляю DataSource, DataMember; выполняю Fill в другом потоке, возвращаю DataSource, DataMember в исходное значение.
Не помогает — та же самая ситуация.
Может этими компонентами можно работать лишь в том потоке, в котором они созданы?
Если это так, то progress bar сделать поистине невозможно.
Re[3]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, tnikolai, Вы писали:
iT>>Попробуйте делать в параллельном потоке Fill в отсоединенный от контролов DataSet, а потом в основном потоке подключать его к гриду или куда там вы его подключаете.
T>В BindingSource перед этим зануляю DataSource, DataMember; выполняю Fill в другом потоке, возвращаю DataSource, DataMember в исходное значение. T>Не помогает — та же самая ситуация. T>Может этими компонентами можно работать лишь в том потоке, в котором они созданы? T>Если это так, то progress bar сделать поистине невозможно.
Попробуйте основной поток приложения сделать MTA, форму открывать в STA (иначе половина COM объектов не работает)
Почему? STA создается один на приложение (как скрытое окно) и все потоки с этим атрибутом синхронизуются через общую оконную функцию: нормального паралелизма нет.
Re[4]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, shelkovnikov, Вы писали:
S>Попробуйте основной поток приложения сделать MTA, форму открывать в STA (иначе половина COM объектов не работает)
А как это сделать? Вообщето я COM вообще не использую, и подобное делать нежелательно.
S>Почему? STA создается один на приложение (как скрытое окно) и все потоки с этим атрибутом синхронизуются через общую оконную функцию: нормального паралелизма нет.
Если нормального параллелизма нет, то DataAdapter.Fill может и выполнится нормально, но пока он не закончит выполнение, progress bar не сдвинется с места.
Re[3]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, Igor Trofimov, Вы писали:
iT>Возвращаешь — в каком потоке?
Всё в основном. Только Fill в другом потоке выполняетя.
iT>Со всеми контролами надо работать из того потока, где они были созданы, т.е. обычно — из главного потока приложения. iT>С DataDet, DataAdapter, etc — в любых потоках.
Только с DataDet. В справке для DataAdapter сказано, что только public static члены потокобезопасны, а для остальных не гарантируется потокобезопасность.
Re[5]: DataAdapter.Fill(datatable) в отдельном потоке
iT>>Возвращаешь — в каком потоке? T>Всё в основном. Только Fill в другом потоке выполняетя.
Ну тогда должно работать
iT>>Со всеми контролами надо работать из того потока, где они были созданы, т.е. обычно — из главного потока приложения. iT>>С DataDet, DataAdapter, etc — в любых потоках. T>Только с DataDet. В справке для DataAdapter сказано, что только public static члены потокобезопасны, а для остальных не гарантируется потокобезопасность.
А я не говорил про потокобезопасность в том смысле, что параллельно из нескольких потоков можно работать.
Я говорил про то, что можно работать из любого потока. Контролы имеют привязку к потоку. DataSet, DataAdapter — нет.
Re[6]: DataAdapter.Fill(datatable) в отдельном потоке
Еще один момент. В основном потоке, чтобы не замораживался интерфейс, нужно либо вызывать Application.DoEvents, либо не держать выполнение.
Если тебе надо управлять ProgressBar'ом, пока не закончилось выполнение потока с Fill, то либо цикл управления ProgressBar'ом выноси в еще один поток, либо внутрь этого ожидающего цикла вставь Application.DoEvents.
Re[6]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, Igor Trofimov, Вы писали:
iT>>>Возвращаешь — в каком потоке? T>>Всё в основном. Только Fill в другом потоке выполняетя.
iT>Ну тогда должно работать
Работает, но с глюком(сетка пустая пока не щёлкнеш на заголовок столбца), видимо из-за того, что DataAdapter не потокобезопасен.
iT>>>Со всеми контролами надо работать из того потока, где они были созданы, т.е. обычно — из главного потока приложения. iT>>>С DataDet, DataAdapter, etc — в любых потоках. T>>Только с DataDet. В справке для DataAdapter сказано, что только public static члены потокобезопасны, а для остальных не гарантируется потокобезопасность.
iT>А я не говорил про потокобезопасность в том смысле, что параллельно из нескольких потоков можно работать. iT>Я говорил про то, что можно работать из любого потока. Контролы имеют привязку к потоку. DataSet, DataAdapter — нет.
В любом смысле с непотокобезопасным номпонентом в другом потоке работать нельзя, даже и из одного потока!
Re[7]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, Igor Trofimov, Вы писали:
iT>Еще один момент. В основном потоке, чтобы не замораживался интерфейс, нужно либо вызывать Application.DoEvents, либо не держать выполнение.
Если бы DataAdapter.Fill можно было бы прерывать вызовами Application.DoEvents! Проблемм бы не было.
iT>Если тебе надо управлять ProgressBar'ом, пока не закончилось выполнение потока с Fill, то либо цикл управления ProgressBar'ом выноси в еще один поток, либо внутрь этого ожидающего цикла вставь Application.DoEvents.
А вот вынести ProgressBar.PerfomStep в отдельный поток никак не получается. Требует выполнения только в основном потоке, или выдаёт ошибку InvalidOperationException. Если использовать Invoke/BeginInvoke, то пока DataAdapter.Fill занимает поток, ProgressBar с места не двигается.
Re[8]: DataAdapter.Fill(datatable) в отдельном потоке
Здравствуйте, Igor Trofimov, Вы писали:
T>>В любом смысле с непотокобезопасным номпонентом в другом потоке работать нельзя, даже и из одного потока!
iT> А что такое "другой" поток, по-твоему? "Другой" по отношению к чему?
Не тот, в котором компонент создан.
Re[9]: DataAdapter.Fill(datatable) в отдельном потоке
T>>>В любом смысле с непотокобезопасным номпонентом в другом потоке работать нельзя, даже и из одного потока! iT>> А что такое "другой" поток, по-твоему? "Другой" по отношению к чему? T>Не тот, в котором компонент создан.
И где, по-твоему, DataAdapter связывается с потоком, в котором он был создан?
Или скажем, ArrayList? Он по-дефолту тоже "не потокобезопасен".
Re[8]: DataAdapter.Fill(datatable) в отдельном потоке
Короче, я тут накидал тебе простой пример.
Вместо адаптера и базы данных там просто генератор данных для таблицы.
Но не думаю, что с DataAdapter'ом что-то изменится и перестанет работать.
Здравствуйте, Igor Trofimov, Вы писали:
iT>Короче, я тут накидал тебе простой пример. iT>Вместо адаптера и базы данных там просто генератор данных для таблицы. iT>Но не думаю, что с DataAdapter'ом что-то изменится и перестанет работать.
iT>TestThreadFill.zip
Всё получилось!
Спасибо!
У меня была дурацкая ошибка.