Есть ли недопустимая операция с перекрестным потоком?

#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 );