iterating panel control - c#

I tried to find the answer by googling but no luck.
I designed form with panel containing textboxes so I can iterate through its controls
and save every textbox in an array (so I can iterate the array when I want to),
the thing is I couldn't find which property the panel knows how to arrange the order to iterate the controls inside it, which is the first, second,etc..
I thought maybe it's by tag, but when I changed them to my likings it didn't change anything.
so I wonder - how can you tell the panel iteration to go through the controls as you prefer?
which property do you need change?
private void CreateTxtArr()
{
txts = new TextBox[8];
for (int i = 0; i < pnlTxt.Controls.Count; i++)
txts[i] = (TextBox)pnlTxt.Controls[i];
}

You can use is operator to check if the child control of panel is TextBox
private void CreateTxtArr()
{
txts = new TextBox[8];
for (int i = 0; i < pnlTxt.Controls.Count; i++)
if( pnlTxt.Controls[i] is TextBox)
txts[i] = (TextBox)pnlTxt.Controls[i];
}

If you can use .Net 3.5 or higher, you can do it pretty easly with Linq:
private void CreateTxtArray()
{
// txts is an Array of TextBox
var txts = (from Control ctrl in pnlTxt.Controls
where ctrl is TextBox
select ctrl as TextBox).ToArray();
}
Is a simpler way to iterate, in all cases
EDIT: this is an old answer I had forgotten about, below there is an even simpler way to do that
private void CreateTxtArray()
{
// txts is an Array of TextBox
var txts = pnlTxt.Controls.OfType<TextBox>().ToArray();
}

Related

How to use an array to hold controls in form and hide/show them

I'm still new at coding. I'm making a calculator but I also want a lot of other things in it. like a conversion calculator, cook book, and kanji radical dictionary in c# WindowsFormsApplication I want to change from one to the next using a comboBox so I was going to make a array with all the control I wish to hide/show
string[] numList = {"button0","button1","button2", "button3"};//this will have all number and .
for (int i = 0; i < numList.Length; i++)
{
numList[i].Hide();
}
But it tell me there no definition for 'Hide' but when I switch numList[i] to button0 it work but I don't wish to wright the same 11 control for every time i add something to the comboBox anyway to fixes this or any other method
If you want to hide all Buttons then try this:
foreach (Button control in Controls.OfType<Button>())
{
(control).Hide();
}
This iterate through all Buttons of the form and hide them. But if you want to just hide a specific buttons then you can set the Tag property of that buttons to something like OP then to hide only that Buttons:
foreach (Button control in Controls.OfType<Button>())
{
if (control.Tag.ToString() == "OP")
{
(control).Hide();
}
}
Or with linq:
foreach (Button control in Controls.OfType<Button>().Where(control => control.Tag.ToString() == "OP"))
{
(control).Hide();
}
try below code
private void btnHide_Click(object sender, EventArgs e)
{
string[] buttonList = { "button1", "button2", "button3" };
for (int i = 0; i < buttonList.Length; i++)
{
Control[] ctrl = this.Controls.Find(buttonList[i], true);
((Button)ctrl[0]).Visible = false;
}
}
You are keeping a list of strings, you should actually add the buttons in to the list in order to have the Hide method visible
Control[] numList = {button0, button1, button2, button3 };

Can we dynamically reference element (Server Side)

