System windows forms control invoke

Человек даже немного поработав с Windows Forms наверняка сталкивался с замечательным исключением System.InvalidOperationException с таким описанием:
{«Cross-thread operation not valid: Control ‘textBox1’ accessed from a thread other than the thread it was created on.»}
Этим сообщением среда выполнения недвусмысленно дает понять, что обращаться к элементам управления пользовательского интерфейса можно только из того потока, который создал этот элемент управления. Такое поведение обусловлено деталями реализации, в частности использованием однопоточной модели аппартаментов (Single-threaded Apartment, STA) и механизма обработки оконных сообщений.
Вот простенький пример кода, который приводит к генерации такого исключения:

public partial class Form1 : Form

{

    public Form1()

    {

        InitializeComponent();

        //на форме расположен TextBox и Button.

        //В TextBox будет выводиться количество сработок таймера,

        //таймер запускается по нажатию на кнопку Button

        timer = new Timer(AsyncHandler);

    }

    private void button1_Click(object sender, EventArgs e)

    {

        timer.Change(1000, 1000);

    }

    private void AsyncHandler(object data)

    {

        tickCount++;

        textBox1.Text = tickCount.ToString();

    }

    private readonly System.Threading.Timer timer;

    private int tickCount;

}

Существует вполне простой и понятный способ решения этой проблемы, путем проверки свойства элемента управления InvokeRequired с последующим вызовом метода Invoke.

Вот самый простой и примитивный способ:

private void AsyncHandler(object data)

{

    tickCount++;

    Action<int> action = DoChangeTicks;

    if (InvokeRequired)

    {

        Invoke(action, tickCount);

    }

    else

    {

        action(tickCount);

    }

}

private void DoChangeTicks(int count)

{

    textBox1.Text = tickCount.ToString();

}

Способ простой, но не совсем удобный. В данном случае вспомогательный метод только увеличивает связность и усложняет понимает решаемой задачи.
Если воспользоваться новшествами C#3.0 в виде лямбда-выражений, можно сделать несколько более удобную реализацию следующего вида:

private void AsyncHandler(object data)

{

    tickCount++;

    Action action = () => textBox1.Text = tickCount.ToString();

    if (InvokeRequired)

    {

        Invoke(action);

    }

    else

    {

        action();

    }

}

Уже лучше. Мы избавились от необязательного метода, который неразрывно связан с тем действием, которое выполняет метод AsyncHandler. Но, все же, еще есть над чем подумать.

Следующий вариант решения был честно подсмотрен в неплохой книжке: Bill Wagner «More Effective C#».

/// <summary>

/// Расширения облегчающие работу с элементами управления в многопоточной среде.

/// </summary>

public static class ControlExtentions

{

    /// <summary>

    /// Вызов делегата через control.Invoke, если это необходимо.

    /// </summary>

    /// <param name=»control»>Элемент управления</param>

    /// <param name=»doit»>Делегат с некоторым действием</param>

    public static void InvokeIfNeeded(this Control control, Action doit)

    {

        if (control.InvokeRequired)

            control.Invoke(doit);

        else

            doit();

    }

    /// <summary>

    /// Вызов делегата через control.Invoke, если это необходимо.

    /// </summary>

    /// <typeparam name=»T»>Тип параметра делегата</typeparam>

    /// <param name=»control»>Элемент управления</param>

    /// <param name=»doit»>Делегат с некоторым действием</param>

    /// <param name=»arg»>Аргумент делагата с действием</param>

    public static void InvokeIfNeeded<T>(this Control control, Action<T> doit, T arg)

    {

        if (control.InvokeRequired)

            control.Invoke(doit, arg);

        else

            doit(arg);

    }

}

С помощью этого вспомогательного класса, реализация метода, взаимодействующего с элементами управления из других потоков, будет следующей:

private void AsyncHandler(object data)

{

    tickCount++;

    this.InvokeIfNeeded(

        () => textBox1.Text = tickCount.ToString()

            );

}

C#: зачем нужны InvokeRequired и Invoke?


Добавил(а) microsin

  

Вы наверное знаете, что нельзя просто так обращаться к графическим элементам управления интерфейса пользователя (GUI формы) из других потоков, таких как BackgroundWorker [2]. Это связано с безопасностью данных потоков, когда конкурентное обращение разными потоками к одним и тем же данным на запись может привести к непредсказуемому поведению программы.

