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.
Related
I have 5 different tables that are bound on a Windows Form and using C#. One of the tables is a DataGridView. When I load the form with the following code, the object that I want to have focus is automatic.
this.termsTableAdapter.Fill(this.terms_DataSet.Terms);
this.customerTableAdapter.Fill(this.customer_Info_DataSet.Customer);
this.customer_ShipTableAdapter.Fill(this.customer_Info_DataSet.Customer_Ship);
this.customer_MailTableAdapter.Fill(this.customer_Info_DataSet.Customer_Mail);
when I add the line to bind the DataGridView, I can't set focus to the control that I would like to set to even with the .Focus() as you see below
this.customer_Ship_ContactsTableAdapter.Fill(this.customer_Info_DataSet.Customer_Ship_Contacts);
customerComboBox.Focus();
any ideas why the datagridview holds the focus rather than the control that I would like to set?
I can click in the other controls to change the focus but I would like it set at form_Load.
Focus will only work when the form is visible, and in the load event, it isn't visible yet.
Try using the Select() method instead:
customerComboBox.Select();
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.
I have a picture box. This picturebox is used for map.
Map has elemenst on it. For example, a display.
I created "display" from windows user control. This user control has "a panel, 3 pictureboxes on the panel".
Any user creates "displays" on the screen and save it as a control of a picturebox (map). When any user save the data, it is saved to the database.
In every second, I look at the picturebox (map), control the data on it and also database. If "display" changed its status(like shows go or stop, kind of traffic signs), then I found the changed ones and refresh it.
Now is the question: If I remove the display(user control) than add it again to map's (picturebox) controls, it works well. Updated "display" is seen on the map. However, any user can see the process because the display is disapeared for miliseconds and come back like flickering.
How can I refresh this user control without remove and add again process, Is there a method to refresh it some way?
To suppress any flickering, you can cheat by telling windows to suspend the parent control painting before your flicker generating operation, and resume it afterwards. Check this SO question out.
I do it quite often on my custom controls and it works great. You can even add the "SuspendDrawing" and "ResumeDrawing" static methods from the first answer as extension methods for Control class.
I have a problem with controls nested in a TabControl. I have a TabControl with n TabPages, with a DataGridView on each TabPage. Each DataGridView has a CheckBoxC column. I populate all datagridviews with different datasources (so each has different types of data). This is working ok!
I have added a ComboBox column so I can select all the rows on all DataGridViews. I do this programmatically (on a button click), and the counting of the selection is ok, except that the ticks are not added to checkBox cell of DataGridViews except on TabPage #1 (the one that I can see on startup).
If I click all the tabPages before I go and select all the rows in DataGridViews, the code works fine, and the ticks are added to all the rows (like I wanted).
But why this does not work without clicking all the tabPages? Is there any bug or something of TabControl?
My workaround was to add this in the load event of the form.
this.tabcontrol1.BindingContext = this.BindingContext;
I know this answer is correct for WPF, not positive about WinForms though. With WPF at least, it's a visually based interface, so the program does not load any of the objects/controls/etc on other tabs until they are clicked on. So it wouldn't be a bug, it's a part of the design.
I had a similar problem with trying to clear all textboxes on multiple tabs with a single button. I never did get it working, but I know there should be a way by using a combination of VisualTreeHelper and a foreach statement.
Again, this is based off of WPF and not WinForms, but hopefully it can point you in the right direction as to how to solve it.
I have a windows form application that has two main panels: The one on the left is a narrow strip which has a series of radio buttons. The panel on the right houses a Tabcontrol, which has multiple Tabpages added to it which the user can select among along the top. Each of these tabpages themselves has about 7 DataGridViews added to it. Each DataGridView has about 5-6 columns of text, with a variable number of rows (10-500). The data added to it was done directly to the DGV itself, ie using the DGV.Rows.Add() method, passing an object array, not via a datasource.
When a user selects a different tab page, the datagridview that gets shown is dependent on the radiobutton that is selected on the left. I accomplish this by handling the SelectedIndexChange event of the tabcontrol and each of the radiobutton's CheckedChange event.
Within the SelectedIndexChange event of the tabcontrol, I programmatically checked the currently selected radioButton. Then within the radiobutton's CheckedChange event, I iterate through all of the DataGridViews on the TabControl's selectedTab and hide all those that don't match the one corresponding to the selected radiobutton.
My issue is everytime the user starts changing among a lot of tabs, or tries to view a DGV that has many rows, the program would throw the following error:
System.ComponentModel.Win32Exxception: Error creating window handle.
Does anyone know what would cause the above error? My initial suspicion was that when I change to a different tabpage, the DGV on the original tabpage i was on was still in memory, but when I try calling .Dispose() on it, the DGV just disappears. It may be I am missing something fundamental here.
The problem is that you are probably trying to show a disposed DataGridView.
Do not dispose any Control in your form unless you are previously removing it from the appropiate Container.Controls collection (because you do not need it anymore and/or you plan adding a new one in its place). Otherwise dispose any controls when closing and disposing the Form that contains them if necessary.
In order to show the proper DataGridView depending on selected tab and user options use the Visible property or dynamically add and remove the needed controls to the container's Controls collection (in this case TabPage.Controls.
If its not that then maybe you have a "control leak" (probably event handler holding the object) and you are exceeding the windows handle limit for any given application (10.000 I think it is).