Say I have the elements with the ID's of "Input1", "Input2" and "Input3".
Is there a way to loop through them rather then having to write:
Input1.Value = 1;
Input2.Value = 1;
Input3.Value = 1;
in jquery you can just refrence an element like $('#Input'+i) and loop through i, something similar would be very useful in ASP code behind.
Edit: Duh, I searched again for finding all "x" controls on page and came up with the following source code:
foreach(Control c in Page.Controls)
{
if (c is TextBox)
{
// Do whatever you want to do with your textbox.
}
}
Kind of ... based on your example naming scheme you can do something like the following:
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
string controlName = TextBox
for(int i=1;i<4;i++)
{
// Find control on page.
Control myControl1 = FindControl(controlName+i);
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}
}
This will let you loop through numerically named controls but otherwise it is somewhat clunky.
If you know the parent container you can loop though its .Controls() property. If you start at the Page level and work recursively, you can eventually reach all controls on the page.
See the answer from this question for more details.
I like to keep things strongly typed, so I store them in a list. This makes the code more resilient to refactoring and there's no need to cast. It takes a slight bit more upfront work to put all your controls into the list, but to me it's often worth it.
I'm not sure what type your controls are, so I'm going to pretend they're of type Input.
var InputControls = new List<Input>(){Input1, Input2, Input3};
foreach(var input in InputControls)
{
input.Value = 1;
}

Switching Panels on button event

I have a row of panels on my WindowsForm which have two buttons on each, Move Up and Move down. I want it so that when the user clicks down it switches the current panel with the panel beneath it essentially taking its place. (swapping them over). I have 10 instances of the same panel so something simple like the below isnt working because all the panels are called DataPanel. Any help is appreciated.
private void MoveDownEnabled_Click(object sender, EventArgs e)
{
Point temp = DataPanel.location;
DataPanel.Location = Panel2.Location;
Panel2.Location = temp;
}
I would recommend storing the Panel in a collection, for a start. This will make the code for accessing the next panel, very clean.
ArrayList panels = new ArrayList();
panels.add(panel);
panels.add(panel2);
panels.add(panel3);
ANd also keep a value, index, to show where in the list you're up to.
private int index = 0; // Set it to a default value.
Then ammend your button click code:
private void MoveDownEnabled_Click(object sender, EventArgs e)
{
Panel Current = panels.get(index);
if(index < panels.Count)
{
// Grab the next item.
Panel Next = panels.get(++ index);
// And this part is up to you!
}
}
You seem to have the right idea with how you're swapping them around, so I think now I've set this up for you, you can work the rest out for yourself.
Don't use your variable name to differentiate controls at runtime, use their properties or their instances. In this case, you can use the Panel's Name property to differentiate, or its Tag property which can hold an object type. Also, I recommend storing the Panels in a collection such as a List so that they can be iterated and accessed easily.
For example (as a general idea)
//won't get nested panels but sounds like you don't need that
var listOfPanels = this.Controls.OfType<Panel>().ToList();
//access the panel you want by name
Panel pnl = listOfPanels.Where(x => x.Name == "panelName").FirstOrDefault();
In your case, your Panel events will be send the panel as the sender in your event handler.
private void MoveDownEnabled_Click(object sender, EventArgs e)
{
Panel selectedPanel = sender as Panel;
if(selectedPanel != null)
{
Point temp = DataPanel.location;
DataPanel.Location = selectedPanel.Location;
selectedPanel.Location = temp;
}
}
I think a simple swap method should do:
public void SwapPanels(System.Windows.Forms.Panel pnl1, System.Windows.Forms.Panel pnl2)
{
var localtion1 = pnl1.Location;
var location2 = pnl2.Location;
pnl2.Location = localtion1;
pnl1.Location = location2;
}
if you want to swap any two panels, just call this method to swap them. if you have many panels, just store them in a list or so and swap them freely.

How to access TabPages that are created in real-time?