Предотвращают такие неприятные ситуации специальные программные решения. В потоке BackgroundWorker, например, этот функционал инкапсулирован в вызове ReportProgress и обработчике ProgressChanged. Для обращения к элементам интерфейса управления пользователя (к экземпляру класса System.Windows.Forms.Control, и следовательно экземпляру формы окна программы System.Windows.Forms.Form как частности) из сторонних потоков как раз и нужны свойство InvokeRequired и метод Invoke класса Control.

Методы Invoke/BeginInvoke позволяют Вам перепоручить (делегировать, delegate) классу GUI вызов некоторых связанных с интерфейсом пользователя методов. Передаваемые в форму данные (такие как значения параметров) помещаются в некую очередь, поддерживаемую потоком GUI. Поток GUI берет из этой очереди элементы и выполняет реальные вызовы синхронно с другими вызовами обработки GUI. С помощью Invoke вызывающий сторонний поток (не поток GUI) переводится в состояние ожидания, пока вызов не будет завершен потоком GUI. BeginInvoke сделает возврат немедленно в момент реального вызова.

Итак, invoke-методы реализованы в классе Control (и также в экземпляре формы Form1 приложения), и полезно их использовать только тогда, когда Вы вызываете методы формы или обращаетесь к её свойствам (т. е. к классу Control) из потока, который не относится к потоку обработки графического интерфейса формы (GUI).

[InvokeRequired]

Чтобы было понятно, давайте разберемся подробнее. InvokeRequired делает проверку, в каком контексте работает текущий код. Проверка InvokeRequired нужна только тогда, когда вызов/обращение к форме происходит из стороннего потока, не относящегося к GUI.

InvokeRequired всегда вернет true, если это работает контекст чужого потока (не потока GUI), тогда необходимо вызывать Invoke со ссылкой на текущий выполняемый код (как это делается, будет показано на примере ниже). Если это не сделать, то произойдет ошибка времени выполнения:

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

InvokeRequired всегда вернет false, если работает поток GUI, и в этом случае вызывать Invoke не требуется.

[Invoke]

Добавим ясности: разберем простой конкретный пример с компонентом USB HID (библиотека UsbLibrary), код которого работает в отдельном потоке. Экземпляр класса UsbHidPort myUSB сделан дочерним по отношению к классу формы приложения, и в его обработчике приема данных необходимо отображать принятые данные в ListBox формы. Обработчик приема данных UsbHidPort работает в отдельном потоке, не в потоке GUI формы, поэтому без invoke-функционала добавить данные в ListBox формы формы нельзя. Для потокобезопасной работы в обработчике приема данных UsbHidPort нужно добавить код наподобие следующего:

private void usb_OnDataRecieved(object sender, DataRecievedEventArgs args)
{
   try
   {
      string DataSt = null;
      if (ParentForm.InvokeRequired)
      {
         ParentForm.Invoke(new DataRecievedEventHandler(usb_OnDataRecieved),
                           new object[] { sender, args });
      }
      else
      {
         // Показываем, что приняли:
         for (int i = 4; i < args.data.Length; i++)
            DataSt += (char)(args.data[i]);
         ParentForm.lbConsole.Items.Add(DataSt);
         logfile.write(DataSt);
      }
   }
   catch (Exception ex)
   {
      logfile.write(ex.Message);
   }
}

Обратите внимание, что вызов InvokeRequired и Invoke формы приложения происходит через переменную ParentForm, добавленную к классу myUSB, которая была предварительно инициализирована в коде загрузки формы после вызова конструктора экземпляра класса mySUB.

namespace WindowsFormsApplication1
{
   public partial class FormMain : Form
   {
      log logfile;
      public myUSB myusb;
 
      public FormMain()
      {
         InitializeComponent();
      }
 
      void Form1_Load(object sender, EventArgs e)
      {
         myusb = new myUSB();
         myusb.ParentForm = this;
... }
 
      //Другие методы формы:
      ...
   }
}
namespace WindowsFormsApplication1
{
   public class myUSB
   {
      byte[] rxdata;
      int rxidx;
      public UsbHidPort usb;
      const int WAIT_ANSWER_TIMEOUT = 500;
      log logfile;
      public FormMain ParentForm;
 
      public void RxReset()
      {
         rxidx = 0;
         rxdata[0] = 0;
      }
 
      //Конструктор
      public pkrc()
      {
         if (null == logfile)
            logfile = new log(this.GetType().ToString());
         if (null == rxdata)
            rxdata = new byte[256];
         RxReset();
         if (null == usb)
            usb = new UsbHidPort();
         usb.VendorId = 0x03EB;
         usb.ProductId = 0x6201;
      }
 
      ~pkrc()
      {
         Close();
      }
 
