-1

I get an InvalidOperationException with the message,

Control control name accessed from a thread other than the thread it was created on.

The "Control" was created by a Thread that is no longer doing any work, and I don't know how if I can invoke the method or if I should create a local variable that contains the value of the tags_richtextbox. The class that is Giving the error:

public class details_Panel
{
    public string tags
    {
        get { return tags_richtextbox.Text; }
        set { tags_richtextbox.Text = value; }
    }
    private RichTextBox tags_richtextbox = new RichTextBox() { DetectUrls = false, Dock = System.Windows.Forms.DockStyle.Fill, ReadOnly = true };
}

The Function Giving the error:

detailsPanelSaveData.tags.AddRange(ent.detailspanel.tags.Split(','));

So should I Invoke or add a private variable that has the same value as tags_richtextbox.Text and if I should invoke, whats the syntax to do that and wait for it to finish? (I'm still learning about threading and figuring out the correct invoke syntax)

Edit: DetailPanelSaveData.tags is a List<string> Just realized I wasn't very clear
So to Clarify I'm trying to save a split string in a list of strings.

Jason Brown
  • 127
  • 2
  • 13
  • There are plenty of question about dealing with the exception and how to use `Control.Invoke` (or you can check [documentation](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) as last resort) - so lack of demonstrated research calls for downvote. The second part of the question is mostly opinion based - it is really up to you how/if you should refactor code. There are many ways to deal with the cross-thread access to controls and listing all of them would be too long. – Alexei Levenkov Oct 30 '15 at 02:55
  • 1
    Possible duplicate of [Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on](http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed-from-a-thread-other-than-the) –  Oct 30 '15 at 03:04

1 Answers1

1

The "Control" was created by a Thread that is no longer doing any work

Without a good, minimal, complete code example that reliably reproduces the problem, it's impossible to completely understand the problem. However, the idea of there being a thread in which some instance of a control was created, and yet that thread "is no longer doing any work" is a bit weird, to say the least.

Control objects must only be created in a thread that is running the UI. In most programs, there is only one such thread and there should only ever be one such thread. If you have code running in a different thread, and due to some operation in that thread there is a point at which a control needs to be created, you need to transfer execution to that one UI thread for the purpose of creating the control, so that the control is created in the correct thread.

Without a better code example, it's not clear what else you need to fix. But for sure, you need to change the code where that control is created so that you're creating the control in the UI thread.

Elsewhere, e.g. when you are converting the text into an array of tags to add to your list, you may also need to transfer execution to the UI thread when you access the tags property where the tags_richtextbox object is accessed. Or maybe you won't. That all depends on where that code is executing; if it's in the UI thread, then you're all set. Otherwise, yes…you need to wrap the operation in some kind of cross-thread invocation.


NOTE: nowhere in your question are you specific about which GUI API in .NET you are using. Judging from the little bit of code and your comments in the question, I'm guessing this is Winforms. But WPF and Winrt (Store apps) have the same issue, and so the above advice applies equally in all scenarios. Of course, the exact technique for transferring execution to the UI thread varies according to API. Winforms uses Control.Invoke(), WPF uses Dispatcher.Invoke(), and Winrt uses Dispatcher.RunAsync(). It is these methods (or their asynchronous equivalents, in the case of Winforms or WPF) to which I am referring when I describe a "cross-thread invocation" or the need to "transfer execution to the UI thread".

NOTE: there is one exception to some of the above, which I hesitate to even mention because I doubt it applies in your scenario, and even if it does, the first thing you should do is fix your code so it doesn't. But for completeness, I am compelled to mention that a program can have more than UI thread running at a time. This is rare and should be avoided, but it can happen. If it does, then it is possible that one control object could be created in a thread that is legitimately different from that which owns some other control object. Now, in that case it would be your responsibility to ensure that any given UI thread continues to run for as long as any of the objects it owns still exist, and you will still need to use the GUI API's mechanism for transferring execution to a different thread when that object is accessed by a thread other than the one which owns it. But that is a way that, even though still not correct, you could wind up with a control object that was created by a UI thread that "is no longer doing any work".

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Sorry I'm using WinForms and as for the thread that was doing work, it runs until the program is set to close down, and then it runs out of things to do since the work is no longer being sent. This thread creates objects that contain a predefined tablelayoutpanel that contains all the labels and other information. Anyway the only object that was having an issue was the RichTextBox so I just added a variable that's the same value as the RichTextBox.Text. I will attempt to give a proper code example just to show what was happening. – Jason Brown Oct 30 '15 at 05:26
  • Im not sure How to make a working Small Scale version of the code, But I did make a small scale non working version of it, that shows the issue (also shows the reason that im in this situation is, My dislike for events) http://pastebin.com/YsvaiRCz – Jason Brown Oct 30 '15 at 06:40
  • @JasonBrown: if you have a good code example, it belongs in the original question, not at an external web site. Please edit your question to improve it. – Peter Duniho Oct 30 '15 at 06:44
  • I'm not sure I could call it good, otherwise I would put it in the question...Its long, and written without testing...I will touch it up a bit before I add it to the original question. Its time consuming though, trying to figure out a decent small example that gives the same error. – Jason Brown Oct 30 '15 at 09:06
  • @JasonBrown: _"Its time consuming though"_ -- perhaps. Still, you are the person in the best position to do so, and who has the most incentive to expend time, which is valuable to every person, on the problem. :) – Peter Duniho Oct 30 '15 at 15:29
  • I gave up on writing a small scale version of what I was doing, I ended up fixing the problem by creating another variable that stores a copy of the value of text and returns that instead of the control.text – Jason Brown Oct 31 '15 at 01:42
  • @JasonBrown: then your code is likely still broken. If you don't need that `RichTextBox` instance at all, then just remove it. Use the new variable to track the text instead. If you do need that instance, then you need to make sure it's created, and used, in the correct thread. – Peter Duniho Oct 31 '15 at 06:00
  • I ended up basically completely removing the class that had the richtextbox and essentially just added it directly onto the winform, Anyway Thanks for the notes. Since I have only started working with C#, I still don't have a great idea as to how I should do common things. And generally have to go back and rewrite stuff. Although getting rid of the large amount of controls that were being created has increased the speed of everything by quite alot. (load/save was taking 30seconds for 100 entrys now it takes less then 1) (I haven't properly benchmarked it yet though) – Jason Brown Oct 31 '15 at 07:35