Вызов (делегат)

Может кто-нибудь объяснить это выражение, написанное на этой ссылке

Invoke(Delegate):

Выполняет заданный делегат в потоке, которому принадлежит дескриптор управления базовым окном.

Может кто-нибудь объяснить, что это значит (особенно смелый), я не могу понять это.

Ответ 1

Ответ на этот вопрос заключается в том, как работают С# Controls

Элементы управления в Windows Forms привязаны к определенному потоку и не безопасный поток. Поэтому, если вы вызываете метод управления из другой поток, вы должны использовать один из методов вызова управления для маршал призыв к соответствующей теме. Это свойство можно использовать для определить, следует ли вам вызывать метод invoke, который может быть полезен, если вы не знаете, какой поток принадлежит элементу управления.

От Control.InvokeRequired

Эффективно, что Invoke делает, гарантирует, что код, который вы вызываете, происходит в потоке, который элемент управления "живет" эффективно предотвращает перекрестные поточные исключения.

С исторической точки зрения, в .Net 1.1, это было фактически разрешено. Это означает, что вы можете попробовать и выполнить код в потоке "GUI" из любого фонового потока, и это будет работать в основном. Иногда это просто заставило ваше приложение выйти из-за того, что вы фактически перепутали поток графического интерфейса, пока он делал что-то еще. Это Cross Threaded Exception - представьте, что вы пытаетесь обновить TextBox, пока графический интерфейс рисует что-то еще.

  • Какое действие имеет приоритет?
  • Возможно ли, чтобы оба произошли сразу?
  • Что происходит со всеми другими командами, которые должен выполнить GUI?

Эффективно, вы перебиваете очередь, которая может иметь много непредвиденных последствий. Invoke - это "вежливый" способ получить то, что вы хотите сделать в этой очереди, и это правило было принудительно введено с .Net 2.0 с помощью брошенного InvalidOperationException.

Чтобы понять, что на самом деле происходит за кулисами, и что подразумевается под "графическим потоком", полезно понять, что такое Message Pump или Message Loop.

На самом деле это уже ответило на вопрос "Что такое Message Pump" и рекомендуется читать для понимания реального механизма, с которым вы связываетесь при взаимодействии с элементами управления.

Другие чтения, которые могут оказаться полезными, включают:

Что происходит с Begin Invoke

Одним из основных правил программирования графического интерфейса Windows является то, что только поток, который создал элемент управления, может получить доступ и/или изменить его содержимое (за исключением нескольких задокументированных исключений). Попробуйте сделать это из любого другого и вы получите непредсказуемое поведение, начиная от тупиковой ситуации, до исключения до половины обновленного пользовательского интерфейса. Правильный путь для обновления управление из другого потока - отправить соответствующее сообщение в очередь сообщений приложений. Когда насос сообщений приближается к выполняя это сообщение, элемент управления будет обновлен, на том же нить, которая его создала (помните, что насос сообщений работает на основном нить).

а для более подробного обзора кода с репрезентативной выборкой:

Неверные операции с несколькими потоками

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

Как только вы получите оценку InvokeRequired, вы можете рассмотреть возможность использования метода расширения для переноса этих вызовов. Это хорошо описано в вопросе о переполнении стека Очистка кода, заполненного Invoke Required".

Существует также история истории, которая может быть интересной.

Ответ 2

Элемент управления или окна в Windows Forms - это всего лишь оболочка окна Win32, идентифицированного дескриптором (иногда называемым HWND). Большинство вещей, которые вы делаете с элементом управления, в конечном итоге приведет к вызову API Win32, который использует этот дескриптор. Ручка принадлежит потоку, который его создал (как правило, основной поток) и не должен обрабатываться другим потоком. Если по какой-то причине вам нужно что-то сделать с помощью элемента управления из другого потока, вы можете использовать Invoke, чтобы попросить основной поток сделать это от вашего имени.

Например, если вы хотите изменить текст метки из рабочего потока, вы можете сделать что-то вроде этого:

theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));

Ответ 3

Если вы хотите изменить элемент управления, это должно быть сделано в потоке, в котором был создан элемент управления. Этот метод Invoke позволяет вам выполнять методы в связанном потоке (поток, которому принадлежит элемент управления, лежащий в основе окна).

В приведенном ниже примере thread1 выдает исключение, потому что SetText1 пытается изменить textBox1.Text из другого потока. Но в thread2 Action в SetText2 выполняется в потоке, в котором был создан TextBox.

private void btn_Click(object sender, EvenetArgs e)
{
    var thread1 = new Thread(SetText1);
    var thread2 = new Thread(SetText2);
    thread1.Start();
    thread2.Start();
}

private void SetText1() 
{
    textBox1.Text = "Test";
}

private void SetText2() 
{
    textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}

Ответ 4

Вызывать ((MethodInvoker) делегат {textBox1.Text = "Test";});

Ответ 5

На практике это означает, что делегат гарантированно будет вызываться в основном потоке. Это важно, потому что в случае элементов управления Windows, если вы не обновляете свои свойства в основном потоке, вы либо не видите изменения, либо элемент управления вызывает исключение.

Образец:

void OnEvent(object sender, EventArgs e)
{
   if (this.InvokeRequired)
   {
       this.Invoke(() => this.OnEvent(sender, e);
       return;
   }

   // do stuff (now you know you are on the main thread)
}

Ответ 6

Это означает, что делегат будет запускаться в потоке пользовательского интерфейса, даже если вы вызываете этот метод из фонового рабочего или потока потока. Элементы пользовательского интерфейса имеют сходство нитей - им нравится говорить непосредственно с одним потоком: поток пользовательского интерфейса. Поток пользовательского интерфейса определяется как поток, который создал экземпляр управления, и поэтому связан с дескриптором окна. Но все это детализация реализации.

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

Ответ 7

this.Invoke(delegate) убедитесь, что вы вызываете делегат аргументом this.Invoke() в основном потоке/созданном потоке.

Я могу сказать, что правило Thumb не имеет доступа к элементам управления формы, кроме основного потока.

Возможно, следующие строки имеют смысл использовать Invoke()

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox1.InvokeRequired)
        {   
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

Есть ситуации, хотя вы создаете поток Threadpool (рабочий поток), который будет работать в основном потоке. Он не будет создавать новый поток coz основного потока, доступный для обработки дальнейших инструкций. Итак, сначала исследуем, является ли текущий текущий поток основным потоком, используя this.InvokeRequired, если возвращает true, текущий код работает в рабочем потоке, поэтому вызовите   this.Invoke(d, новый объект [] {текст});

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

Ответ 8

Делегирование по существу является встроенным Action или Func<T>. Вы можете объявить делегата вне области действия метода, который вы используете, или используя выражение lambda (=>); потому что вы запускаете делегат в рамках метода, вы запускаете его в потоке, который выполняется для текущего окна/приложения, которое является выделенным жирным шрифтом.

Пример Lambda

int AddFiveToNumber(int number)
{
  var d = (int i => i + 5);
  d.Invoke(number);
}

Ответ 9

Это означает, что передаваемый вами делегат выполняется в потоке, который создал объект Control (который является потоком пользовательского интерфейса).

Вам нужно вызвать этот метод, когда ваше приложение многопоточно, и вы хотите выполнить некоторую операцию пользовательского интерфейса из потока, отличного от потока пользовательского интерфейса, потому что если вы просто попытаетесь вызвать метод в элементе управления из другого потока, Получите исключение System.InvalidOperationException.