      #region Обработка событий USB библиотеки
      /// < summary>
      /// Запустится при подключении любого USB устройства
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="e">< /param>
      private void usb_OnDeviceArrived(object sender, EventArgs e)
      {
         logfile.write("usb_OnDeviceArrived");
      }
 
      /// < summary>
      /// При отключении любого устройства USB
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="e">< /param>
      private void usb_OnDeviceRemoved(object sender, EventArgs e)
      {
         logfile.write("usb_OnDeviceRemoved");
      }
 
      /// < summary>
      /// При подключении определенного устройства USB
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="e">< /param>
      private void usb_OnSpecifiedDeviceArrived(object sender, EventArgs e)
      {
         logfile.write("usb_OnSpecifiedDeviceArrived");
      }
      /// < summary>
      /// При отключении определенного устройства USB
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="e">< /param>
      private void usb_OnSpecifiedDeviceRemoved(object sender, EventArgs e)
      {
         if (ParentForm.InvokeRequired)
         {
            ParentForm.Invoke(new EventHandler(usb_OnSpecifiedDeviceRemoved),
            new object[] { sender, e });
         }
         else
         {
            logfile.write("UsbHidPort closed");
         }
      }
 
      /// < summary>
      /// ////////////////////////////////////////////////////////////////////////////////
      /// Приём данных
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="args">Report, принятый от устройства USB HID, содержится
      /// в args.data< /param>
      private void usb_OnDataRecieved(object sender, DataRecievedEventArgs args)
      {
         try
         {
            if (ParentForm.InvokeRequired)
            {
               ParentForm.Invoke(new EventHandler(usb_OnDataRecieved),
                                 new object[] { sender, e });
            }
            else
            {
               string DataSt = null;
               //Простой вывод в лог данных:
               for (int i = 0; i < args.data.Length; i++)
                  DataSt += args.data[i].ToString("X2") + " ";
               logfile.write(DataSt);
               //Вывод данных в ListBox формы:
               ParentForm.lbConsole.Items.Add(DataSt);
            }
         }
         catch (Exception ex)
         {
            logfile.write(ex.Message);
         }
      }
 
      /// < summary>
      /// При передаче данных в устройство USB
      /// < /summary>
      /// < param name="sender">< /param>
      /// < param name="e">< /param>
      private void usb_OnDataSend(object sender, EventArgs e)
      {
         //logfile.write("usb_OnDataSend");
      }
      #endregion
      
      public void Open()
      {
         //Инициализация библиотеки USB HID.
         usb.OnDataRecieved += new DataRecievedEventHandler(this.usb_OnDataRecieved);
         usb.OnDataSend += new System.EventHandler(this.usb_OnDataSend);
         usb.OnDeviceArrived += new System.EventHandler(this.usb_OnDeviceArrived);
         usb.OnDeviceRemoved += new System.EventHandler(this.usb_OnDeviceRemoved);
         usb.OnSpecifiedDeviceArrived += new System.EventHandler(this.usb_OnSpecifiedDeviceArrived);
         usb.OnSpecifiedDeviceRemoved += new System.EventHandler(this.usb_OnSpecifiedDeviceRemoved);
         try
         {
            usb.Open(false);
            if (0 != usb.GetLastError)
            {
               logfile.write(String.Format("cannot open USB HID device VID:0x{0:X4} PID:0x{1:X4}",
                             usb.VendorId, usb.ProductId));
            }
         }
         catch (Exception ex)
         {
            logfile.write(ex.Message);
         }
      }
 
      public void Close()
      {
         usb.Close();
      }
 
      public String Received()
      {
         string rx = Encoding.GetEncoding(1251).GetString(rxdata).Substring(0, rxidx);
         if (rx.Contains(DBGMSG))
         {
            if (rx.Contains("\r\n"))
            {
               int pos = rx.IndexOf("\r\n");
               int len = pos - DBGMSG.Length;
               logfile.write(rx.Substring(DBGMSG.Length, len));
               rx = rx.Substring(pos+2);
            }
         }
         return rx;
      }
 
      public bool SendHID(UInt32 cmdcode, byte [] data, int len)
      {
         bool sendOK = false;
         byte[] Report = new byte[usb.SpecifiedDevice.OutputReportLength];
         int idx = 0;
         Report[idx++] = 0;  //report ID
         //Добавление передаваемых данных в Report (полезная нагрузка):
         Report[idx++] = 'D';
         Report[idx++] = 'E';
         Report[idx++] = 'A';
         Report[idx++] = 'D';
         Report[idx++] = 'B';
         Report[idx++] = 'E';
         Report[idx++] = 'E';
         Report[idx++] = 'F';
         while (idx < usb.SpecifiedDevice.OutputReportLength)
            Report[idx++] = 0;            //остаток буфера обнуляем
         try
         {
            usb.SpecifiedDevice.SendData(Report);
            sendOK = true;
         }
         catch (Exception ex)
         {
            logfile.write(ex.Message);
         }
         return sendOK;
      }
   }
}

