C# How to get child control in specific control - c#

I need save image from specific child controls(Picturebox inside GroupBox), refer to this question, but GetAll() is from last to first return controls: ckBox8 -> ckBox3 -> ckBox1, how should save image from ckBox1 to ckBox8?
public IEnumerable<Control> GetAll(Control control, Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl, type)).Concat(controls).Where(c => c.GetType() == type);
}
private void MyControlsTest()
{
var c = GetAll(this, typeof(CheckBox));
var ckBoxlist = c.OfType<CheckBox>().Where(ckBox => ckBox.Checked == true);
foreach (var i in ckBoxlist)
{
MessageBox.Show(i.Name);
/*Save PictureBox inside CheckBox if ckBox.Checked == true*/
}
}

Because your controls have equivalent names, you can transform the name of the control you know, to find the control you want:
foreach(var g in this.Controls.OfType<GroupBox>()){ //'this' is the Form. If all your GroupBoxes are in some other panel/container, use that panel's name instead
var cb = g.Controls[g.Name.Replace("gp", "ck")] as CheckBox;
var pb = g.Controls[g.Name.Replace("gpBox", "pb")] as PictureBox;
//PUT MORE CODE HERE e.g. if(cb.Checked) pb.Image.Save(...)
}
If cb/pb are null you'll need to look into the hierarchy to see why; I can't tell from a screenshot what the control nesting looks like. Indexing a ControlCollection by [some name] brings the first control that is a direct child member of the collection, but remember that controls exist in a tree - if you had a panel inside a groupbox then the checkbox is a child of the panel, not the groupbox (the panel is a child of the groupbox).
If things are deeply nested, you can look at ControlCollection.Find instead - there is a bool youcan specify to make it dig through all children. Note that it returns an array of controls

Related

Using findControl to find a child element

I have a Placeholder and I have a dynamically created panel in the placeholder, I also have some dynamically added radio buttons in the panel, now I can usefindControl() to find the radio buttons if they are direct children of the placeholder.
I've literally spent the whole of yesterday trying to find them when they are the child elements of the Panel. How is there a way to do this?
Here's my code below:
PlaceHolder1.Controls.Add(myPanel); //add the panel to the placeholderenter code here
myPanel.Controls.Add(myRadioButton); //add the radiobutton to the panel
You should make method that recursively searches for a control using it's Id. That mean that the method will search for a control inside of (in your case) placeholder. If method finds control, it will return it. If not, it will go search every placeholder's subcontrol, going "deeper". And then, if nothing is found, it will search one more level down, in every placeholder subcontrols' subcontrol etc.)
private Control FindControl(string ctlToFindId, Control parentControl)
{
foreach (Control ctl in parentControl.Controls)
{
if (ctl.Id == ctlToFindId)
return ctl;
}
if (ctl.Controls != null)
{
var c = FindControl(ctlToFindId, ctl);
if (c != null) return c;
}
return null;
}
and then use it like this:
Control ctlToFind = FindControl(myRadioButton.Id, Placeholder1);
if (ctlToFind != null)
{
//your radibutton is found, do your stuff here
}
else
{
// not found :(
}
Finding Controls recursive is an option, but it also has a couple of down-sides.
If you know the ID's of all the controls you can just use FindControl
RadioButtonList myRadioButton = PlaceHolder1.FindControl("Panel1").FindControl("RadioButtonList1") as RadioButtonList;
Label1.Text = myRadioButton.SelectedValue;
But you will need to give your dynamically added controls an ID.
Panel myPanel = new Panel();
myPanel.ID = "Panel1";
RadioButtonList myRadioButton = new RadioButtonList();
myRadioButton.ID = "RadioButtonList1";
PlaceHolder1.Controls.Add(myPanel);
myPanel.Controls.Add(myRadioButton);

To focus or not to focus

I have a Panel that has AutoScroll = true.
In that Panel is a series of TextBoxes. I should note that the TextBoxes aren't on the panel directly but are nested several levels (about 4-5).
Now, the scrolling with my mouse wheel works only if the panel has focus, naturally. I can use Focus() within mouseEnter event to make sure the panel has focus.
However, the TextBoxes I mentioned earlier rely heavily on focus. Only the user should be able to remove focus from the TextBox by clicking somewhere else.
The TextBoxes are created dynamically and would make for a very messy code to keep an array of them, or any type of reference to check if they have focus. Not to mention that there could be a lot of them.
How do I give the focus to the Panel, but only if none of the TextBoxes is focused?
You don't need to keep an array of the dynamically created Textboxes, you can get the array using:
bool anyTextBoxFocused = false;
foreach (Control x in this.Controls)
{
if (x is TextBox && x.Focused)
{
anyTextBoxFocused = true;
break;
}
}
if (!anyTextBoxFocused)
{
//give focus to your panel
}
Edit
Based on How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?, even nested controls can be obtained using:
public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
then use it with:
var c = GetAll(this,typeof(TextBox));

