Управление потоком. Вызвать

3 ответа

Есть два золотых правила потоковой передачи в Windows Forms:

  • Не трогайте любые свойства или методы элемента управления (кроме тех, которые явно указаны как допустимые) из любого потока, кроме того, который создал «дескриптор» элемента управления (обычно есть только один поток пользовательского интерфейса)
  • Не блокируйте поток пользовательского интерфейса для каких-либо значительных время, иначе вы сделаете приложение не отвечающим

Чтобы взаимодействовать с пользовательским интерфейсом из другого потока, вам необходимо «маршалировать» вызов потока пользовательского интерфейса, используя делегата и вызывая Control. Вызов / BeginInvoke . Вы можете проверить, нужно ли вам вызывать Invoke , используя свойство InvokeRequired , но в наши дни я лично склонен просто делать это в любом случае - особых штрафов нет для вызова, когда вам это не нужно.

Лямбда-выражения в C # 3 (или анонимные методы в C # 2) также делают это намного более приятным.

Например, вы можете использовать:

cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear()));

All the скобки немного мешают, так что вы можете добавить такой метод расширения, если вы используете C # 3:

public static void Invoke(this Control control, MethodInvoker action)
{
    control.Invoke(action);
}

Тогда вы можете сделать:

cbFly.Invoke(() => cbFly.Items.Clear());

, что намного проще. Обычно вы можете обойтись без использования MethodInvoker , захватив любые переменные, к которым вам нужно получить доступ в делегате.

См. мое руководство по потокам или Джо Альбахари для подробнее.

В качестве второстепенного вопроса, Я вижу, что вы используете Thread.Abort - фактически в своем собственном потоке, несмотря на то, что после него есть другие вызовы. Почему? Прерывание любого потока , отличного от вашего , является вызовом типа «только для чрезвычайных ситуаций» (который обычно должен сопровождаться выгрузкой приложения в любом случае), и я не вижу причин для прерывания текущего потока, когда еще есть работа, которую предстоит проделать потом ...

50
ответ дан 3 December 2019 в 13:16
поделиться

Я всегда находил эту статью полезной в этом конкретном вопросе.

В вашем примере вы пытаетесь изменить различные элементы управления из потока, который этого не сделал. создать элемент управления. Чтобы обойти эту проблему в вашем примере, сделайте это вместо этого (при условии, что метод ShowAllFly () является методом в вашей форме):

public void ShowAllFly()
{
    Invoke((MethodsInvoker) delegate {
        cbFly.Items.Clear();
        cbFly.Items.Add("Uçuş Seçiniz...");
        dsFlyTableAdapters.tblFlyTableAdapter _t =
            new KTHY.dsFlyTableAdapters.tblFlyTableAdapter();
        dsFly _mds = new dsFly();
        _mds.EnforceConstraints = false;
        dsFly.tblFlyDataTable _m = _mds.tblFly;
        _t.Fill(_m);
        foreach (DataRow _row in _m.Rows)
        {
            cbFly.Items.Add(_row["FlyID"].ToString() + "-" +
                            _row["FlyName"].ToString() + "-" +
                            _row["FlyDirection"].ToString() + "-" +
                            _row["FlyDateTime"].ToString());
        }
        //_Thread.Abort(); // WHY ARE YOU TRYING TO DO THIS?
        timer1.Enabled = false;
        WaitPanel.Visible = false;
    } );
}

Чтобы подчеркнуть мысль, высказанную @Jon Skeet, я закомментировал вызов прерывания нить. Нить закончится сама собой. Нет причин прерывать его таким образом.

4
ответ дан 3 December 2019 в 13:16
поделиться

Взаимодействие с элементами управления в другом (ui) потоке необходимо вызывать следующим образом:

 public delegate void ProcessResultDelegate (строковый результат);
void ProcessResult (строковый результат)
{
 если (textBox1.InvokeRequired)
 {
 var d = новый ProcessResultDelegate (ProcessResult);
 d.Invoke (результат);
 }
 еще
 {
 textBox1.Text = результат;
 }
}
6
ответ дан 3 December 2019 в 13:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: