BackgroundWorker - Cross-thread operation not valid

前端 未结 7 1065
南方客
南方客 2020-12-14 19:16

I have a winform application (one form), on this form there is a RichTextBox. In the constructor of this form I create an instance of the class MyClass. In the

相关标签:
7条回答
  • 2020-12-14 19:31

    Using BackgroundWorker component, only the ProgressChanged and RunWorkerCompleted events allow you to invoke methods/properties on UI controls (which should be always done on UI thread). As you are updating the UI in DoWork event which runs on a non-UI thread you are getting this error, you should probably update you UI controls using Invoke or BeginInvoke methods in DoWork event if you want to.

    0 讨论(0)
  • 2020-12-14 19:43

    i think the error stops on this line:

    richtextBox.Text.Add("MyText");
    

    your question i similar to this:

    BackgroundWorker OnWorkCompleted throws cross-thread exception

    0 讨论(0)
  • 2020-12-14 19:44

    Add:

    e.Result = "MyText";
    

    In your bw_DoWork And:

    richTextBox1.AppendText((string)e.Result);
    

    In your bw_RunWorkerCompleted

    (Alter it to fit your code)

    EDIT:

    If it's done many times during the BackgroundWorker's work, you can add:

    _bw.ReportProgress(0, "MyText");
    

    to the bw_DoWork and:

    richTextBox1.AppendText((string)e.UserState);
    

    to the bw_ProgressChanged.

    0 讨论(0)
  • 2020-12-14 19:48

    To make it cleaner and based on Jon Skeet's suggestion, I made an extension method which does the same, you can change the "this Label control" to this TextBox control or simply use "this Control control" (and basically allow every control to be updated easily):

    internal static class ExtensionMethods
    {
        /// <summary>
        /// Updates the label text while being used in a multithread app.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="text">The text.</param>
        internal static void UpdateThreadedText(this Label control, string text)
        {
            Action action = () => control.Text = text;
            control.Invoke(action);
        }
    
        /// <summary>
        /// Refreshes the threaded.
        /// </summary>
        /// <param name="control">The control.</param>
        internal static void RefreshThreaded(this Label control)
        {
            Action action = control.Refresh;
            control.Invoke(action);
        }
    }
    

    And then the usage is quite simple:

    this.yourLabelName.UpdateThreadedText("This is the text");
    this.yourTextBoxName.UpdateThreadedText("This is the text");
    this.yourControlName.UpdateThreadedText("This is the text");
    

    or

    this.yourLabelName.RefreshThreaded();
    

    Works for me nicely :)

    0 讨论(0)
  • 2020-12-14 19:49

    Using BackgroundWorker doesn't exempt you of the normal threading rules - such as that only the UI thread can access UI components.

    If you want to update the UI from a BackgroundWorker other than using the progress/completion events (which are raised on the UI thread) you need to use Control.Invoke / Control.BeginInvoke just as you would in other situations. For example:

    if (....)
    {
        Action action = () => richtextBox.Text.Add("MyText");
        richtextBox.Invoke(action); // Or use BeginInvoke
    }
    
    0 讨论(0)
  • 2020-12-14 19:49

    try this code,

    BeginInvoke((MethodInvoker)delegate
    {
        richtextBox.Text.Add("MyText");
    });
    
    0 讨论(0)
提交回复
热议问题