This question has been asked a lot, and I've read all the posts on Stackoverflow on it.
I wanted to confirm my conclusion though.
Where the source of information being populated is quite fast (ie it doesn't take much processing time to get the information itself), it seems to me that the processing that takes the time is actually feeding it into the DataGridView. However that has to be done on the UI thread as that's where the control is.
If that's the case there seems to be limited benefit to trying to do anything in the background, and that the corollary is that there's no effective way to populate a DataGridView without bunging up the UI thread. Is that right?
Surely there must somehow be a way to populate a DataGridView entirely asynchronously while the user can still interact with the UI?
Surely there must somehow be a way to populate a DataGridView entirely asynchronously while the user can still interact with the UI?
There are many ways it can be done.
Paging via Async/await Inlined with Regular Code
If whatever it is you are fetching the data from (whether it be a direct database connection; REST or WCF call) supports paging, then you could fetch pages of data via inline async/await and add rows for each item returned in the page.
e.g.
// somewhere in your UI code
async Task LoadAsync(List<Page> pages)
{
foreach (var page in pages)
{
var stuff = await service.GetMovieSalesPagedAsync (page);
foreach (var item in stuff)
{
_dataGrid.Rows.Add (/* convert item then add it here */);
}
}
}
This is faster than say requesting all the data in one go and then trying to add rows for each item. The latter would just block the UI.
The benefit of the above approach is that the code is inline and easier to read.
Dedicated Task with Progressive Filling During Application Idle
This technique is better for when there is a large amount of data to display and you want the best performance UI-wise. It's also useful if the source does not support paging.
Here you can spawn a Task whose job is to retrieve the data a page (or all at once) at a time, then add each page results to say a ConcurrentQueue<> for the benefit of the UI thread. If you have to retrieve all of it, then break the results into pages manually.
Meanwhile, in your Application.Idle handler try to pop an item off the queue and if one is found, add the new items as rows to the datagrid. Now depending on your app, you may choose to process all available pages or wait for the next application idle event. It might take a bit of fine tuning. Waiting for the next application idle allows your app to play nice with UI responsiveness.
This will cause the datagrid to be filled progressively rather than all at once.
A con of this approach is that the code is no longer inline. You have one block of code responsible for fetching and storing data; another for pumping it into the UI.
I am having issues on how to get around the following problem.
I have a class which which allows me to dynamically update and display a graph on a form. In order to update the values of the graph I have a method within the class of the form. I pass in the value to update the graph with to this method. Here is a high level example of what I am trying to do:
class GUICLass : Form {
//Code for drawing chart etc all here
public updategraphWithNewValue(double value){
// Code to update the graph
}
}
My other class is as follows:
class ValueProviderForGraph{
GUIClass graphForm = new GUIClass();
public calculateValuesAndPlot(){
for(int i = 0; i < 4000; i++){
graphForm.updategraphWithNewValue(i);
graphForm.update();
}
}
}
Now the issue I get from the above is that the form freezes while this operation is taking place. How could I go about getting around this, any help or advice would be much appreciated. I hope this high level example has enough information, if not please do let me know and I shall try and explain myself better.
Thanks.
Look into using BackgroundWorker. Its event-oriented interface should get you up and running quickly.
You can only update your form's controls from the thread that the control was originally created on.
If you are trying to update it from a different thread, you must marshal that call. There are numerous approaches on the web. My personal favorite (for WinForms) is the following:
https://stackoverflow.com/a/709846/141172
UPDATE
After re-reading your question at the urging of #StenPetrov, I suspect that you do not have a cross-thread issue after all, but that the UI thread is simply not processing messages while it updates the graph (this would cause the freezing during the operation).
If the UI thread is busy updating the graph, you will get that behavior. However, it looks like you are causing the graph to do an unnecessary update 3999 times. Try moving the line
graphForm.update();
outside of your for loop.
While I don't know exactly how your graph control works, I suspect the call to update() causes the entire graph to be re-rendered. You should only do that after all new data points have been added.
Do you need to update the UI often or not?
If you don't have to update the UI often, such as loading a large graph for viewing, then BackgroundWorker will do.
If you need the UI updated frequently you have to (a) make your graph calculations independent of UI, (b) run the graph calculations in a separate thread and (c) after the update is calculated use Form.Invoke(...) to update the UI
History of the problem
This is continuation of my previous question
How to start a thread to keep GUI refreshed?
but since Jon shed new light on the problem, I would have to completely rewrite original question, which would make that topic unreadable. So, new, very specific question.
The problem
Two pieces:
CPU hungry heavy-weight processing as a library (back-end)
WPF GUI with databinding which serves as monitor for the processing (front-end)
Current situation -- library sends so many notifications about data changes that despite it works within its own thread it completely jams WPF data binding mechanism, and in result not only monitoring the data does not work (it is not refreshed) but entire GUI is frozen while processing the data.
The aim -- well-designed, polished way to keep GUI up to date -- I am not saying it should display the data immediately (it can skip some changes even), but it cannot freeze while doing computation.
Example
This is simplified example, but it shows the problem.
XAML part:
<StackPanel Orientation="Vertical">
<Button Click="Button_Click">Start</Button>
<TextBlock Text="{Binding Path=Counter}"/>
</StackPanel>
C# part (please NOTE this is one piece code, but there are two sections of it):
public partial class MainWindow : Window,INotifyPropertyChanged
{
// GUI part
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var thread = new Thread(doProcessing);
thread.IsBackground = true;
thread.Start();
}
// this is non-GUI part -- do not mess with GUI here
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property_name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property_name));
}
long counter;
public long Counter
{
get { return counter; }
set
{
if (counter != value)
{
counter = value;
OnPropertyChanged("Counter");
}
}
}
void doProcessing()
{
var tmp = 10000.0;
for (Counter = 0; Counter < 10000000; ++Counter)
{
if (Counter % 2 == 0)
tmp = Math.Sqrt(tmp);
else
tmp = Math.Pow(tmp, 2.0);
}
}
}
Known workarounds
(Please do not repost them as answers)
I sorted the list according how much I like the workaround, i.e. how much work it requires, limitations of it, etc.
this is mine, it is ugly, but simplicity of it kills -- before sending notification freeze a thread -- Thread.Sleep(1) -- to let the potential receiver "breathe" -- it works, it is minimalistic, it is ugly though, and it ALWAYS slows down computation even if no GUI is there
based on Jon idea -- give up with data binding COMPLETELY (one widget with databinding is enough for jamming), and instead check from time to time data and update the GUI manually -- well, I didn't learn WPF just to give up with it now ;-)
Thomas idea -- insert proxy between library and frontend which would receiver all notifications from the library, and pass some of them to WPF, like for example every second -- the downside is you have to duplicate all objects that send notifications
based on Jon idea - pass GUI dispatcher to library and use it for sending notifications -- why it is ugly? because it could be no GUI at all
My current "solution" is adding Sleep in the main loop. The slowdown is negligible, but it is enough for WPF to be refreshed (so it is even better than sleeping before each notification).
I am all ears for real solutions, not some tricks.
Remarks
Remark on giving up with databinding -- for me the design of it is broken, in WPF you have single channel of communication, you cannot bind directly to the source of the change. The databinding filters the source based on name (string!). This requires some computation even if you use some clever structure to keep all the strings.
Edit: Remark on abstractions -- call me old timer, but I started learning computer convinced, that computers should help humans. Repetitive tasks are domain of computers, not humans. No matter how you call it -- MVVM, abstractions, interface, single inheritance, if you write the same code, over and over, and you don't have way to automatize the things you do, you use broken tool. So for example lambdas are great (less work for me) but single inheritance is not (more work for me), data binding (as an idea) is great (less work) but the need of proxy layer for EVERY library I bind to is broken idea because it requires a lot of work.
In my WPF applications I don't send the property change directly from the model to the GUI. It always goes via a proxy (ViewModel).
The property change events are put in a queue which is read from the GUI thread on a timer.
Don't understand how that can be so much more work. You just need another listener for your model's propertychange event.
Create a ViewModel class with a "Model" property which is your current datacontext. Change the databindings to "Model.Property" and add some code to hook up the events.
It looks something like this:
public MyModel Model { get; private set; }
public MyViewModel() {
Model = new MyModel();
Model.PropertyChanged += (s,e) => SomethingChangedInModel(e.PropertyName);
}
private HashSet<string> _propertyChanges = new HashSet<string>();
public void SomethingChangedInModel(string propertyName) {
lock (_propertyChanges) {
if (_propertyChanges.Count == 0)
_timer.Start();
_propertyChanges.Add(propertyName ?? "");
}
}
// this is connected to the DispatherTimer
private void TimerCallback(object sender, EventArgs e) {
List<string> changes = null;
lock (_propertyChanges) {
_Timer.Stop(); // doing this in callback is safe and disables timer
if (!_propertyChanges.Contain(""))
changes = new List<string>(_propertyChanges);
_propertyChanges.Clear();
}
if (changes == null)
OnPropertyChange(null);
else
foreach (string property in changes)
OnPropertyChanged(property);
}
This isn't really a WPF issue per se. When you have a long-running operation that updates a set of data rapidly, keeping the UI updated - any UI, whether it's WPF or WinForms or just VT100 emulation - is going to present the same problem. UI updates are comparatively slow and complex, and integrating them with a fast-changing complex process without hurting that process requires a clean separation between the two.
That clean separation is even more important in WPF because the UI and the long-running operation need to run on separate threads so that the UI doesn't freeze while the operation is running.
How do you achieve that clean separation? By implementing them independently, providing a mechanism for periodically updating the UI from within the long-running process, and then testing everything to figure out how frequently that mechanism should be invoked.
In WPF, you'll have three components: 1) a view, which is the physical model of your UI, 2) a view model, which is the logical model of the data that is displayed in the UI, and that pushes changes in the data out to the UI through change notification, and 3) your long-running process.
The long-running process can be almost completely unaware of the UI, so long as it does two things. It needs to expose public properties and/or methods so that the view model can examine its state, and it needs to raise an event whenever the UI should be updated.
The view model listens to that event. When the event is raised, it copies state information from the process to its data model, and its built-in change notification pushes those out to the UI.
Multithreading complicates this, but only a bit. The process needs to run on a different thread than the UI, and when its progress-reporting event is handled, its data will be copied across threads.
Once you've built these three pieces, the multithreading is very straightforward to accomplish using WPF's BackgroundWorker. You create the object that's going to run the process, wire its progress-reporting event up with the BackgroundWorker's ReportProgress event, and marshal data from the object's properties to the view model in that event handler. Then fire off the object's long-running method in the BackgroundWorker's DoWork event handler and you're good to go.
A user interface that changes faster than the human eye can observe (~25 updates/sec) is not a usable user interface. A typical user will observe the spectacle for at most a minute before giving up completely. You are well past this if you made the UI thread freeze.
You have to design for a human, not a machine.
Since there are too many notifications for the UI to handle, why not just throttle the notifications a bit? This seems to work fine:
if (value % 500 == 0)
OnPropertyChanged("Counter");
You could also limit the frequency of the notifications, using a timer:
public SO4522583()
{
InitializeComponent();
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(50);
_timer.Tick += new EventHandler(_timer_Tick);
_timer.Start();
DataContext = this;
}
private bool _notified = false;
private DispatcherTimer _timer;
void _timer_Tick(object sender, EventArgs e)
{
_notified = false;
}
...
long counter;
public long Counter
{
get { return counter; }
set
{
if (counter != value)
{
counter = value;
if (!_notified)
{
_notified = true;
OnPropertyChanged("Counter");
}
}
}
}
EDIT: if you cannot afford to skip notifications because they're used by other parts of your code, here's a solution that doesn't require big changes in your code:
create a new property UICounter, which throttles the notifications as shown above
in the Counter setter, update UICounter
in your UI, bind to UICounter rather than Counter
A layer between UI and the library is necessary. This will ensure that you will be able to do interaction testing and also allow you to swap out the library with another implementation in future without much change. This isn't a duplication, but a way of providing an interface for UI layer to communicate. This layer will accept objects from library, convert them to specific data transfer objects and pass them onto another layer which will have the responsibility to throttle the updates and convert them to your specific VM objects.
My opinion is that VMs should be as dumb as possible and their only responsibility should be to provide data to views.
Your qestion sounds similar to slow-down-refresh-rate-of-bound-datagrid.
At least the answers are similar
Have a shadow copy of your data bound to the gui element instead of binding the original data.
Add an eventhandler that update the shadow-copy with a certain delay from the original data.
You need to disconnect the source of the notifications from the target for the notifications. The way you have it set up now, every time the value changes, you go through an entire refresh cycle (which I believe is blocking your processing function from continuing as well). This is not what you want.
Provide an Output stream to your processing function which it would use to write its notifications.
On the monitoring side, attach an input stream to that outputstream and use it as the data source for your UI component. This way there isn't any notification event handling going on at all - the processing is running flat out as fast as it can, outputting monitor data to the output stream you provide. Your monitor UI is simply rendering whatever it receives in the input stream.
You will need a thread to continuously read from the input stream. If no data is available, then it should block. If it reads some data, it should dump it into the UI.
Regards,
Rodney
I'm writing a class for logging events. My LogClass is implemented as a singleton, and any class in the system can write a log entry. The entries are stored in a List and when a buffer is filled they get dumped to the disk.
I'm using a DataGridView to display the contents of the LogClass during execution, therefore I used the BindingList so that the Viewer would update automatically.
I'm wondering how thread safe my class is.
I'm using "lock" everytime I add a new entry to the list, and when I'm iterating through the list to dump it to the disk.
Besides the DataGridView, the class is basically Write-Only because there isn't an option to read from the log, only to add entrires to the log.
The dump is executed internally, and that is the only time there is a explicit read command on the BindingList.
So my real concern is what goes on with the DataGridView and the BindingList ?
The BindingList throws an event everytime the list changes.
This doesnt seem like a concern when adding new entries, because the event is thrown when the adding finished.
My code for Dump() is:
lock (lockObj) {
foreach (LogEntry le in List) {
writeToDisk(le)
removeFromList(le)
}
}
Even though I'm locking the list during the whole iteration, an event is thrown to the Viewer that the list changed (because of the removal) and therefore being read by the DataGridView. I don't really want anything reading/writing to the list while I'm altering it.
Any ideas?
It's not really a concern because, once bound, you can only change the list from the Form.Invoke method (inherited from Control.Invoke). If you try to change the list from another thread, the .NET runtime will bark at your w/ an exception saying something to the effect of "can't change this list from current thread".
This has some code you can grab.
Regards,
=Alan
I thought that BindingList didn't implement change notification. In this scenario I don't think this is thread safe.
The solution might be to use custom collection that implements IBindingList and change the list accessor to acquire lock before returning any element.
I have a custom implementation of IBindingList with change notification so if you want I can share this.(I'll probably write an article on code project describing the implementation anyway..)
OK, please disregard what has gone before. I'm not getting the errors anymore, so it seems my problem is with getting a Chart to update when I change the values to which the Chart is data bound.
//Disregard below here
Hi all. I have a WinForms application that has a panel, panel1. A background thread creates some other controls that then get added to panel1 like so
panel1.Controls.AddRange(myArrayOfControls);
This works great and I can see my controls get added. But, when new data comes in on another thread, I update values in the controls' parent objects and then need to Refresh() to get the display to update with the new values. Calling Refresh() in either context, the thread where the data comes in or the objects that receive the updated data causes an InvalidOperation exception because Invoke is required. I've tried using Invoke in my model objects and also the thread where the data is incoming and can't seem to shake the error.
If anyone has some guidance I'd greatly appreciate it.
UPDATE: Here's a little more info. I didn't think it would require it, but I was wrong. :)
I have an object class MyObject. This MyObject class gets created in a thread called topologyThread. Data comes in on dataThread. Instances of MyObject have a Panel instance variable and the Panel has child Controls including two Charts from the System.Windows.Forms.DataVisualization.Charting namespace. So, as data comes in on dataThread, I update the respective data values in the MyObject objects and then need to refresh the Charts to show the updated data.
I do know the data is processing fine. In my MyObject class, I'm logging the new values to Console in the setter for the property and see the new values show up.
You must do both operations (refresh and updating of control's parent object) from the main UI thread. If you are modifying a control from a background thread and not getting an exception that is bad luck because it is definitely an error.
The best way to do this is to use
theControl.Invoke(new MethodInvoker(MyUpdateMethod));
If you have a sample of how the update is done, we can give a better sample on how to properly call it from the background thread.
JaredPar is a pretty good answer. I would like to add to it a bit as to the reason your code sort of works.
With windows forms you can talk to the UI thread from other threads. This is really bad practice in all cases.
The catch is that when you do it, it is hard to catch because sometimes the UI will work as if nothing is wrong. item will get added or changed and the UI will reflect the changes. However other times running the same exact code, it will not work.
That is the catch with touching the UI from any thread other then the UI thread. The out come is inconsistent and that is why is very bad practice.
God I wish I could comment. :)
JaredPar's answer is good. It can cause problems in some instances (notably when the method is invoked before the form is finished being constructed). Here's a somewhat more robust implementation (using extension methods)
public static class ControlInvokeExtensions
{
public static void InvokeOnHostThread(Control host, MethodInvoker method)
{
if (IsHandleCreated)
Invoke(new EventHandler(delegate { method(); }));
else
method();
}
}
now you can call it this way
panel1.InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls));
or if you're in the form:
InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls));