I press a button (located on the main form , the MDI Parent) which triggers a BackgroundWorker's RunWorkerAsync method (located on the same MDI Parent form). In this method I set the DataSource of my DataGridView which is located inside one child window owned by my main Mdi Window. Here's the code for the RunWorkerAsync:
Action d = () => {
((DataGridView) data_viewer.gridviewer).SuspendLayout();
((DataGridView) data_viewer.gridviewer).DataSource = datatable_copied;
((DataGridView) data_viewer.gridviewer).ResumeLayout();
};
base.Invoke( d );
The above code populates the grid OK. All data is delivered into the grid. The problem is that I will work with very big tables and while the data is loaded the whole app hangs, including the Mdi Parent window. I wouldn't mind having the DGV hang but for the Main MDI parent and the child window containing the DGV to hang while this whole thing loads is too much. How can I solve this? I want to be able to move the child window containing the DGV without a problem while it loads (or maybe draws) the whole datatable. I thought using a background worker would solve the issue but apparently it doesn't.
There is no getting around rendering a huge table on a WinForm.
Whether it is async or not, the UI still has to render the entire grid. Pushing it to the background thread just makes the UI more responsive while it is being computed and rendered.
Another approach is to page the data meaningfully, so that you:
Reduce the network traffic
Reduce memory of the WinForm
Speed up the rendering time
Is a user going to need 1,000's or 100,000 rows of data in one hit? Humans can't compute information on that scale - hence reporting aggregates the values.
Have a look at this StackOverflow post relating to paging a DataGridView and see if that helps.
Related
My Application processes large data Entries and display each group of entries in Tree List View.
The Main Form has other Controls such as Text Box "Used as Filter for Entries" and Graph "Displays Entries Data"
Every thing work Great , The Problem is while Processing Data entries and Displaying on TreeListView if i places the Mouse on textbox or graph , it keeps flickering and blinking ! , i can write data successfully to textbox but it is always flickering.
Take into consideration that The function of handling that large data entries and display on TreeListView is in separate thread.
so what is the problem here ? and how this separate thread affects rest of other controls in my mainform ?
One solution: Make everything Visible = false until your processing finish up, then Visible = true. You can also display a message "Please wait" while the items are hidden.
Another solution: avoid on-ui-thread long operations. Avoid fast add/delete into listview or treeview. It is better to clear everything then add everything. Yo can also hide your treeview, add items to it, then show it.
I've MDI winform with a top panel displaying picture and a navigation menu populated from a database on the left. I wanted to display a default child form immediately after the MDI form is displayed. I've used DevExpress WaitForm before displaying everything. However, the top panel remains blank until the child form is completely displayed. What can I do to display the child form after every component of the MDI is displayed. I tried threads but didn't figure out how to properly manage it. Your help is highly appreciated.
Thanks
The child form contains a xtraReport control that generates reports from the database
Sounds like your child form is blocking the main window with its fetching of database data and report generation.
Consider using another thread to fetch the data from the database. Once you have all the data, have the UI thread set the data source property (or equivalent) on the xtraReport control.
For threading you could use:
An explicit Thread (not recommended)
A Task though you may need to thread-marshal to your UI thread
An async method that you can await (recommended). This makes it much easier to do the work on another thread then automatically marshal the results to your UI thread where you can update xtraReport
I have an application which has a Mainform that has 2 panels using a splitter. The top panel is a form that has the binding navigator, dataset, bindingsource, tableadapters..
The bottom panel is a form as well. It's just a datagridview basically. I pass the bindingsource from the top form, into the bottom form when the Mainform loads.
The bottom form takes the bindingsource, and uses a relationship (between two tables) for it's own datasource member.
Viewing the data works great.
When I update data in the master, i capture it when the user is navigating off the record. I use bindingsource.EndEdit(), DataSet.HasChanges() to verify and then tableadapter.update to write the data before navigating to the next record.
That also works great.
Now, how do I capture and write data in the detail(bottom) form? all it has is the bindingsource passed in.
I have a partially working solution, where the top form actually uses a second tableadapter.update statement to write the the child table.. but it seems to take 2 record navigations for that to work. (at which point the data is actually updated correctly though)
Any high level better ways to work all this?
thanks
R
Looks like it was either a general issue with the event orders.. or maybe it's specific to the bindingnavigator or my setup.. but in order to get the bottom form's events firing BEFORE the record is changed in the top applet (when clicking directly from a modified grid row in the bottom, to the navigator), i had to explicitly move focus first in that top applet event. In my case, i trapped any click on the navigator and just ran this.focus(); that caused all the bottom form events to fire before continuing on. This then allowed my haschanges() check in the top form to happen after the bindingsource.endedit in the bottom form.
I've got a list of UserControl objects; when a menu option is clicked to go to another section of the application it does the following:
Set the currently displayed usercontrol to visible
Clear the main panel's Controls list
New up the requested control (if not already created in the list)
Add the new control to the main panels' Controls list
Dock the new control to fill
Set the new control to visible
I did this because, previously all of the areas of the application were not user controls and they were just collections of controls in a TabControl. The underlying code was monstrous (the code in frmMain was 13000+ lines).
It works well. All controls (what each tab page would have been before) manage their own behaviour, each control has a small code footprint. I can have a sexy menu. All good things.
However, obviously there's a problem. Before, the tabcontrol would load on startup, and all tabs would render (but weren't seen). One tab page in particular has a scheduling control on it and it takes a good 3-4 seconds to draw and adjust its layout. Now that controls are loaded and shown as they're needed, the first time you view this particular control, you see it load and adjust its size/formatting/etc. Which is hardly esthetically pleasing.
My question is, how can I load and render this control so that it'll render and figure out its layout, but without it actually showing the user?
I've tried simple things like:
ScheduleWindow scheduler = new ScheduleWindow() { Visible = false; }
mainPanel.Controls.Add(scheduler);
scheduler.Visible = true;
I've tried creating and loading the control on its own thread (with numerous difficulties) and it still didn't do anything...
Is there any way to achieve what I'm looking for?
Try using the SuspendLayout() and ResumeLayout() methods on the main form? When you call SuspendLayout(), you can do whatever you need to do with the controls you are adding, such as docking, resizing, etc. When you call ResumeLayout(), all changes will be applied at once, and should happen instantaneously.
Alternatively, some controls have a BeginUpdate() and EndUpdate() method, which suspend redraws for that control, allowing you to do heavy work (such as adding thousands of items to a ListView) without seeing the updates happen live. This also improves performance, as rather than redrawing every time the control is changed, you batch changes, then redraw once.
Try calling scheduler.Handle.ToString() and/or scheduler.Refresh().
I have a form with two panels(top, bottom), each panel contains grids. Basically, it's a Master-Detail form where selecting a row from the top grid would show details in the bottom grid.
Binding the data to the detail grid is taking some time. Since binding is done on UI thread, it blocks the thread and therefore the user cannot select another row from the master grid until the binding is done.
Please note that by binding I don't mean getting data from data source. It's the actual binding that's taking longer as it does a lot of data massaging. How can I keep the UI thread free while the detail grid is doing it's binding?
Thanks a million.
You can't. The update of the UI has to be performed on the UI thread.
You may be able to speed up the binding by using things such as BeginUpdate/EndUpdate which is available on some controls but as you don't specify what you are using I can't say if that's available.
You can use a background thread to perform your data retrieval, then use the UI thread to display it.
If I were you, it sounds like you are dealing with a LOT of data, and I would separate all the "massaging" you can into a separate thread process.
So maybe for example when a master record is created, you "manually" spin off the detail data in a background thread to another dataset and do the massaging, then just bind the resulting dataset to the grid. That way the only thing taking place on the UI thread is just the UI binding.
Ultimately if it's taking that long, you may be approaching a critical point in your application where you need to manually do what you need to do in code rather than using the out of the box data binding features in .NET.
Finally I found the solution. The solution doesn't include multithreading to start with. As I said that the delay was in binding the grid meaning the main thread was held, we couldn't do much. So the solution is to bring delays. When user selects the master row, a timer ticks off for a certain time. If another request is made before the time is expired, timer gets restarted. This is we ignore all calls that are made because user was clicking or selecting rows too fast. Once timer is expired, I take the selected row and display data. Simple and elegant solution.