[Ссылки]

1. invoke in other class site:codeproject.com.
2. Visual Studio C++ 2010 Express: BackgroundWorker Class.
3. Идеология C#: события и делегаты.

System.Windows.Forms.Control.Invoke(System.Delegate)

Here are the examples of the csharp api class System.Windows.Forms.Control.Invoke(System.Delegate) taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

200 Examples

1. Example

Project: naps2
Source File: WiaBackgroundEventLoop.cs

public void Dispose()
        {
            if (thread != null)
            {
                try
                {
                    form.Invoke(new Action(Application.ExitThread));
                }
                catch (Exception ex)
                {
                    Log.ErrorException("Error disposing WIA event loop", ex);
                }
                thread = null;
            }
        }

2. Example

Project: naps2
Source File: FormBase.cs

public void Invoke(Action action)
        {
            ((Control) this).Invoke(action);
        }

3. Example

Project: tcp-moe
Source File: Authentication.cs

public void Unlock()
        {
            this.Invoke((MethodInvoker)delegate
            {
                this.Enabled = true;
            });
        }

4. Example

Project: tcp-moe
Source File: Loader.cs

public void InjectionFinished()
        {
            this.Invoke((MethodInvoker)delegate
            {
                UI.MsgBox.Show("Successfully loaded " + lstCheatList.SelectedItem.ToString() + "!", "Injection successful", MessageBoxIcon.Information);
                Worker.instance.Shutdown();
            });
        }

5. Example

Project: ClientServerProject
Source File: NetClientItem.cs

private void ThreadPoolLoadPortrait(object obj)
        {
            // ?????????
            if (m_NetAccount != null)
            {
                Bitmap bitmap = UserClient.PortraitManager.GetSmallPortraitByUserName(m_NetAccount.UserName);

                if(IsHandleCreated)
                {
                    Invoke(new Action(() =>
                    {
                        pictureBox1.Image = bitmap;
                    }));
                }
            }
        }

6. Example

Project: ClientServerProject
Source File: FormMainWindow.cs

private void Net_socket_client_LoginSuccess()
        {
            // ??????????????????????????????
            if (IsHandleCreated) Invoke(new Action(() =>
            {
                toolStripStatusLabel_status.Text = "???????";
            }));
        }

7. Example

Project: ClientServerProject
Source File: FormMainWindow.cs

private void Net_socket_client_BeforReConnected()
        {
            // ???????????????????????
            if (IsHandleCreated && IsWindowShow) Invoke(new Action(() =>
            {
                netClientOnline1.ClearOnlineClients();
            }));
        }

8. Example

Project: ClientServerProject
Source File: FormMainWindow.cs

private void Net_socket_client_MessageAlerts(string object1)
        {
            // ????
            if (IsHandleCreated) Invoke(new Action(() =>
            {
                toolStripStatusLabel_status.Text = object1;
            }));
        }

9. Example

Project: BuildToolsGUI
Source File: BuildTools.cs

private void Disable() {
            if (InvokeRequired) {
                Invoke(_disableDelegate);
            } else {
                updateBT.Enabled = false;
                runBT.Enabled = false;
                versionBox.Enabled = false;
            }
        }

10. Example

Project: BuildToolsGUI
Source File: BuildTools.cs

private void Enable() {
            if (InvokeRequired) {
                Invoke(_enableDelegate);
            } else {
                updateBT.Enabled = true;
                runBT.Enabled = true;
                versionBox.Enabled = true;
            }
        }

11. Example

Project: BuildToolsGUI
Source File: BuildTools.cs

public void ProgressShow() {
            if (InvokeRequired) {
                Invoke(_showProgressDelegate);
            } else {
                progress.Visible = true;
            }
        }

12. Example

Project: BuildToolsGUI
Source File: BuildTools.cs

public void ProgressHide() {
            if (InvokeRequired) {
                Invoke(_hideProgressDelegate);
            } else {
                progress.Visible = false;
            }
        }

13. Example

Project: BuildToolsGUI
Source File: BuildTools.cs

public void ProgressIndeterminate() {
            if (InvokeRequired) {
                Invoke(_indeterminateProgressDelegate);
            } else {
                progress.Style = ProgressBarStyle.Marquee;
            }
        }

