Check if user control is already open - c#

Im using WinForm C#
Have MainForm there is one panel where. my Inventory and Sell user controls are opening in panel. panel1.Controls.Add(inventory);
How to check if userControls are open?
When i check it i want to add tabControl. But i dont know how to add in tabPage controls without closing user control. Thanks

I mean if user control is already added in panel1.Controls. If its added gave name of user control
– Acid
How could the user control possibly be added to panel1.Controls without you knowing it? And if you added it yourself, you should already know the name of the user control.
Thus, all you have to do is loop through the controls in panel1.Controls and see if you find your user control. For example:
foreach (Control ctrl in panel1.Controls)
{
if (ctrl.Name == myUserControl)
{
// Found the control!
// (do something here...)
}
}
Alternatively, if you for whatever reason don't know the name of the control, you could still find all the controls of type UserControl that have been added to the panel's Controls collection. Like so:
foreach (Control ctrl in panel1.Controls)
{
if (ctrl is UserControl)
{
// Found a UserControl!
// (do something here...)
}
}
Remember that the Tag property provided on every control gives you a way to uniquely identify it. You can check that property for matches, too, if you don't know the name.

Not sure what you mean by open, but you can handle the ControlAdded event on the Panel class to capture when a control is added...
panel1.ControlAdded += new ControlEventHandler(p_ControlAdded);

Related

Issue while iterating through User Controls in a Windows Form

