跨线程操作无效:从创建它的线程以外的线程访问控制


扬尘
2024-12-23 02:40:58 (2月前)
  1. 我有一个场景。 Windows FormsC#,.NET

有一个主要形式托管一些用户

控制
</跨度>

用户

控制
</跨度>
有些沉重

数据
</跨度>
操作,如果我直接调用UserControl_Load …在主要主线程上创建。在我正在获取的usercontrol的LOAD方法中

数据
</跨度>
基于一些的价值观

控制
</跨度>
在userControl上(如文本框)。

伪代码看起来像这样:

代码……

17 条回复
  1. 0# 蜡笔小辛 | 2019-08-31 10-32



    跨线程操作有两种选择。




    1. Control.InvokeRequired Property

    2. </code>


    第二个是使用




    1. SynchronizationContext Post Method

    2. </code>


    Control.InvokeRequired仅在从Control类继承的工作控件时有用,而SynchronizationContext可以在任何地方使用。一些有用的信息如下链接




    跨线程更新UI | 。净




    使用SynchronizationContext |交叉线程更新UI 。净


  2. 1# 林老爷的日常 | 2019-08-31 10-32



    行动y; //在课堂内宣布



    label1.Invoke(Y =()=&GT; label1.Text = “文本”);


  3. 2# 布偶的表弟派大星丶 | 2019-08-31 10-32



    如果您正在使用的对象没有,则可以使用另一种方法




    1. (InvokeRequired)

    2. </code>


    如果您使用主窗体以外的类中的主窗体并且主窗体中的对象处于主窗体但没有InvokeRequired,这将非常有用




    1. delegate void updateMainFormObject(FormObjectType objectWithoutInvoke, string text);

    2. private void updateFormObjectType(FormObjectType objectWithoutInvoke, string text)
      {
      MainForm.Invoke(new updateMainFormObject(UpdateObject), objectWithoutInvoke, text);
      }

    3. public void UpdateObject(ToolStripStatusLabel objectWithoutInvoke, string text)
      {
      objectWithoutInvoke.Text = text;
      }

    4. </code>


    它的工作原理与上面相同,但是如果你没有一个带有invokerequired的对象,但它有权访问MainForm,那么它是一种不同的方法


  4. 3# 甲基蓝 | 2019-08-31 10-32



    我有这个问题

    FileSystemWatcher

    并发现以下代码解决了这个问题:




    fsw.SynchronizingObject = this



    然后,控件使用当前表单对象来处理事件,因此将在同一个线程上。


  5. 4# 早岁那知世事艰 | 2019-08-31 10-32



    这不是解决此错误的推荐方法,但您可以快速抑制它,它将完成这项工作。我更喜欢这个原型或演示。加




    1. CheckForIllegalCrossThreadCalls = false

    2. </code>




    Form1()

    构造函数。


  6. 5# 薄情 | 2019-08-31 10-32



    UI中的线程模型



    请阅读


    线程模型


    在UI应用程序中,以了解基本概念。该链接导航到描述WPF线程模型的页面。但是,Windows窗体使用相同的想法。



    UI线程











    BeginInvoke和Invoke方法







    调用







    的BeginInvoke







    代码解决方案



    阅读有关问题的答案

    如何从C#中的另一个线程更新GUI?


    对于C#5.0和.NET 4.5,推荐的解决方案是

    这里



  7. 6# 大黑骡子王 | 2019-08-31 10-32




    1. this.Invoke(new MethodInvoker(delegate
      {
      //your code here;
      }));

    2. </code>

  8. 7# 满目山河 | 2019-08-31 10-32



    您只想使用Invoke或BeginInvoke来完成更改UI所需的最少工作量。您的“重”方法应该在另一个线程上执行(例如,通过BackgroundWorker),然后使用Control.Invoke / Control.BeginInvoke来更新UI。这样你的UI线程就可以自由处理UI事件等。



    看我的

    穿线文章

    为一个

    WinForms示例

    1. - 虽然这篇文章是在BackgroundWorker到达现场之前编写的,但我担心我没有在这方面更新它。 BackgroundWorker只是略微简化了回调。


  9. 8# 一只特立独行的猪 | 2019-08-31 10-32



    .NET中的控件通常不是线程安全的。这意味着您不应该从它所在的线程以外的线程访问控件。要解决这个问题,你需要

    调用

    控件,这是你的第二个样本正在尝试。



    但是,在您的情况下,您所做的就是将长时间运行的方法传递回主线程。当然,这不是你想要做的。你需要重新考虑这一点,这样你在主线程上所做的就是在这里和那里设置一个快速的属性。


  10. 9# 哈哈哈哈 | 2019-08-31 10-32



    用于UI跨线程问题的最干净(和适当的)解决方案是使用SynchronizationContext,请参阅
    <a href =“http://www.lostechies.com/blogs/gabrielschenker/archive/2009/01/23/synchronizing-calls-to-the-ui-in-a-multi-threaded-application.aspx"rel = “noreferrer”>
    在多线程应用程序中同步对UI的调用

    文章,它解释得非常好。


  11. 10# Moso31 | 2019-08-31 10-32



    与以前的答案一样,
    但是很短的添加允许使用所有Control属性而不会有跨线程调用异常。




    辅助方法
    </强>




    1. ///
      /// Helper method to determin if invoke required, if so will rerun method on correct thread.
      /// if not do nothing.
      ///

      /// Control that might require invoking
      /// action to preform on control thread if so.
      /// true if invoke required
      public bool ControlInvokeRequired(Control c, Action a)
      {
      if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate
      {
      a();
      }));
      else return false;

    2. return true;
    3. }

    4. </code>



    样本用法
    </强>




    1. // usage on textbox
      public void UpdateTextBox1(String text)
      {
      //Check if invoke requied if so return - as i will be recalled in correct thread
      if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
      textBox1.Text = ellapsed;
      }

    2. //Or any control
      public void UpdateControl(Color c, String s)
      {
      //Check if invoke requied if so return - as i will be recalled in correct thread
      if (ControlInvokeRequired(myControl, () => UpdateControl(c, s))) return;
      myControl.Text = s;
      myControl.BackColor = c;
      }

    3. </code>

  12. 11# 我头上有犄角 | 2019-08-31 10-32



    按照最简单的(在我看来)方式修改另一个线程中的对象:




    1. using System.Threading.Tasks;
      using System.Threading;

    2. namespace TESTE
      {
      public partial class Form1 : Form
      {
      public Form1()
      {
      InitializeComponent();
      }

    3.     private void button1_Click(object sender, EventArgs e)
    4.     {
    5.         Action<string> DelegateTeste_ModifyText = THREAD_MOD;
    6.         Invoke(DelegateTeste_ModifyText, "MODIFY BY THREAD");
    7.     }
    8.     private void THREAD_MOD(string teste)
    9.     {
    10.         textBox1.Text = teste;
    11.     }
    12. }
    13. }

    14. </code>

  13. 12# 筱梨 | 2019-08-31 10-32



    例如,从UI线程的Control获取文本:




    1. Private Delegate Function GetControlTextInvoker(ByVal ctl As Control) As String

    2. Private Function GetControlText(ByVal ctl As Control) As String
      Dim text As String

    3. If ctl.InvokeRequired Then
    4.     text = CStr(ctl.Invoke(
    5.         New GetControlTextInvoker(AddressOf GetControlText), ctl))
    6. Else
    7.     text = ctl.Text
    8. End If
    9. Return text
    10. End Function

    11. </code>

  14. 13# 听风~ | 2019-08-31 10-32



    您需要查看Backgroundworker示例:



    http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

    特别是它如何与UI层交互。根据您的发布,这似乎可以解答您的问题。


  15. 14# v-star*위위 | 2019-08-31 10-32



    我现在知道太晚了。但是,即使在今天,如果您在访问跨线程控件时遇到问题?这是迄今为止最短的答案:P




    1. Invoke(new Action(() =>
      {
      label1.Text = WooHoo!!!”;
      }));

    2. </code>


    这是我从线程访问任何表单控件的方式。


  16. 15# 敢嫁就敢娶 | 2019-08-31 10-32




    同样的问题:如何更新-gui-from-another-thread-in-c



    两种方式:





    1. 在e.result中返回值并使用它在backgroundWorker_RunWorkerCompleted事件中设置yout文本框值





    2. 声明一些变量以将这些值保存在单独的类中(这将作为数据持有者)。创建此类的静态实例,您可以通过任何线程访问它。



    3. </醇>


      例:




      1. public class data_holder_for_controls
        {
        //it will hold value for your label
        public string status = string.Empty;
        }

      2. class Demo
        {
        public static data_holder_for_controls d1 = new data_holder_for_controls();
        static void Main(string[] args)
        {
        ThreadStart ts = new ThreadStart(perform_logic);
        Thread t1 = new Thread(ts);
        t1.Start();
        t1.Join();
        //your_label.Text=d1.status; —- can access it from any thread
        }

      3. public static void perform_logic()
      4. {
      5.     //put some code here in this function
      6.     for (int i = 0; i < 10; i++)
      7.     {
      8.         //statements here
      9.     }
      10.     //set result in status variable
      11.     d1.status = "Task done";
      12. }
      13. }

      14. </code>

登录 后才能参与评论