07-01-2009 02:28 PM - edited 07-01-2009 02:38 PM
If I write data from SQL to a scattergraph, it will work the first time. The second time it will throw a System.InvalidOperationException unless I do not have the tab that contains the chart open. If I don't select that tab, it will work flawlessly. I can run as many queries as I want when the chart isn't showing on the screen.. It must have soemthing to do with repainting the chart.
Also, I don't know if I'm approaching this the right way. I want to allow the user to run queries and then post the data to the xy chart. The only problem is that the x axis range depends on the query, so I have to set it after I run the query. That means I actually have to run the query twice. Once to read the data so I can grab the min and max for the range, and once again to post the data to the chart.
I should mention that I am using threads.
Here is the error:
System.InvalidOperationException was unhandled Message="Collection was modified; enumeration operation may not execute." Source="mscorlib" StackTrace: at System.Collections.Hashtable.HashtableEnumerator.MoveNext() at NationalInstruments.UI.Internal.InnerAxisElement.a(ComponentDrawArgsInternal A_0, RectangleF[] A_1) at NationalInstruments.UI.Internal.InnerAxisElement.DrawForeground(ComponentDrawArgsInternal args) at NationalInstruments.Restricted.ControlElement.a(ComponentDrawArgsInternal A_0, Rectangle A_1, Boolean A_2) at NationalInstruments.Restricted.ControlElement.DrawChildren(ComponentDrawArgsInternal args, Rectangle clipRectangle) at NationalInstruments.Restricted.ControlElement.a(ComponentDrawArgsInternal A_0, Rectangle A_1, Boolean A_2) at NationalInstruments.Restricted.ControlElement.DrawChildren(ComponentDrawArgsInternal args, Rectangle clipRectangle) at NationalInstruments.Restricted.ControlElement.a(ComponentDrawArgsInternal A_0, Rectangle A_1, Boolean A_2) at NationalInstruments.Restricted.ControlElement.a(ComponentDrawArgsInternal A_0, Rectangle A_1) at NationalInstruments.Restricted.ControlElement.Paint(PaintEventArgs e) at NationalInstruments.UI.WindowsForms.ControlBase.OnPaint(PaintEventArgs e) at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs) at System.Windows.Forms.Control.WmPaint(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(ApplicationContext context) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine) at DEER_DAQ_Data_Miner.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:
Here is the code:
Try
txtReport.AppendText(vbNewLine & sql)
ScatterPlot1.ClearData()
While (rdr.Read)
If Not firstcount Then
firstcount = True
min = rdr.GetValue(0)
End If
max = rdr.GetValue(0)
End While
WaveformGraph.XAxes(0).Range = New Range(min, max)
ScatterPlot1.XAxis.Range = New Range(min, max)
rdr.Close()
Dim secondrdr As SqlDataReader = cmd.ExecuteReader
While (secondrdr.Read)
ScatterPlot1.PlotXYAppend(secondrdr.GetValue(0), secondrdr.GetValue(1))
End While
secondrdr.Close()
Catch ex As Exception
txtReport.AppendText(vbNewLine & ex.Message)
End Try
07-06-2009 06:27 PM
07-06-2009 08:25 PM
As soon as I did it without a thread it worked well. I liked it much better when I could see the line being painted from left to right. How could I create the graph on startup and write to it after user events through the same thread? Just it just have to be done on the same thread like Dim XYThread as Thread. Can the thread's address be changed from one subroutine to another to handle this?
Thanks!
07-07-2009 02:27 PM
That is good news.
As can be seen in the NI Measurement Studio .NET Class Library help files, there is a section on thread safety:
Thread Safety
Only the following members are safe for multithreaded operations: BeginInvoke, EndInvoke, Invoke, InvokeRequired, and CreateGraphics.
You may be able to use these functions in order to update your graph from a seperate thread.
You can also search the web as this is a general problem in C. Some terms to look for are "cross thread function calls" "marshall a thread" "thread safety".
Regards