代码之家  ›  专栏  ›  技术社区  ›  Mike

跨线程分配属性

  •  1
  • Mike  · 技术社区  · 16 年前

    Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on 关于获得房产。

    因此,我的问题是,除了创建深度副本,或者将集合复制到不同的列表对象之外,还有更好的方法来避免for循环期间的错误。

    Cross-thread operation not valid: Control 'lstProcessFiles' accessed 
    from a thread other than the thread it was created on.
    

        private void btnRunProcess_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
    
            BackgroundWorker bg = new BackgroundWorker();
            bg.DoWork += new DoWorkEventHandler(bg_DoWork);
            bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
            bg.RunWorkerAsync();
       }
    
    
        void bg_DoWork(object sender, DoWorkEventArgs e)
        {
            WorkflowEngine engine = new WorkflowEngine();
            ListBox.SelectedObjectCollection selectedCollection=null;
    
            if (lstProcessFiles.InvokeRequired)
            {
                // Try #1
                selectedCollection = (ListBox.SelectedObjectCollection) 
                    this.Invoke(new GetSelectedItemsDelegate(GetSelectedItems), 
                    new object[] { lstProcessFiles });
    
                // Try #2
                //lstProcessFiles.Invoke(
                //    new MethodInvoker(delegate {
                //        selectedCollection = lstProcessFiles.SelectedItems; }));
            }
            else
            {
                selectedCollection = lstProcessFiles.SelectedItems;
            }         
    
            // *********Same Error on this line********************
            // Cross-thread operation not valid: Control 'lstProcessFiles' accessed 
            // from a thread other than the thread it was created on.
            foreach (string l in selectedCollection)
            {
                if (engine.LoadProcessDocument(String.Format(@"C:\TestDirectory\{0}", l)))
                {
                    try
                    {
                        engine.Run();                       
                        WriteStep(String.Format("Ran {0} Succussfully", l));
                    }
                    catch
                    {
                        WriteStep(String.Format("{0} Failed", l));
                    }
    
                    engine.PrintProcess();
                    WriteStep(String.Format("Rrinted {0} to debug", l));
                }
            }
        }
    
        private delegate void WriteDelegate(string p);
        private delegate ListBox.SelectedObjectCollection GetSelectedItemsDelegate(ListBox list);
    
        private ListBox.SelectedObjectCollection GetSelectedItems(ListBox list)
        {
            return list.SelectedItems;
        }
    
    4 回复  |  直到 9 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    this SO question

    在许多UI技术(Winforms、WPF、Silverlight)中,UI元素只能在UI线程上安全地进行交互。 这意味着在编写多线程代码时,需要使用所选UI库中的机制来正确地与UI控件交互。在WPF/Silverlight中 Dispatcher in WinForms 它需要使用 InvokeRequired BeginInvoke() 将工作分派到UI线程。

    在你的情况下,似乎你已经在尝试使用 BeginInvoke 分派到适当的线程。 我怀疑问题在于迭代ListBox的集合本身就是一个跨线程操作。 SelectedItems 收集工具 GetEnumerator() -最有可能的是,它没有复制收藏。因此,我怀疑您的代码必须在对其进行迭代之前创建一个副本,或者在UI线程上执行整个迭代。

    复制一份藏品并不坏,但话说回来,

        2
  •  1
  •   Ignacio Soler Garcia    16 年前

    必须使用控件的InvokeRequired属性,以避免从不同的线程调用一个控件。

    例如,检查 this page

        3
  •  0
  •   Paolo    16 年前

    您一直在传递此行中选定的项目:

    bg.RunWorkerAsync(lstProcessFiles.SelectedItems);

    你为什么要用嫁妆的方法把它们弄回来?

    通过以下方式从DoworkEventArgs访问它们:

    var collection = (ListBox.SelectedObjectCollection)e.Argument

    (在调用后台工作者之前,您可能仍需要将选定对象复制到一个普通列表中,我不确定该特定集合类型中存在哪些对象)

        4
  •  0
  •   Mike    16 年前

    我只是像这样复制了一个字符串对象。即使它是一个更复杂的物体,像这样的东西应该仍然有效

    private List<string> GetSelectedItems(ListBox list)
    {
        return lstProcessFiles.SelectedItems.Cast<string>().ToList();
    }