14. Example

Project: Depressurizer
Source File: CancelableDlg.cs

protected void DisableAbort()
        {
            if (InvokeRequired)
            {
                Invoke(new SimpleDelegate(DisableAbort));
            }
            else
            {
                cmdStop.Enabled = cmdCancel.Enabled = false;
            }
        }

15. Example

Project: Depressurizer
Source File: MainForm.cs

private void reorderFillerColumn()
        {
            if (lstGames.InvokeRequired)
            {
                RemoveItemCallback callback = reorderFillerColumn;
                Invoke(callback);
            }
            else
            {
                // filler column should always be last column
                colFiller.DisplayIndex = (lstGames.ColumnsInDisplayOrder.Count - 1);
            }
        }

16. Example

Project: DroppedBoxx
Source File: Form1.cs

public void ShowSyncStatus()
        {
            if (this.InvokeRequired)
            {
                ShowSyncStatusDelegate dlg = new ShowSyncStatusDelegate(this.ShowSyncStatus);
                this.Invoke(dlg);
                return;
            }

            //do something with the GUI control here
            if (FoldersPanel.Visible)
            {
                //update the sync status stuff...
                FoldersPanel.UpdateSyncStatus();
            }
        }

17. Example

Project: DotNetSiemensPLCToolBoxLibrary
Source File: ConnectionEditor.cs

public void enableCmdTest()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(enableCmdTest));
                return;
            }
            cmdTest.Enabled = true;
        }

18. Example

Project: DotNetSiemensPLCToolBoxLibrary
Source File: Form1.cs

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                myConn.Connect();
                myDelegate += new stateConnectedDelegate(stateConnected);
                this.Invoke(myDelegate);
            }
            catch (Exception)
            {
                backgroundWorker1.ReportProgress(0);
            }
           
            
        }

19. Example

Project: WsdlUI
Source File: uc_Wm.cs

void uc_wm_request1_OnXmlFormatError(object sender, uc_WmRequest.XmlFormatErrorEventArgs e) {

            Invoke((MethodInvoker)(() => {
                uc_log1.LogErrorMessage(e.ErrorMessage);
            }));

        }

20. Example

Project: WsdlUI
Source File: uc_Wm.cs

void SetReady(string message) {

            Invoke((MethodInvoker)(() => {

                uc_log1.LogInfoMessage(message);

                uc_Status1.StatusReady();

                uc_wm_request1.Enable();

                tsbtn_Go.Enabled = true;
                tsbtn_Cancel.Enabled = false;

            }));
        }

21. Example

Project: WsdlUI
Source File: uc_Wm.cs

void SetInProgress() {
            Invoke((MethodInvoker)(() => {

                uc_log1.LogInfoMessage("request start");

                uc_Status1.StatusInProgress();

                uc_wm_request1.Disable();

                tsbtn_Go.Enabled = false;
                tsbtn_Cancel.Enabled = true;

            }));
        }

22. Example

Project: duplicati
Source File: WinFormsRunner.cs

protected override void UpdateUIState(Action action)
        {
            m_handleProvider.Invoke(action);
        }

23. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

public void HandleChangeStateEvent(object sender, EventsThreads.ThreadStringEventArgs e)
        {
            Invoke(new MethodInvoker(() =>
            {
                if (Program.FormMainInstance != null)
                    Program.FormMainInstance.toolStripStatusLabelLeft.Text = e.Message;
                Program.LogThis(new Log(Log.ModuleType.MetadataSearch, e.Message, Log.LogType.debug));
            }));
        }

24. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

private void HandleCustomSearchStartEvent(object sender, EventArgs e)
        {
            Invoke(new MethodInvoker(() =>
            {
                Program.FormMainInstance.programState = FormMain.ProgramState.Searching;
                btnSearch.Text = "&Stop";
                btnSearch.Image = Resources.magnifier_stop;
            }));
        }

25. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

public void HandleCustomSearchEndEvent(object sender, EventsThreads.ThreadEndEventArgs e)
        {
            Invoke(new MethodInvoker(() =>
            {
                Program.FormMainInstance.programState = FormMain.ProgramState.Normal;
                btnSearch.Text = "&Search";
                btnSearch.Image = Resources.magnifier;
            }));
        }

26. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

public void HandleSearchStartEvent(object sender, EventArgs e)
        {
            Invoke(new MethodInvoker(() =>
            {
                btnSearchAll.Text = "&Stop";
                btnSearchAll.Image = Resources.world_search_stop;
                checkedListBoxExtensions.Enabled = panelSearchConfiguration.Enabled = false;
            }));
        }

27. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

public void HandleSearchEndEvent(object sender, EventsThreads.ThreadEndEventArgs e)
        {
            Invoke(new MethodInvoker(() =>
            {
                btnSearchAll.Text = "&Search All";
                btnSearchAll.Image = Resources.world_search;
                checkedListBoxExtensions.Enabled = panelSearchConfiguration.Enabled = true;
            }));
        }

28. Example

Project: FOCA
Source File: PanelMetadataSearch.cs

private void DownloadProgressChanged(object o, DownloadProgressChangedEventArgs dpce)
        {
            Invoke(new MethodInvoker(() =>
            {
                ((Download) dpce.UserState).Pbar.Value = dpce.ProgressPercentage;
                ((Download) dpce.UserState).DownloadStatus = Download.Status.Inprogress;
            }));
        }

29. Example

Project: FOCA
Source File: PanelTasks.cs

public void AddNewTask(TaskFOCA t)
        {
            Invoke(new MethodInvoker(delegate
            {
                pendientes.BeginUpdate();
                pendientes.Items.Add(t.id.ToString(), "[" + t.id + "] " + t, 75);
                pendientes.EndUpdate();

                pendientes.Columns[0].Text = @"Queued tasks (" + pendientes.Items.Count + @")";

                if (!bAutoScroll) return;
                if (pendientes.Items.Count > 0)
                    pendientes.EnsureVisible(pendientes.Items.Count - 1);
            }));
        }

30. Example

Project: FOCA
Source File: PanelTasks.cs

public void StartTask(TaskFOCA t)
        {
            Invoke(new MethodInvoker(delegate
            {
                ejecucion.BeginUpdate();
                ejecucion.Items.Add(t.id.ToString(), "[" + t.id + "] " + t, 75);
                ejecucion.EndUpdate();

                pendientes.BeginUpdate();
                pendientes.Items.RemoveByKey(t.id.ToString());
                pendientes.EndUpdate();

                ejecucion.Columns[0].Text = @"Running tasks (" + ejecucion.Items.Count + @")";
                pendientes.Columns[0].Text = @"Queued tasks (" + pendientes.Items.Count + @")";

                if (!bAutoScroll) return;
                if (ejecucion.Items.Count > 0)
                    ejecucion.EnsureVisible(ejecucion.Items.Count - 1);
            }));
        }

31. Example

Project: FOCA
Source File: PanelTasks.cs

public void EndTask(TaskFOCA t)
        {
            Invoke(new MethodInvoker(delegate
            {
                realizadas.BeginUpdate();
                realizadas.Items.Add(t.id.ToString(), "[" + t.id + "] " + t, 75);
                realizadas.EndUpdate();

                ejecucion.BeginUpdate();
                ejecucion.Items.RemoveByKey(t.id.ToString());
                ejecucion.EndUpdate();


                realizadas.Columns[0].Text = @"Finished tasks (" + realizadas.Items.Count + ")";
                ejecucion.Columns[0].Text = @"Running tasks (" + ejecucion.Items.Count + ")";

                if (!bAutoScroll) return;
                if (realizadas.Items.Count > 0)
                    realizadas.EnsureVisible(realizadas.Items.Count - 1);
            }));
        }

32. Example

Project: BehaviorIsManaged
Source File: RichTextBoxTarget.cs

protected override void CloseTarget()
        {
            if (this.CreatedForm)
            {
                this.TargetForm.Invoke((FormCloseDelegate)this.TargetForm.Close);
                this.TargetForm = null;
            }
        }

33. Example

Project: vsSolutionBuildEvent
Source File: StatusFrm.cs

protected void push(RichTextBox box, string message)
        {
            // box.InvokeRequired may does not check properly
            try {
                box.Text += message;
            }
            catch
            {
                box.Invoke((MethodInvoker)delegate {
                    box.Text += message;
                });
            }
        }

34. Example

Project: nemiro.oauth.dll
Source File: MainForm.cs

private void RequestEnd()
    {
      if (this.InvokeRequired)
      {
        this.Invoke(new Action(RequestEnd));
        return;
      }

      dataGridView1.Enabled = toolStrip1.Enabled = flowLayoutPanel1.Enabled = true;
      pictureBox1.Visible = false;
    }

35. Example

Project: FlingOS
Source File: MainForm.cs

