I'm Using a Task to start a while loop to run and constantly collect data from from a USB device. The data can come in very fast, multiple messages per millisecond. I want to display the data in real time using a ListView.
The goal is to have two options to display the data. The first way is to display the newest message at the top of the list view. I've tried calling a dispatcher and inserting the data at the beginning of an ObservableCollection. This works fine with a message every 20 ms or so.
Often the data coming in is the same message again and again with a consistent interval. The second way is to have a row in the listview for each unique message. As a new message comes in it either takes the place of the previous similar message or it is inserted into a new position. I accomplished this by inheriting from ObservableCollection and implementing a binarysearch function to get an index and then replace or insert the newest message. This also worked fine at about the same rate.
The problem is Updating the UI can't keep up with reading the data from the USB device when the traffic coming from the USB device is heavy. It worked fine with low volumes of data but I'm stuck trying to make this thing more efficient.
I've tried creating my own methods in my ExtendedObservableCollection. I created some AddRange methods for each scenario and calling OnCollectionChange
after all the updates. The performance this way seems to be even worse than it was before which is very confusing to me. This seems like the way to go. I think the issue has something to do with my while loop which is collecting the data and the AddRange method not getting along.
I also tried calling BindingOperations.EnableCollectionSynchronization(MessageList, balanceLock);
with out using the dispatcher and it didn't seem to help much. I put my AddRange methods inside a lock statement.
I also tried running the Batchupdate method in its own while loop running parallel the my loop collecting data it didn't work at all.
This is my loop for reading the messages from the USB device
int interval = 40;
private void BeginReading()
{
do
{
waitHandle.WaitOne(TimeSpan.FromMilliseconds(.5));
if (ReadOk)
{
MessageBuffer.Add(message);
}
if (Stopwatch.ElapsedMilliseconds > interval)
{
BatchUpdate();
MessageBuffer = new List<Message>();
interval += 40;
}
} while (ReceiveReady);
}
This is one of my AddRange Methods in my extended ObservableCollection
public void AddRangeScroll(List<Message> MessageList)
{
if (MessageList == null) throw new ArgumentNullException("List");
foreach (Message message in MessageList)
{
Items.Insert(0, message);
}
OnCollectionChanged(newNotifyCollectionChangedEventArgs
(NotifyCollectionChangedAction.Reset));
}
I'm hoping I'll be able to read the data from the USB device and update the ListView in something that resembles real time.
The messages I'm reading are CAN messages and I'm using the PEAK PCANBasic API to connect to one of their gridconnect USB to CAN devices.