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).
Related
Items like below have to be accommodated on a specific area on WinForm.
"Order 1 ------------ Time Left: 00:20:00"
"Order 2 ------------ Time Left: 01:30:20"
We should be able to perform the following action on the each order:
Each item will occupy not more than one line. As the area specified
for it on the win form is limited, as more items comes in, I want to
make the area scrollable.
According to the time left the background color of the line should also change.
There is a DONE button next to it. So, if the item is selected and DONE is pressed, the item is moved off the list.
My question is what C# Form control can be used for it. I was thinking of labels, but how to make the area scrollable if there are many of them. If not labels, what else is suggested?
As suggested in comments, you can use grid, but in case it does not suits your requirements, this is like something what you can do -
Create a custom user control which will have a label control for your order detail and a Done button. Something like this (sure you will design it better!). The label will be empty initially and you will pass then from outside, using a public property for example, while creating the control.
Define an Event on this control, and raise this event when the Done button is clicked. This is required for your main form to know that when to remove this user control.
Add a FlowLayoutPanel to your main form. This will be the container for your user controls. Make sure to set the following so that the controls are created as desired
this.flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
this.flowLayoutPanel1.WrapContents = false;
this.flowLayoutPanel1.AutoScroll = true;
Now you can start adding your custom control to this FlowLayoutPanel, either by loop or the way you like. The control will added in linear way, one in each line, and you will also get scroll it it exceeds the given space.
Make sure to define event handler for the control, so that you know when to remove the control. And of course you can set other properties like back groung color etc. That's not going to be any problem.
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();
Is there a predefined event for Tab Controls, or maybe something custom I can develop, that will allow me to execute some logic on a control I've removed from that Tab Control's Control Collection, before it ACTUALLY gets removed from the tab control.
Context :
I have a tab control with tab pages. These tab pages load documents related to entries in a reference grid. Each time I select a row in the reference grid, a tab page with the corresponding document loaded gets added to my tab control. The Check column for that row in the grid also gets checked.
I want to be able to close a tab page in my tab control and be able to relate this closed tab page to its corresponding entry in the reference grid so i can uncheck that row.
I've tried browsing through all the possible events for tab control and found nothing suitable. The ControlRemoved event fires only AFTER my tabpage has closed and tab focus has automatically shifted to the next tab.... This is causing my controlremoved logic to fail and enter an infinite loop, trying to close ALL the available tabs instead of just this one, and throwing an invalid index exceptions when it's closed the final one.
You need to ensure that when you uncheck the item in your grid programmatically you do not update the tab control. Otherwise you always will run into an infinite loop causing the unwanted behavior.
You can achieve this by using a boolean flag. In the code-example below I haven't used the "real" event-handlers because I have no IDE at hand to test this at the moment, but rather replaced them by simple methods, so get the idea:
private bool suppressTabUpdate = false;
private void HandleGridCheckedOrUncheckedEvent()
{
if (suppressTabUpdate)
return;
// Insert logic here to create or remove the tab pages as required
}
private void HandleTabPageRemovedEvent()
{
suppressTabUpdate = true;
// Uncheck the item in the grid here
suppressTabUpdate = false;
}
I'm not sure if there's an exact event for you're looking for, but I have an alternative approach to propose.
It sounds to me that some of the UI code is too closely tied together. The grid and the tab control should not be talking to each other directly from the event handlers: that's what's causing the infinite loop (the events are "ping-ponging" back and forth).
Instead, I recommend that both the grid and the tab control be managed by another "component" (just a class, or a few methods in the existing form class) and that this component manage opening/closing tabs and modifying rows in the grid.
For example, when the user selects a row in the grid, don't modify the grid directly at all: instead, call a new method that does whatever needs to happen when a row is selected: check a checkbox, open a tab, etc. When a row no longer needs to be selected, don't change any selections directly: instead, call a new method that does whatever needs to happen when a row is not selected: uncheck a checkbox, close a tab, etc.
If you need a reference to your tab BEFORE it gets removed, there is one simple way to do it. Make CustomTabControl that inherits from TabControl and override its OnControlRemoved event.
If you have this:
public class CTabControl:TabControl
{
protected override void OnControlRemoved(ControlEventArgs e)
{
TabPage tp = e.Control as TabPage; // reference to tab page before it gets removed
base.OnControlRemoved(e);// gets removed here
}
}
I am writing a windows forms application that has a lot of textboxes. I want to add a label or a caption to the textbox, so that I don’t have to drag a lot labels onto the form and deal with positioning etc. So far I have found 2 possible ways to do this.
Create a user control with the label and textbox. How do I get the
control, label and textbox to size appropriately depending on the
text entered since the control will be reusable and different text sizes will be entered. How to get all the
properties and events of the textbox to remain the same.
Extend a normal textbox and add a string property called label or
caption, and show this property at the left of the textbox. I know
this can be done in Web.UI with CSS but is it possible in a winform
and how?
Any suggestions on how to do either of these?
Thanks.
You can create a UserControl that contains a label and a textbox. When you add the user control to your form, both the label and the textbox within will be added simultaneously. You can expose properties of the label and textbox to assign values at design or run time.
Using this method, you can add multiples of the user control to standardize the layout. As far as resizing the controls based on the text, you'll have to subscribe to events and change the sizing manually.
For example, you can subscribe to the TextChanged event of the label and the textbox. When the event fires, you calculate the size of the string and then adjust the width and position of the controls accordingly.
If you get to the point where you have too many textboxes, I would suggest switching to a DataGridView. The GridView component is very well suited for what you're describing, but of course it requires you to accept a grid layout.
One of the bonuses involved in using a GridView is hard to appreciate until you see it in action: it creates only one HWINDOW at a time (two if you're in editing mode). If you create Labels and TextBoxes all over your form, each one is registered with the operating system as an HWINDOW object. All those HWINDOW objects take time to display! In .NET 1.0, WinForms was so slow that dialogs with more than about two dozen controls were unusable. Even though .NET 2.0 is much better in this regard, but you'll still get significantly better performance by using a single control that manages lots of data, as opposed to lots of controls that each manage one piece of data.
Oh, and another option, if you like: you can also try a PropertyGrid. It has the advantage that it will also show help and allow you to create complex editing controls for each element.
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.