A DispatcherTimer, which fires the Tick event in the UI thread, is what counts as a low-resolution or low-precision timer, because its interval effectively means "tick no earlier than x from the last tick". If the user interface thread is busy with anything (input processing, chart updating, etc.), then this delays timer events. Moreover, having a DispatcherTimer pool that discards the UI stream at very small intervals will also slow down the responsiveness of your application, because when the Tick event increases, the application cannot respond to input.
So, as you noted, in order to process the data often, you have to go into the background thread. But there are reservations. The fact that you are not currently observing corruption or other errors may just be accidental. If the list changes in the background thread while the foreground thread tries to read it, you will end up crashing (if you're lucky) or see corrupted data.
In your example, you have a comment that says: "there is no need to update the chart, it is automatically updated." This makes me wonder how the chart knows that you have changed the datapoints collection? List<T> does not change events when it is changed. If you used an ObservableCollection<T> , I would indicate that every time you delete / add a point, you potentially update the chart, which can slow down.
But if you are actually using List<T> , then there must be something else (perhaps another timer?) That updates the chart. Perhaps the chart control itself has a built-in automatic update mechanism?
In any case, the problem is a bit complicated but not entirely new . There are ways in which you could maintain a collection in a background thread and communicate with it from a user interface thread. But the faster the user interface is updated, the more likely you are to expect the background thread to release the lock.
One way to minimize this is to use LinkedList<T> instead of List<T> . Adding LinkedList to the end is O (1), so removing the item. A List<T> needs to move everything down by one when you delete an item from the beginning. Using LinkedList, you can block it in the background thread (s), and you minimize the time that you hold the lock. In the user interface thread, you will also need to get the same lock and either copy the list to an array or update the schedule until the lock is saved.
Another possible solution would be to buffer the “chunks” of points in the background thread and send a packet of them to the user interface stream using Dispatcher.BeginInvoke, where you could safely update the collection.