The following code is used to generate the value on the label.

///Метод является членом класса LabelReg, LabelReg отнаследован от Label protected void reg_OnResultRead(Reg sender, ModBusCommon.Error result, object data) { ///Получили новые данные double value = Convert.ToDouble(data) * Factor; ///Формируется текст для вывода StringBuilder sb = new StringBuilder(); ///Если заданы размерности параметра, формируем текст по формату if (Units.Length > 0) { sb.Append(DisplayFormat.Replace("<VALUE>", value.ToString(Format))); sb.Replace("<UNITS>", Units); } else sb.Append(value.ToString(Format)); Action d = () => { ///Собственно здесь происходит исключение this.Text = sb.ToString(); this.Enabled = (result == ModBusCommon.Error.OK); }; if (this.InvokeRequired) this.Invoke(d); else d(); } 

Periodically, when assigning to the Text property, a System.InvalidOperationException is thrown.

The collection was changed after creating an instance of the enumerator.

in System.Collections.Specialized.ListDictionary.NodeEnumerator.MoveNext ()

in System.Windows.Forms.Layout.DefaultLayout.ApplyCachedBounds (IArrangedElement container)

in System.Windows.Forms.Layout.DefaultLayout.xLayout (IArrangedElement container, Boolean measureOnly, Size & preferredSize)

in System.Windows.Forms.Layout.DefaultLayout.LayoutCore (IArrangedElement container, LayoutEventArgs args)

in System.Windows.Forms.Layout.LayoutEngine.Layout (Object container, LayoutEventArgs layoutEventArgs)

in System.Windows.Forms.Control.OnLayout (LayoutEventArgs levent)

in System.Windows.Forms.ScrollableControl.OnLayout (LayoutEventArgs levent)

in System.Windows.Forms.Control.PerformLayout (LayoutEventArgs args)

in System.Windows.Forms.Control.PerformLayout ()

in System.Windows.Forms.Control.ResumeLayout (Boolean performLayout)

in System.Windows.Forms.Layout.LayoutTransaction.Dispose ()

in System.Windows.Forms.Label.OnTextChanged (EventArgs e)

in System.Windows.Forms.Control.set_Text (String value)

in System.Windows.Forms.Label.set_Text (String value)

in WFControlsLib2.ModBusControls.LabelReg. <> c__DisplayClass1.b__0 (Object s, EventArgs e)

In D: \ doc \ C # \ WFControlsLib2 \ ModBusControls \ LabelReg.cs: line 304

in WFControlsLib2.ModBusControls.LabelReg.reg_OnResultRead (Reg sender, Error result, Object data)

in D: \ doc \ C # \ WFControlsLib2 \ ModBusControls \ LabelReg.cs: line 311

in System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage (IntPtr md, Object [] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object [] & outArgs)

in System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage (iMessage msg, iMessageSink replySink)

How to fix this problem? In theory, I simply set the text value of the Text property to the Label class.

Update ... Overloaded and locked Text method

 public override string Text { get { lock (mutex) { return base.Text; } } set { lock (mutex) { base.Text = value; } } } 

object type mutex, a member of the class, the problem remains.

  • Perhaps the error is not in the place where you are looking. What is Units ? Preferred sample code. - Stepan Kasyanenko
  • I cannot provide an example now, but Units as well as DisplayFormat are string properties of type string Units {get; set;} - Roman
  • If the problem is still relevant, try the following. Generate your text not using StringBuilder , but using just a String . Or, as advised below, create a variable var tmp = sb.ToString(); before creating Action d = ... And inside the anonymous function, use tmp and not sb . - Stepan Kasyanenko
  • Earlier in the comments I indicated that I tried to just write a constant in Text, the problem remains. Those. the problem is not what is being recorded, but where it is being recorded. - Roman
  • As far as I can see, an error occurs during Layot processing ( PerformLayout , ResumeLayout , etc.). That is, when adding / changing text in a label , the control element is rewritten. Since the error clearly indicates that the Collection was changed after creating an instance of the enumerator , it is possible that somewhere in another thread the controllers in this container are changed (added / deleted). - Stepan Kasyanenko

2 answers 2

Perhaps the problem is still the simultaneous access to the Text property of the label object from different streams.

As advised @Alexsandr Ter, put a lock on changing the Text property.

For example:

  Action d = () => { //Следующий код выполняется в однопоточном режиме. lock(lockObj) { this.Text = sb.ToString(); this.Enabled = (result == ModBusCommon.Error.OK); } } 

Important:

The lockObj property must be a static member of the class.

for example

 class LabelReg { private static Object lockObj = new Object(); ... } 
  • Read the comments, I have already tried to lock, this does not solve the problem. - Roman
  • Read the item IMPORTANT in my answer. You did not use lock correctly. Of course, if you used it as suggested by @Alexsandr Ter. - Stepan Kasyanenko
  • I did as suggested by @Alexsandr Ter and did through Mutex , which was a member of the class. The problem is that this way the security of writing to this.Text is ensured only through this reg_OnResultRead function. It does not provide access security by another thread that can access this.Text property directly. - Roman
  • In this case, if there is a possibility, it can allocate the assignment to the Text property in a separate method. And this separate method is thread-safe. And, of course, all changes to the Text do through this method. - Stepan Kasyanenko
  • I can do the assignments through the special method, but the system will still work with the Text property directly. Or do you propose to override the Text property itself? - Roman

Apparently your label in another thread is working. Use

  var tmp = sb.ToString(); object obj = new object(); lock(obj){ if (this.InvokeRequired) { this.Invoke(new ThreadStart( delegate { this.Text = tmp; })); } } 
  • These are just different ways to implement inter-thread interaction, this does not solve the problem. - Roman
  • Maybe your label is trying to change from multiple streams. - Alexsandr Ter
  • If you're talking about simultaneous access from different streams, then there would be another exception. > Invalid operation in multiple threads: attempting to access a control not from the thread in which it was created. To eliminate this, InvokeRequired is checked. I highlighted the exception description in the question. - Roman
  • Then option one calls sb.ToString () when the garbage collector has already destroyed it - Alexsandr Ter
  • Why on earth would he destroy him if he was used? The exception causes the Text property of the Label class. If you look in the debugger, then sb exists, the text value in sb is. - Roman