I am facing an issue while running through all the User Controls in my Windows form.
I am creating a Windows Form that has the following features:
The Main form has 3 User Controls embedded in it
The Main form also has a combo box. Selecting a particular value in the Combo box will bring the corresponding User Control to the front.
Each User Control has two Check boxes as well as two Combo boxes.
The User can summon each User Control through the Main Form's combo box and check the check boxes and/or modify the combo boxes inside each User Control
Once this is done, there is a button, which on being pressed, executes the following code. This code is supposed to check which check boxes have been checked from every User Control, and execute some functionality :
private void button1_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
if (c is UserControl)
{
foreach (Control ctl in c.Controls)
{
if (ctl is CheckBox && (ctl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
}
}
}
//Some other code after this
}
Here, I have included a Text Box called "Indicator" that shows whether the compiler has entered a particular "for" loop or "if" block. And I'm observing that the innermost "if" alone is not getting executed.
Could someone point out why exactly this is happening?
You need a recursive algorithm,
void ProcessControls(Control ctrlContainer)
{
foreach (Control ctrl in ctrlContainer.Controls)
{
if (ctrl is CheckBox && (ctrl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
if (ctrl.HasChildren)
ProcessControls(ctrl);
}
}
I do think you might be better off adding some functionality to your user control so it can describe the state of its own checkboxes rather than going digging inside it to find it and do logic. Generally in OO programming, when we encapsulate things within a class, we also provide general purpose accessors "visible to the outside" to describe the internal state of affairs, rather than letting external code interests go poking around inside class to find out what they want
At some point in time you've added these usercontrols to the form either directly in the designer, or programmatically. In the first case they will have their own name:
var u1 = usercontrol1.GetCheckboxStateArray();
var u2 = usercontrol2.GetCheckboxStateArray();
Etc
Or maybe you added them programmatically, in which case it would make sense to keep track of them in a list as you're adding them:
protected List<UserControl> _ucList = new List<UserControl>();
...
foreach(var result in somedatabasequery){
var uc = new UserControl(result.Whatever);
this.Controls.Add(uc);
_ucList.Add(uc);
}
Then this list can be iterated. Sure you could argue that "well .Controls is a collection too, so why add them to another list when they're already in an accessible collection" - for the reasons you're here; .Controls is a general purpose description of the hierarchy of all controls on a form, it contains stuff we don't want and is hard to iterate. This List is purely and simply all and only the stuff we're interested in
As an aside, the UI you have described is atypical. The more usual way of hiding and showing controls under the selection of something that holds a bit of text would be a TabControl. It might be easier to loop through too, if you will persist with this "search for UserControls in a collection of controls" method - tabcontrols have tabpages, tabpages would probably have a .Controls that just contains your UserControl. The tabpage intrinsically takes care of showing and hiding controls as pages are clicked on which could simplify your code
Thanks to everyone for the answers. As it happens, the issue was hiding in plain sight, right under my nose. In each of the User Controls, I had placed the Checkboxes and Combo Boxes inside a Group Box. It completely slipped my mind, so much so that I didn't even mention them in my question.
Thus, as #Caius had suggested in the comments, the code wasn't functioning because I had not addressed the Group Box Container holding these Controls. Once I removed the Group Boxes (used only for aesthetic purpose), the code started functioning properly.

Windows Form Control with Children

I have a panel in my Windows form that I would like to add other controls like text boxes into it and also iterate over all elements in the panel to retrieve all the data in it.
Is this possible to do with a panel control?
I experimented with a foreach loop such as
foreach(textbox tb in panel1)
{
}
but I get an error saying panel does not have a public definition for GetEnumerator.
What would be a better control/container to use, where I can add more controls to it and eventually access all the controls within it an their data?
Update
Just a heads up - I am having some problems with adding multiple text boxes in code.
I create a textbox object and then add it to the panel, but only one shows up.
I have read elsewhere on this site and others that adding a textbox with the same name might be causing the problem.
To solve this, I replaced the panel with a flow layout panel which works great.
Hopefully this helps others.
It's the correct control to use. Try iterating the Controls property of the panel object.
foreach(Control control in panel.Controls)
{
if(control is TextBox)
{
TextBox textBox = control as TextBox;
//etc.
}
}
The following example clears all textbox in any control
void ClearTextBoxes(Control parent)
{
foreach (Control child in parent.Controls)
{
TextBox textBox = child as TextBox;
if (textBox == null)
ClearTextBoxes(child);
else
textBox.Text = string.Empty;
}
}
Then whenever you want clear. you call
ClearTextBoxes(panel1);
You need to access Controls collection of the Panel, better if you do:
foreach(Textbox tb in panel1.Controls.OfType<TextBox>)
But the above would give you TextBoxes inside the panel, not inside other controls inside the panel, if you want to get get textboxes recursively then see this question
You're missing one little thing. Try:
foreach (Control c in panel1.Controls)
And then check the control type if you have more than one type of control in it.
The reason for the error is that panel1 is an object, not a collection of objects, so you have to refer specifically to the collection of objects that panel1 contains.
Something like this
foreach (Control c in panel1.Controls)
{
if(c.GetType() == typeof(TextBox))
{
//do stuff
}
}

how can i get my added usercontrol properties from flowLayoutPanel

I am using flowLayoutPanel and adding my custom user controls to it, I can add mu usercontrol to it but i don't know how can it use it after adding.
in this part i add my user controls:
...
ExtensionUserControl extension = new ExtensionUserControl(this, AMI_ClientInstance);
//Add Obj Name (Extension Number)
extension.ExtensionNumber = Obj.ObjName;
flowLayoutPanel1.Controls.Add(extension as ExtensionUserControl);
...
and another place i want to have the properties of my added user control, i try to user this code but it get error, It says that can not convert windows control to ExtensionUserControl
ExtensionUserControl extension = flowLayoutPanel1.Controls[1];
please totally tell me how can i have my user control properties after adding it to panel?
thanks
Are you sure Controls[1] is ExtensionUserControl?
I think that:
foreach(Control ctl in flowLayoutPanel1.Controls)
{
if(ctl is ExtensionUserControl)
{
(ExtensionUserControl)ctl......//do something u want
}
}
I'm not test it yet, just thinking, sorry if it doesn't work

foreach (Control ctrl in Frm.Controls) in which order it takes controls

I am having a peculiar problem with the order in which TextBox controls are added in to the form's Controls property.
Currently, I have the function:
public static bool IsValidate(System.Windows.Forms.Form Frm)
{
foreach (Control ctrl in Frm.Controls)
if (ctrl is TextBox)
// if (((TextBox)ctrl).AccessibleDescription == "Valid" && ((TextBox)ctrl).Text == string.Empty)
if (((TextBox)ctrl).AccessibleDescription == "Valid" && ((TextBox)ctrl).Text.Trim()== "")
{
MessageBox.Show(((TextBox)ctrl).AccessibleName + " Can't be Blank", Program.companyName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
((TextBox)ctrl).Focus();
return false;
}
return true;
}
But it's iterating through the textboxes randomly, even though I have set their tab indices.
So I develop the same form again and create the textboxes sequentially. But still, when I pass the form to this function, it's iterating through the textboxes randomly.
I want to know if there is any property of the controls that would allow me to manage their flow.
You can do its easily.
Please use following syntax and which sort controls as per your tabindex in your form
foreach (Control control in this.Controls.Cast<Control>()
.OrderBy(c => c.TabIndex))
{
}
It's much easier to sort controls manually than manage their order in Controls collection. Example (sorts by TabOrder):
private static int CompareTabIndex(TextBox c1, TextBox c2)
{
return c1.TabIndex.CompareTo(c2.TabIndex);
}
public static bool IsValid(Form form)
{
List<TextBox> textBoxes = new List<TextBox>();
foreach(Control ctl in form.Controls)
{
TextBox textBox = ctl as TextBox;
if(textBox != null) textBoxes.Add(textBox);
}
textBoxes.Sort(new Comparison<TextBox>(CompareTabIndex));
foreach(TextBox textBox in textBoxes)
{
if(textBox.AccessibleDescription == "Valid" && textBox.Text.Trim() == "")
{
MessageBox.Show(textBox.AccessibleName + " Can't be Blank",
Program.companyName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
textBox.Focus();
return false;
}
}
return true;
}
Is it really iterating over the controls "randomly"? (Implying that it is non-deterministic and the order is likely to change each time.) Or is it iterating over the controls in the same order each time, but not the order you expect? I suspect it's the latter, given that the C# language specification explicitly states the ordering of foreach (see first answer).
The tab order certainly won't affect the ordering of the controls. That's just for UI purposes. The actual order of the controls as array elements in the backing store is more likely controlled by the order in which they were created when building the form.
Can you elaborate more on that last part where you develop the form again "and take the text box sequentially"?
The controls are placed in order of the Z-order of the controls in the same parent container (top-most to bottom-most). To test try placing controls on a form and get the order. Apply "Send to Back" or "Bring to Front" for a few controls (at design time or runtime). The order of the foreach will change with the topmost control first and downwards.
The generated Designer code adds the controls based on the z-order. Lowest control first (top most control last). Hence it seems like it is based on the order in which it is added to the container.
I'm not sure if the implementation of BringToFront() and SendToBack() internally removes and adds controls in the required order. To me it makes sense to have it based on the z-order. And like mentioned above, we can always use our own ordering if required.
You can drop the controls into the form in the designer visually, and then open up the Form.Designer.cs source file and locate where the designer has typed in the code to add the controls to the Controls collection (i.e. the Controls.Add lines) and re-order those lines in the *.Designer.cs by hand. Once you've done that, the designer should leave your changes alone. I noticed that the designer writes them in reverse order. Your foreach should find them in the order that you arranged them.
i had this problem and i changed the order control name on Designer.cs ,
this.groupBox3.Controls.Add(this.txtPrice);
this.groupBox3.Controls.Add(this.txtDate);
See the Document Outline of the Form in view -> Other Windows -> Document Outline.
And then change the hierarchy of the controls as you need. the foreach looks there

is there a way to add and remove controls from a form to another without the controls being deleted/GCed?

I have one form called:
MyControlContainerForm ccf
and a main form called:
SolidForm sf
and I am adding all the controls inside an instance of new MyControlContainerForm () to SolidForm, using:
sf.Controls.Add ( Control )
but when I remove them using:
sf.Controls.Remove ( Control )
they are gone from MyControlContainerForm instance as well.
Why? And how do I prevent this?
I want to be able to add MyControlContainerForm controls whenever I want, without initializing MyControlContainerForm every time, just once.
The reason this is happening is not that you're removing the controls from form2, but rather that you're adding them. Controls can't be shared between forms. If you look at the reflected code of the form2.Controls.Add() on the Control Collection enumerator, we can see what's happening here:
...
if (value.parent == this.owner)
{
value.SendToBack();
}
else
{
if (value.parent != null)
{
value.parent.Controls.Remove(value);
}
base.InnerList.Add(value);
...
As you can see here it check the parent of the incoming control, if it's not the owner of the collection, then it simply runs a value.parent.controls.Remove(value) to strip the control from it's originating form, so it can be added to the current one.
Controls are not intended to be on 2 Forms at the same time. Im surprised you got way with that, probably because you do not Show MyControlContainerForm .
Note that Control has a Parent property (= in who's Controls collection am I?), singular.
Edit:
In fact, when button1 is on panel1, it is part of panel1.Controls. But the statement
panel2.Controls.Add(button1);
removes button1 from panel1.Controls.
You can use a List<Control> as a store. That would also keep them alive just fine.

Categories