Some inits done earlier in the code...
private List<System.Windows.Forms.TabPage> tab_pages = new List<System.Windows.Forms.TabPage>();
int tab_increment = 0;
Somewhere in the code, I create a bunch of tab pages in real-time.
for (i=0; i<5; i++)
{
tab_pages.Add( new System.Windows.Forms.TabPage() );
tab_pages[tab_increment].Location = new System.Drawing.Point(4, 22);
tab_pages[tab_increment].Name = 1 + tab_increment.ToString();
tab_pages[tab_increment].Size = new System.Drawing.Size(501, 281);
tab_pages[tab_increment].Text = tab_increment.ToString();
this.tabControl.Controls.Add(tab_pages[tab_increment]);
tab_increment += 1;
}
Now I would like to access elements that are these tab pages. Also let's pretend that I created different elements on each page (example, tabPage[0] a button, tabPage[1] a checkbox, etc), how do I access them knowing that everything was added dynamically?
Check this approach:
void Walk(Control control)
{
foreach (Control c in control.Controls)
{
//just walking through controls...
//...do something
//but remember, it could contain containers itself (say, groupbox or panel, etc.)...so, do a recursion
if (c.Controls.Count > 0)
Walk(c);
}
//or
foreach (Button btn in control.Controls.OfType<Button>())
{
//an example of how to walk through controls sub array of certain type
//this loop won't have a single iteration if this page contains no Buttons
//..so you can replace Button
//and have some certain code for different types of controls
}
}
And launch it for tabcontrol:
foreach (TabPage page in tabControl1.TabPages)
Walk(page);
I guess there is no special need to have separate collection of tabpages for one tabcontrol, as soon as it has TabPages property.
In the code above I used Enumerable.OfType Method to get a subcollection of controls of certain type.
As for your code, try this:
for (int i = 0; i < 5; i++)
{
this.tabControl.Controls.Add(new System.Windows.Forms.TabPage());
this.tabControl.TabPages[i].Text = i.ToString();
//...do whatever you need
//...
//besdies, I think, ther's no need in tab_increment...loop index works well enough
}
In order to add pages, I think that using
tabControl.TabPages.Add(new TabPage("Name"));
or in your case
this.tabControl.TabPages.Add(tab_pages[tab_increment]);
is more suitable.
In order to access them you could use
TabPage tp = tabControl.TabPages[i]; //where i is the index of your TabPage
and you can use TabPage.Controls.Add of the Controls property to add any Control on the TabPage like:
Button btn = new Button();
btn.Name = "Button name";
tp.Controls.Add(btn);
You can use the Controls property on the TabPage object. Each control in the collection is given to you as a Control, and it is up to you to cast them to the type that you want.

Dynamically create text inputs (ASP.net/C#)

I have an input field on my page where the user will type in the number of text inputs they want to create. The action for the button is:
int num_flds = int.Parse(a_fld.Text);
for (int i = 0; i < num_flds; i++)
{
TextBox tmp = new TextBox();
tmp.ID = "answer_box" + i;
tmp.Width = Unit.Pixel(300);
answer_inputs.Controls.Add(tmp);
}
Now, I have another button that the user would click after they have filled in all their dynamically-created text boxes. Questions, first of all, am I creating the text boxes dynamically in the correct place? How would I get the values out of the dynamically-created text boxes? (The dynamically-created text boxes are being added to the Panel "answer_inputs".
I recommend reading this and a few other articles about the topic of dynamically created controls. It is not quite as straightforward as you might think. There are some important page lifecycle issues to consider.
When creating web controls dynamically, I find it best to have the controls themselves report in the answers. You can achieve it like this:
Create something in your Page class to store the values:
private readonly Dictionary<TextBox, string> values=new Dictionary<TextBox, string>();
Make a method to act as a callback for the textboxes when their value changes:
void tmp_TextChanged(object sender, EventArgs e)
{
TextBox txt = sender as TextBox;
if(txt!=null)
{
values.Add(txt,txt.Text);
}
}
And then add this method to each textbox as they are added:
int num_flds;
if(!int.TryParse(a_fld.Text,out num_flds))
{
num_flds = 0;
}
for (int i = 0; i < num_flds; i++)
{
TextBox tmp = new TextBox();
tmp.ID = "answer_box" + i;
tmp.Width = Unit.Pixel(300);
answer_inputs.Controls.Add(tmp);
tmp.TextChanged += tmp_TextChanged;
}
Finally, you iterate through the dictionary on callback to see if it holds any values. Do this in the OnPreRender method for instance.
Edit: There is a problem with this, if the number of text fields are decreased on postback. Some safe way to recreate the previous textfields on postback should be employed.

Categories

Resources