Accessing variables dynamically in C#

I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.

How to put string as panel name in c#

I have panel that visibility is false. I want when click on treeview list, that list will retrive the panel name that i stored in database. i know how to retrieve that panel name from database in string. But how to change that 'string' into panel to make able to write like this:
panelNamethatLoadFromDB.visible = true;
My Code:
DataTable dtPanelToView = MyLibrary.getResults("SELECT LEVEL1_ID, LEVEL1_PATH FROM LEVEL1_TREEVIEW WHERE LEVEL1_DESC='" + clickLink + "'");
if (dtPanelToView.Rows.Count > 0)
{
string panelToDisplay = dtPanelToView.Rows[0]["LEVEL1_PATH"].ToString();
}
So, currently this "panelToDisplay" is string that contains panel name. i want to change this panel visibilty. Example : panelToDisplay.visible = true;
WinForms stores the controls diplayed on a form in the Form.Controls collection.
You could loop over this collection to find your panel
foreach(var pan in yourForm.Controls.OfType<Panel>())
{
if(pan.Name == panelToDisplay)
{
pan.Visible = true;
}
}
Using the IEnumerable extensions you could also avoid the explicit loop with
var pan = yourForm.Controls.OfType<Panel>().FirstOrDefault(x => x.Name == panelToDisplay);
if(pan != null)
pan.Visible = true;
Keep in mind that the Controls collection of the form stores only the first level of controls. If a control contained in the Form's Controls collection is a control container then it has its Controls collection where other controls could be stored.
EDIT
As from the comment below from TaW you could also use the Controls collection with a string indexer
if(this.Controls.ContainsKey(panelToDisplay))
this.Controls[panelToDisplay].Visible = false;

C# LoadControl() (.ascx) and add into "this" rather than sub control

I'm good with Loading the control, using the LoadControl("~/vitrualPath"), so I have:
UserControl ctrl = (UserControl)LoadControl("~/controls/someControl.ascx");
this.Controls.Add(ctrl);
//plcCtrl.Controls.Add(ctrl);
The trouble is that I wish to then loop through all the controls in the usercontrol:
foreach (Label c in this.Controls.OfType<Label>())
{
// It's a label for an input
if (c.ID.Substring(0, 8) == "lblInput")
{
// Do some stuff with the control here
}
}
However, the added controls aren't part of this, but part of ctrl
Is there a way I can add the contents of the loaded control to this or a way to loop through both this and ctrl in one hit?
If you simply want to loop through both top-level labels and labels in ctrl, try this.Controls.Concat(ctrl.Controls).OfType<Label>() in your foreach loop.
You can also move your if into a LINQ Where call:
.Where(l => l.ID.Substring(0, 8) == "lblInput")
By using a recursive function you don't need to worry about controls within sub levels/ containers. Something like this should be OK (all you need to do is to pass the top level control along with the id substring that you are interested in). So if the conditions are met it will do whatever you have intended to do with the control and at any sub level.
public void ProcessControl(Control control, string ctrlName)
{
foreach (Label c in control.Controls.OfType<Label>())
{
// It's a label for an input
if (c.ID.Substring(0, 8) == ctrlName)
{
// Do some stuff with the control here
}
}
foreach (Control ctrl in control.Controls)
{
ProcessControl(ctrl, ctrlName);
}
}
You should write a recursive method that starts looping the controls in this.Controls and goes down the tree of controls. It will then also go in your user control and find your labels.
I don't think there is a way to loop through both like you want.
You can easily create a method that receives a Control as parameter and iterate though its controls. Something like this:
void Function(Control control)
{
foreach (Label c in control.Controls.OfType<Label>())
{
// It's a label for an input
if (c.ID.Substring(0, 8) == "lblInput")
{
// Do some stuff with the control here
}
}
}
You should be able to access the controls inside the user control by accessing the this.Controls[index].Controls I think, however it kind of depends what you are trying to achieve? Their might be a cleaner way of doing what you are trying to do?

Categories