Выскакивает InvalidOperationException при присоединении DataSet к DataSource [дубликат]

340
15 июня 2017, 03:43

На данный вопрос уже ответили:

  • Работа с контролами из фонового потока 1 ответ

Есть DataGridView, он присоединен к SQLite. При изменении БД вручную через запросы, пытаюсь изменить в режиме реального времени таблицу и отобразить на ней новые значения строк. И в месте, где я присоединяю DataSet к своей DataGridView, возникает данное исключение. Причем, исключение возникает не всегда, а после какого-то уже изменения или еще чего, сам точно это не поняд. Можете пожалуйста подсказать, как можно решить данную проблему?

con.Open();
sql = "select rowid, * from OpenPos";
adapOpenPos = new SQLiteDataAdapter(sql, con);
dsOpenPos = new DataSet();
adapOpenPos.Fill(dsOpenPos);
dataGridView1.DataSource = dsOpenPos.Tables[0];
dataGridView1.Columns[0].Visible = false;
dataGridView1.Columns[15].Visible = false;
con.Close();

Ошибка:

Недопустимая операция в нескольких потоках: попытка доступа к элементу управления, не из того потока, в котором он был создан.

Answer 1

Уберите явную выборку поля rowid:

sql = "select * from OpenPos";

Звёздочка и так извлекает все поля, так что дополнительные указания мало того, что ничего не дают, так ещё и заставляют драйвер SQLite отказывать в выполнении подобного запроса.

Указание дополнительных полей имеет смысл только при использовании подхапросов и объединений. Тогда звёздочка относится к FROM-выражению из основного запроса, а явно именованные поля ищутся в подзапросах:

sql = "SELECT bar.a, * FROM foo LEFT JOIN bar ON foo.key = bar.parent";
Answer 2

Данная проблема решается несколькими способами :

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

Простой и неправильный способ : Отменяем проверку, из какого потока используется контрол

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

Для одного раза может и сработать, но делать так крайне не рекомендуется.

Использование методов Invoke/BeginInvoke

Эти методы выполняют указанные делегаты в том потоке, в котором контрол был создан. Invoke вызывает делегат синхронно, BeginInvoke - асинхронно. Чтобы определить, требуется ли Invoke используйте свойство InvokeRequired. Например, объявляем делегат

delegate void Del(string text);

и вызываем Invoke

textBox1.Invoke(new Del((s) => textBox1.Text = s), "newText");

Вместо объявления новых делегатов можно использовать готовые, Action или Func Пример готового, потоко-безопасного метода

void SetTextSafe(string newText)
{
    if (textBox1.InvokeRequired) 
         textBox1.Invoke(new Action<string>((s) => textBox1.Text = s), newText);
    else 
         textBox1.Text = newText;
}
READ ALSO
Игра Викторина на подобие игры Борьба Умов [требует правки]

Игра Викторина на подобие игры Борьба Умов [требует правки]

Доброго времени суток! Хочу создать игру викторинуНа подобие игры Борьба Умов

262
Шифр Хилла (Расшифровка) C#

Шифр Хилла (Расшифровка) C#

Подскажите, что не так с моим кодом для дешифровки текстаДетерминант и матрицу алгебраических дополнений находит правильно, проверял

594
Обновление коллекции источника данных Datagrid

Обновление коллекции источника данных Datagrid

На форме есть 2 гридаDataContext для формы - отдельный класс(ViewModel)

234
OnPropertyChanged - Calculated property

OnPropertyChanged - Calculated property

Доброго времени сутокТакой вопрос:

238