#c# #.net #multithreading #winforms
#c# #.net #многопоточность #winforms
Вопрос:
Мои коды работают нормально, но когда я создаю поток, я получаю недопустимую операцию с перекрестным потоком при попытке добавить элемент ComboBox
. Я тоже пробовал использовать эти коды backgroundworker
, но та же ошибка
new Thread(GetInfo).Start();
public void GetInfo()
{
while (true)
{
if (SellerControlGroup.Enabled)
{
SqlDataReader Type = new SqlCommand("select type from _Price where Service = 1", sqlCon.con).ExecuteReader();
while (Type.Read())
{
string type = Convert.ToString(Type["type"]);
ProgramType.Items.Add(type);
}
Type.Close();
}
}
}
Комментарии:
1. Вы не можете изменять элементы в потоке пользовательского интерфейса из фонового потока, однако вы можете использовать делегат для обратного вызова изменений в потоке пользовательского интерфейса
2. @Icepickle Как я могу использовать делегат для добавления элементов в
ComboBox
3. Ниже приведен пример делегирования
Ответ №1:
Вы можете обновить элемент управления из потока, который он был создан, и не можете обновить его из другого потока.
Ниже приведен рабочий код для обновления элемента управления из того же потока, который был создан из другого потока.
new Thread(GetInfo).Start();
public void GetInfo()
{
while (true)
{
if (SellerControlGroup.Enabled)
{
SqlDataReader Type = new SqlCommand("select type from _Price where Service = 1", sqlCon.con).ExecuteReader();
while (Type.Read())
{
string type = Convert.ToString(Type["type"]);
// Update control with the same thread its been created
this.Invoke((MethodInvoker)delegate()
{
ProgramType.Items.Add(type);
});
}
Type.Close();
}
}
}
Комментарии:
1. SellerControlGroup, похоже, также является элементом управления пользовательского интерфейса.
2. Вы можете прочитать свойство control из другого потока. Только для записи вам нужен делегат.
3. Нет, это небезопасно. Вы не должны «обращаться» к элементу управления пользовательского интерфейса из другого потока.
4. @MehrzadChehraz Спасибо, обычно read работает нормально и не выдает никаких ошибок. Но, если требуется, вышеуказанное
if
может быть заменено делегатом как,this.Invoke((MethodInvoker)delegate() { if (SellerControlGroup.Enabled){ ProgramType.Items.Add(type); } });
5. @Aruna — Чтение в порядке, если вы не пытаетесь одновременно писать в любом потоке. Также это решение было бы лучше, если бы оно выполняло чтение за один раз, а затем выполняло один вызов для обновления всех значений.
Ответ №2:
Вы могли бы использовать делегат для вызова изменений в потоке пользовательского интерфейса, например
delegate void AddItemDelegate(ComboBox cmb, string value);
void AddItem(ComboBox cmb, string value) {
if (cmb.InvokeRequired) {
cbm.Invoke( new AddItemDelegate( AddItem ), cmb, value );
} else {
cmb.Items.add(value);
}
}
а затем просто используйте
AddItem( ProgramType, type );