How to Cache Real-time Data? - vb.net

I'm working on a windows forms application (.NET 4.0).
My form contains a 'Fast Line' chart using the Microsoft chart control included in VS2010.
The chart gets filled with about 20,000 datapoints.
My application then starts receiving market data from a server via DDE (Dynamic Data Exchange) in real-time and adds it the chart.
Note: I have no control over the server and so I have to deal with DDE only even though it's an outdated technology. VS doesn't support DDE anymore and so I use the Ndde library which works like a charm.
First we connect to the server, create an advise loop, and then subscribe to the OnAdvise event to receive notifications of new data:
Dim client As DdeClient = New DdeClient("ServerApplication", "Bid")
Private Sub StartDDE()
client.Connect()
client.StartAdvise("EURUSD", 1, True, 60000)
AddHandler client.Advise, AddressOf OnAdvise
End Sub
Now we can put the commands to update the chart inside the event:
Private Sub OnAdvise(ByVal sender As Object, ByVal args As DdeAdviseEventArgs)
Dim myPrice As Double = args.Text
Chart1.Series("Bid").Points.AddY(myPrice)
End Sub
You get the idea.
THE PROBLEM:
This works fine for a few seconds until the chart crashes throwing the exception:
"Collection was modified; enumeration operation may not execute."
I spent a lot of time researching what may be the cause of this in my particular case, and I've come to the conclusion that it's because the chart is receiving data quicker than it can handle. It's already loaded with a lot of data and needs a certain time (less than a second) to add the received data in a new DataPoint and invalidate (refresh) itself. Whereas the server often sends data values very quickly (for example 5ms in between). So I've tried the following:
System.Threading.Thread.Sleep(800)
Chart1.Series("Bid").Points.AddY(myPrice)
thus pausing the application to give time to the chart to finish its work before adding a new point, and guess what? The application now works for minutes before throwing the exception. (altering the value in Sleep() doesn't help any further however)
The only help I could find online is an old post of someone mentioning that you should put incoming data on a cache queue, with one new data value released from the cash at a time (every time the chart finishes working).
My question is how would you do this?
Other suggestions are welcome!

This is most likely an issue caused by attempting to modify a UI element from a thread other than the UI thread.
The way you have it coded now the DdeClient.Advise event handler is being executed on a worker thread managed by the library. See, DDE sucks and because it sucks it has these requirements that it has to run on a thread with a message pump.1 To make the library compatible with other types of applications besides windows forms I coded it in such a manner that it will create a dedicated thread with a message loop and marshal all of the operations onto that thread by default.
But, you can override this behavior by specifying an ISynchronizeInvoke instance manually in the DdeClient constructor. The library will then use whatever thread is hosting the ISynchronizeInvoke instance for all of its DDE operations. All Form and Control instances implement ISynchronizeInvoke so it is easy enough to tell the library to use the main UI thread.
Dim client As DdeClient = New DdeClient("ServerApplication", "Bid", yourForm)
If you tell the library to use your Form instance then the Advise event handlers will be executed on the same thread hosting that Form; the UI thread.
By the way, I realize that you have no control over the server, but I would at least begin talking with the vendor of the software to use more modern (not 20 years old) mechanisms for doing interprocess communications.
1It also has the unfortunate requirement of thread affinity which made dealing with the garbage collector a real pain.

Get real ;) DDE is slow, graphics is slow. Do not do them in the same thread.
Try that:
Create a second thread that handles DDE, queues the items.
The chart thread then pulls the updates and draws them.
Now, here comes the point:
ONLY the ui thread is allowed to modify the chart control. Yes, sucks. No, not negotiable. - old UI rule since the dawn of time.
Threads needs locking ;)

Related

Update GUI from another class in vb.net

I'm building a server and a client for a chat that runs on Tcp and Sockets, I want the client to handle more than one connection (to servers) so I made a class called "Client" to manage the async connection, so that I can run more instances at the same time like:
Dim ConnectionToServer1 as new Client
Dim ConnectionToServer2 as new Client
Since it's async when the the "connection" receives a message it generates an event (AsyncCallback) where I can convert the received bytes into a string.
The problem is: I've tried to set this string to a RichTextBox on my Form from inside the Client class, but nothing happens, I've tried to create a delegate in the form code but nothing works, the only way I was able to put the received message in the RichTextBox is by creating a public variable called LastMessage in the Client class where the last message is stored (every time it receives a message, the sub overrides the string), and then running a thread created by the Form which keeps checking for data (since the thread has been created by the form it has access to the controls, including the RichTextBox, right?)
Although I find this a bit clunky, is there any other way (through delegates maybe?) I can do it?
Here's some code:
Client class: http://pastebin.com/GF9um8Ss
Form code: http://pastebin.com/xW7mDj8j
Sounds like you started down all the right paths.
Now, on threaded applications one of the challenges that you will face is you can have tons of worker threads, but only the main, UI thread can actually make any updates to the UI. So keeping that in mind, if you have async code that needs to update the ui you will need to use what is effectively a delegate.
You can do this using tasks these days a lot easier, so read up on the Task Parallel Library, but essentially you need a delegate/task that is marshaled to run on the ui thread to handle the UI updates.
Set this global property as false
Control.CheckForIllegalCrossThreadCalls = false
this will let you edit any control of your form from any thread

Suitable pattern for updating a progress bar from multiple threads (using TPL?)