private void UpdateRegisters()
        {
            if (InvokeRequired)
            {
             /n ..... /n //View Source file for more details /n }

36. Example

Project: bjd5
Source File: View.cs

public void SetColumnText(){
            if (ListView == null)
                return;

            //Ver5.8.6 Java fix
            if (ListView.Columns.Count != 8){
                return;
            }

            if (ListView.InvokeRequired){
                ListView.Invoke(new MethodInvoker(SetColumnText));
            }
            else{
                //?????????????????
                ListView.Columns[0].Text = (_kernel.IsJp()) ? "??" : "DateTime";
                ListView.Columns[1].Text = (_kernel.IsJp()) ? "??" : "Kind";
                ListView.Columns[2].Text = (_kernel.IsJp()) ? "????ID" : "Thread ID";
                ListView.Columns[3].Text = (_kernel.IsJp()) ? "??(???)" : "Function(Server)";
                ListView.Columns[4].Text = (_kernel.IsJp()) ? "????" : "Address";
                ListView.Columns[5].Text = (_kernel.IsJp()) ? "?????ID" : "Message ID";
                ListView.Columns[6].Text = (_kernel.IsJp()) ? "??" : "Explanation";
                ListView.Columns[7].Text = (_kernel.IsJp()) ? "????" : "Detailed information";
            }
        }

37. Example

Project: trizbort
Source File: Canvas.Automap.cs

public Room FindRoom(string roomName, string roomDescription, RoomMatcher matcher)
            {
                Room room = null;
                try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.FindRoom(roomName, roomDescription, matcher); }); }
                catch (Exception) { }
                return room;
            }

38. Example

Project: trizbort
Source File: Canvas.Automap.cs

public Room CreateRoom(Room existing, string name)
            {
                Room room = null;
                try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.CreateRoom(existing, name); }); }
                catch (Exception) { }
                return room;
            }

39. Example

Project: trizbort
Source File: Canvas.Automap.cs

public Room CreateRoom(Room existing, AutomapDirection directionFromExisting, string name)
            {
                Room room = null;
                try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.CreateRoom(existing, directionFromExisting, name); }); }
                catch (Exception) { }
                return room;
            }

40. Example

Project: trizbort
Source File: Canvas.Automap.cs

public void Connect(Room source, AutomapDirection directionFromSource, Room target)
            {
                try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.Connect(source, directionFromSource, target); }); }
                catch (Exception) { }
            }

41. Example

Project: trizbort
Source File: Canvas.Automap.cs

public void AddExitStub(Room room, AutomapDirection direction)
            {
                try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.AddExitStub(room, direction); }); }
                catch (Exception) { }
            }

42. Example

Project: trizbort
Source File: Canvas.Automap.cs

public void RemoveExitStub(Room room, AutomapDirection direction)
            {
                try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.RemoveExitStub(room, direction); }); }
                catch (Exception) { }
            }

43. Example

Project: trizbort
Source File: Canvas.Automap.cs

public void SelectRoom(Room room)
            {
                try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.SelectRoom(room); }); }
                catch (Exception) { }
            }

44. Example

Project: Baka-MPlayer-old
Source File: PlaylistControl.cs

private void OpenFile(string url)
        {
            Invoke((MethodInvoker)(() => mp.OpenFile(url)));
        }

45. Example

Project: Baka-MPlayer-old
Source File: MainForm.cs

private void mp_StdOutEvent(object sender, StdOutEventArgs e)
        {
            Invoke((MethodInvoker)delegate
            {
                if (e.StdOut.Equals("[ACTION] CLEAR_OUTPUT"))
                {
                    outputTextbox.Clear();
                    return;
                }

                outputTextbox.AppendText("\n" + e.StdOut);
                // auto scroll to end
                outputTextbox.SelectionStart = outputTextbox.TextLength;
                outputTextbox.ScrollToCaret();
            });
        }

46. Example

Project: Baka-MPlayer-old
Source File: MainForm.cs

public void CallSetBackForwardControls()
        {
            Invoke((MethodInvoker)SetBackForwardControls);
        }

47. Example

Project: ArnoldSimulator
Source File: WinFormsExtensions.cs

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

48. Example

Project: ArnoldSimulator
Source File: MainForm.cs

private void SimulationOnStateChanged(object sender, StateChangedEventArgs stateChangedEventArgs)
        {
            if (!IsDisposed)
                Invoke((MethodInvoker)UpdateButtons);
        }

49. Example

Project: TeraDamageMeter
Source File: DamageMeterForm.cs

private void InvokeAction(Action action)
        {
            if (IsDisposed)
                return;
            if (!InvokeRequired)
                throw new InvalidOperationException("Expected InvokeRequired");
            Invoke(action);
        }

50. Example

Project: TeraDamageMeter
Source File: SnifferForm.cs

private void InvokeAction(Action action)
        {
            if (IsDisposed)
                return;
            if (!InvokeRequired)
                throw new InvalidOperationException("Expected InvokeRequired");
            Invoke(action);
        }

Executes the specified delegate on the thread that owns the control’s underlying window handle.

Syntax

Parameters

method
A delegate that contains a method to be called in the control’s thread context.

Returns

The return value from the delegate being invoked, or null if the delegate has no return value.

Remarks

Delegates are similar to function pointers in C or C++ languages. Delegates encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code that calls the referenced method, and the method to be invoked can be unknown at compile time. Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and more secure.

The Control.Invoke(Delegate) method searches up the control’s parent chain until it finds a control or form that has a window handle if the current control’s underlying window handle does not exist yet. If no appropriate handle can be found, the Control.Invoke(Delegate) method will throw an exception. Exceptions that are raised during the call will be propagated back to the caller.

The delegate can be an instance of EventHandler, in which case the sender parameter will contain this control, and the event parameter will contain EventArgs.Empty. The delegate can also be an instance of System.Windows.Forms.MethodInvoker, or any other delegate that takes a void parameter list. A call to an EventHandler or System.Windows.Forms.MethodInvoker delegate will be faster than a call to another type of delegate.

Note:

An exception might be thrown if the thread that should process the message is no longer active.

Requirements

Namespace: System.Windows.Forms
Assembly: System.Windows.Forms (in System.Windows.Forms.dll)
Assembly Versions: 1.0.5000.0, 2.0.0.0

До сих пор мы работали с консолью не просто так. Дело в том, что у потоков есть множество ограничений. Далеко не все объекты .NET также безопасно могут существовать при обращении к ним со стороны нескольких потоков. Давайте посмотрим это на примере. Создайте новое WinForms-приложение и поместите на форму компонент RichTextBox и кнопку. Пишем код, который должен выполняться по нажатию кнопки:

   private void button1_Click(object sender, EventArgs e)
   {
     Thread thread = new Thread(new ThreadStart(ThreadFunction));
     thread.Start();
   }

Здесь у нас создается и запускается на выполнение новый поток, который будет выполнять метод ThreadFunction(). Метод потока выглядит следующим образом:

   void ThreadFunction()
   {
     for (int i = 0; i < 10; i++)
       richTextBox1.AppendText(i.ToString());
   }

Здесь мы в цикле из десяти шагов пытаемся вывести число в компонент RichTextBox. На самом деле у нас не выйдет даже одного раза вывести что-то в этот компонент. Нет, мы сможем откомпилировать пример и даже запустить его на выполнение. Но при попытке нажать на кнопку произойдет исключительная ситуация. На рис. 1 показано сообщение об исключительной ситуации из среды разра- ботки.

Рис. 1. Сообщение об исключительной ситуации

Нельзя обращаться к элементам управления, которые были созданы в других потоках. Наш элемент управления на форме был сделан в основном потоке, а доступ мы пытаемся получить из дочернего потока. Так как же нам получить доступ к компоненту из потока? Эта задача достаточно популярна при работе с потоками и решается довольно легко — через делегаты.

Для вывода текста в RichTextBox напишем следующий метод:

void PrintFunc(string str) { richTextBox1.AppendText(str); }

Метод выводит в компонент переданный в качестве параметра текст. Чтобы вызвать этот метод, нужно объявить соответствующий делегат и переменную делегата:

   delegate void PrintInRhichTextBox(string str);
   private PrintInRhichTextBox PrintDelegateFunc;

В конструкторе инициализируем переменную делегата:

   PrintDelegateFunc = new PrintInRhichTextBox(PrintFunc);

Теперь можно вызывать этот метод через делегат. Но не просто так, а через метод Invoke() компонента:

   richTextBox1.Invoke(PrintDelegateFunc,
       new object[] { i.ToString() });

Методу Invoke() передаются два параметра:

  • делегат, который нужно выполнить;
  • массив объектов параметров.

В нашем случае методу делегата нужно передать только один параметр — строку, которая должна выводиться в компоненте, ее и передаем.

Метод Invoke() компонента вызывает указанный метод делегата в потоке, которому и принадлежит этот компонент. Метод Invoke() возвращает значение, которое возвращает вызываемый делегат, или null, если делегат не возвращает никаких значений.

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


Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Windows delete unused drivers
  • Windows 10 расширить раздел
  • Как настроить гаджеты в windows 10
  • Как установить ubuntu через windows
  • Где находятся настройки видеокарты на windows 10