I've been busy updating my brain with the TPL because I intend on using it for my new application (which uses .Net Framework 4.0). However I have some doubts that someone might clarify for me. Previously, I had a progress form which I would launch from the main (GUI) thread after I started the thread which needed to display its' progress. It looked something like this:
sortThread = New Thread(AddressOf _Sorter.Sort())
_ProgressForm = New FrmProgress()
_Sorter.ProgressForm = _ProgressForm
sortThread.Start()
progressForm.ShowDialog()
Basically it would initialize the thread, initialize a FrmProgress form object and assign it to the Sorter object which would then update the progress form (which contained a progress bar and some labels) from its Sort() sub on the separate thread. Updating these control properties was achieved by checking the InvokeRequired property of the FrmProgress form and if needed it would then use the Invoke() method of the control that was to be updated... ex:
Public Sub IncrementProgressBar(x As Integer)
If Me.InvokeRequired Then
pb_MainProgressBar.Invoke(Sub() IncrementProgressBar(x))
Else
pb_MainProgressBar.Increment(x)
End If
End Sub
Now I am interested in using TPL to launch separate worker threads (multiple) that may want to update the progress bar. Should I use the same pattern or should I consider accessing a public TaskScheduler.FromCurrentSynchronizationContext context that was obtained in the main GUI thread? In both cases I suppose I should provide some kind of locking mechanism on the form (SyncLock?)
Invoke should be sufficient, as you are doing. If two different threads try to invoke in parallel the first one will execute first, then the second when the UI thread becomes free. The UI thread cannot service two invokes simultaneously - they are naturally handled in FIFO sequence so there is no issue with thread safety. Any number of threads can invoke on the main thread without worrying about each other or using any additional locking mechanism.
Note, however, that any thread calling Invoke will block until the main thread can service the call. If you, for example, had many threads invoking heavy code at the same time then your various threads would block on the invoke calls until they got their kick at the can, so to speak. If you use BeginInvoke then the calling thread will simply continue executing and the invoked method will be placed in the UI thread's queue (which it will service as soon as it can).

What has happened to the thread of execution in this VB.net/COM dll?

According to the answers to another question, the VB user interface cannot be updated if the thread that created it is busy: hence why big computational jobs usually have to go in a background task.
Here's what's mystifying then. I have the following code. It's called over in-process COM, like this
client calls showform()
client does loads of work, freezing up its own UI in the process
client finishes work, returns to updating its own UI
At step 2, the VB form is there but frozen - you can't interact with it. At step 3, the VB form becomes usable. But why is this? Surely the thread of execution has returned to the client? If the client is somehow handling events for the form, by what magic did it know what events to handle and where to send them?
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
Public Sub New()
MyBase.New()
End Sub
Private f1 As Form1
Public Sub showform()
f1 = New Form1()
f1.Show()
End Sub
End Class
The magic you speak of is the basis of Windows programming. My answer to your previous question explains why and how you can fix this. When making a COM call the client application just imports your procedure into their application. Whether they create a form by typing the code themselves or whether they create a form using code you have typed it doesn't change the nature of the object/owner relationship. A COM call to your showForm will still make f1 belong to the thread which made the call (client UI thread). The window handle for that window will still be the responsibility of the UI thread that created it (the client).
Creating a form only makes a mailbox (window handle). A UI thread is a mailman (message pumping loop). You aren't providing the client with a new mailman, just a new object with a mailbox. When the client program creates the window by making the COM call to your procedure it (the client UI thread) takes responsibility for delivering messages to the new form's mailbox (registers its window handle with the main UI thread). Their mailman still needs to send you messages to make your visual objects work. If he is busy trying to calculate pi to a trillion decimal places then your object freezes like everything else on his mail route.
check the form.load event. the form loads and runs code... that is where it freezes.

Implementing auto-save in WPF / MVVM / NHibernate

My client likes programs like Microsoft OneNote where changes are saved automatically, and he can choose to discard when he explicitly wants to do so. I will have to implement some undo functionality, but I'll figure that out some other time.
With NHibernate, I suppose I can call ISession.Update on every single property / binding change, but I can see real pain with this approach down the road. I am not a fan of timers, but maybe a 5 second timer that starts on property / binding change and at timer end use BackgroundWorker thread to save to db.
What do you think?
A ISession.Update on every property-change isn't a good idea normally. The property-change-events are fired quite often. It could slow down your application when you do ISession.Update on every change. This will probably lead to a bad user experience.
In our Application has the same behavior. We store the changes when a View is closed (an some other related event). For example when the user closes a tab, the data which was displayed in that tab is closed.
An additional timer is probably a good idea to prevent data loss when the application crashes / unexpected happens.

Process All Windows Messages Generated By A Compact Framework Application

Hoepfully someone can shed some light on a problem - I am trying to listen to\intercept all windows messages generated by an application and dispose of certain types, for example Notify or Gesture messages.
I have been reading articals on how to do this using the Microsoft.WindowsCE.Forms.MessageWindow and creating a class which inherits this, overrides the WndProc method but I have been unalbe to get this start listening\watching the message queue automatically when the application starts.
I know it is possible to do this with the OpenNetCF framework and the Application2 namespace however I would prefer not to use 3rd party software at the moment - no offence to the OpenNetCF guys.
Hopefully this makes sense. Also, i am using C#2.0 and Windows Mobile 6.5.
Thanks for your help,
Morris
The solution, then, is pretty simple - all you have to do is spend your time duplicating what the Smart Device Framework code is doing.
You need to create your own message pump via P/Invokes to GetMessage, TranslateMessage and DispatchMessage (it will look just like it does in C). Use this pump instead of calling Application.Run (so there can be no calls to Application.Run in your application).
Inside that new message pump insert your filtering logic.