Attempting to retrieve value from a dynamic custom control - c#

I need to retrieve the text from a textbox within a custom control. The custom control is part of an ArrayList so there can be multiple custom controls displayed on a Form. How do I access the text from a single textbox within one of the controls in the ArrayList?
The code below shows how I'm creating the dynamic custom control:
ArrayList assessmentInfo = new ArrayList();
int length = (int)moduleInfoLevel6.numericUpDownModuleAssessmentNum.Value;
for (int i = 0; i < length; i++)
{
assessmentInfo.Add(new AssessmentInfo());
System.Drawing.Point p = new System.Drawing.Point(10, 160 + i * 32);
(assessmentInfo[i] as AssessmentInfo).Location = p;
(assessmentInfo[i] as AssessmentInfo).Size = new System.Drawing.Size(440, 32);
tabPageLevel6.Controls.Add((assessmentInfo[i] as AssessmentInfo));
}
Here are screenshots showing how the custom control is displayed:
assessmentInfo custom control
http://i.imgur.com/9qwCL.jpg
How the custom control is displayed on the form
http://i.imgur.com/DFJYV.jpg

you could add a name to each control
something like:
(assessmentInfo[i] as AssessmentInfo).Name = "assessmentInfo" + i.ToString();
then you could access it in the following way
foreach (object control in tabPageLevel6.Controls)
{
if (control is AssessmentInfo)
{
if ((control as AssessmentInfo).Name == "assessmentInfo1")
// do something with the control
MessageBox.Show((control as AssessmentInfo).Name);
}
}

Related

How to access asp controls in a class file

I have created a panel in my page view (tour.aspx file).
Now I want to access it in my class file (add_tour.cs file).
This is my panel:
<asp:Panel ID="itinerary_panel" runat="server"></asp:Panel>
This is my code behind tour.aspx file:
add_tour tour_obj = new add_tour();
int days_count = 2;
tour_obj.textbox_generator(days_count);
And this code is in add_tour.cs file:
public void textbox_generator(int days_count)
{
}
Now how to access the panel from aspx file?
Please help.
There's no need to actually add the text boxes to the panel from this class.
public List<TextBox> textbox_generator(int days_count)
{
var textBoxes = new List<TextBox>();
for(int i = 0; i < days_count; i++)
{
txt_desc = new TextBox();
txt_desc.ID = "txt_desc" + i.ToString();
txt_desc.CssClass = "form-control";
txt_desc.Attributes.Add("placeholder", "Enter day " + i + " description");
txt_desc.TextMode = TextBoxMode.MultiLine;
textBoxes.Add(txt_desc);
}
return textBoxes;
}
Then change your code behind to:
add_tour tour_obj = new add_tour();
int days_count = 2;
var textBoxes = tour_obj.textbox_generator(days_count);
foreach(var textBox in textBoxes)
{
itinerary_panel.Controls.Add(textBox);
}
Note that you need to be careful where you add these controls in the page lifecycle. See Microsoft documentation.
This keeps your textbox_generator from needing to know anything about the specific page using it.
Also, you should really align your naming conventions with C# standards. Use PascalCasing. textbox_generator should be TextBoxGenerator etc. And you can probably make textbox_generator into a static method if it doesn't need to access any fields or properties of its class.
If you really wanted your other class to itself add the controls directly to the panel, then you would just pass a reference to the panel from the code behind to the class.
public void textbox_generator(int days_count, Panel panel)
{
for(int i = 0; i < days_count; i++)
{
txt_desc = new TextBox();
txt_desc.ID = "txt_desc" + i.ToString();
txt_desc.CssClass = "form-control";
txt_desc.Attributes.Add("placeholder", "Enter day " + i + " description");
txt_desc.TextMode = TextBoxMode.MultiLine;
panel.Controls.Add(txt_desc);
}
}
and call this this way from your code behind:
add_tour tour_obj = new add_tour();
int days_count = 2;
var textBoxes = tour_obj.textbox_generator(days_count, itinerary_panel);
This works because itinerary_panel actually is a reference to the panel. See Passing Objects By Reference or Value in C#. However, it's often a bad idea to have a method modify the state in that manner.

How to add an interator number to a variable name?

In my program i'm currently working on programmatically adding a variety of form objects in C#. For example i'm trying to create a certain group of panels, which contain the data I wish to show. When loading the form I have a file which contains all of the data I wish to load in, the loading itself works fine but when loading I need to create a variety of form labels, panels and images to display all of the necessary data and as such I need to make these panels and labels all with a seperate name, but programmatically.
for (int i=0; i<fileLength; i++)
{
Panel pnl = New Panel();
pnl.Name = "pnl1"+i;
//Set the other properties here
}
What i'm trying to do if use an iterator to append the current iteration to the end of the name. Am I going the right way about it? Or should I be doing a different method?
You cannot change variable/object name at runtime. If you want to write code against the object than you need to keep a reference to it. In your case you have changed the Name property of Panel but still you have to use it as pnl, not as pnl0 or pnl1.
The other way for doing this would be to use a Dictionary with key as the name as you assign and value as the object itself. This will help you in accessing your controls using its name that you have assigned to it.
Dictionary<string, Panel> panels = new Dictionary<string, Panel>();
for (i = 0; i <= 10; i++) {
Panel pnl = new Panel();
panels.Add("pnl" + i.ToString(), pnl);
}
//write code against panels
panels("pnl0").Width = 100;
For accessing within loop:
foreach (string pnlName in panels.Keys) {
panels(pnlName).Visible = true;
}
for (i = 0; i <= 10; i++) {
panels("pnl" + i).Visible = true;
}

Placing multiple instances of same control on form

I am making an application in winforms which shows a blueprint in a picturebox, and I need to place parts on it programmatically. These parts needs to be clickable (thus they should be a user control), and then fire the corresponding click event (clicking on a part should display information unique to that part). I could say that I want to place custom buttons on my picture. Now, of course, I need only one click event, and change the displayed information according to selection, though I don't know how to "link" this event to each created button.
I have a list of parts right next to the picturebox, and selecting a part should make the associated control to appear on the form (and deselecting it should remove it, or at least make it hidden). At first, I thought I will create one control during design, and make it appear/disappear and relocate it with each selection. The problem is, that the user should be able to select multiple parts, and the program should show all selected parts on the blueprint.
As each blueprint is different, the number of parts cannot be defined in advance. Is it possible, to create multiple instances of the same control on the run? Or is there a workaround?
If you use controls for your picture elements( you do not determine anything from coordinates of mouse click) and each picture element is associated with only one menu control, then I can propose you to use the Tag property to associate the corresponding menu controls:
public Form1()
{
InitializeComponent();
this.CreatePictureRelatedControls();
}
private void CreatePictureRelatedControls()
{
Int32 xPictureControls = 50,
yPictureControls = 50,
xAssociatedControls = 200,
yAssociatedControls = 50,
yMargin = 10;
Int32 controlWidth = 125,
controlHeight = 20;
Int32 controlCount = 3;
// ---------Associated controls-----------------
var associatedControls = new Button[controlCount];
// Loop - creating associated controls
for (int i = 0; i < associatedControls.Length; i++)
{
var associatedButton = new Button()
{
Left = xAssociatedControls,
Top = yAssociatedControls + (i * (controlWidth + yMargin)),
Width = controlWidth,
Height = controlHeight,
Text = String.Format("associated control {0}", i),
Visible = false
};
// Event handler for associated button
associatedButton.Click += (sender, eventArgs) =>
{
MessageBox.Show(((Control)sender).Text, "Associated control clicked");
};
associatedControls[i] = associatedButton;
}
// ----------------- Picture controls ---------------
var pictureControls = new Button[controlCount];
// Loop - creating picture controls
for (int i = 0; i < pictureControls.Length; i++)
{
var pictureButton = new Button()
{
Left = xPictureControls,
Top = yPictureControls + (i * (controlWidth + yMargin)),
Width = controlWidth,
Height = controlHeight,
Text = String.Format("picture part button {0}", i),
// Use of tag property to associate the controls
Tag = associatedControls[i],
Visible = true
};
// Event hadler for picture button
pictureButton.Click += (sender, eventArgs) =>
{
Control senderControl = (Control)sender;
Control associatedControl = (Control)senderControl.Tag;
associatedControl.Visible = !associatedControl.Visible;
};
pictureControls[i] = pictureButton;
}
this.Controls.AddRange(associatedControls);
this.Controls.AddRange(pictureControls);
}
P.S. If you need to associate multiple controls then you can just set Tag property to some collection:
button.Tag = new Control[] {associated[1], associated[3]};

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.

Event problem C# .NET UserControl

I have an UpdatePanel and in it a regular Panel. In the Panel I dynamically add simple UserControls. The Usercontrol has a Button and a Label. When I click on a button in a control it removes all controls in the Panel which I have added dynamically.
Can anyone help?
int controlID = 0;
List<Control> cc = new List<Control>();
if (Session["ControlsCompleted"] != null)
{
cc = Session["ControlsCompleted"] as List<Control>;
for (int i = 0; i < cc.Count; i++)
{
pnlCompletedEducation.Controls.Add(cc[i]);
}
controlID = cc.Count;
}
Controls_TestWebUserControl ct = LoadControl(#"Controls\TestWebUserControl.ascx") as Controls_TestWebUserControl;
ct.ID = controlID.ToString();
cc.Add(ct);
ct.EnableViewState = true;
pnlCompletedEducation.Controls.Add(ct);
txtInstitutionName.Text = controlID.ToString();
List<Control> lc = new List<Control>();
for (int i = 0; i < pnlCompletedEducation.Controls.Count; i++)
{
lc.Add(pnlCompletedEducation.Controls[i]);
}
Session["ControlsCompleted"] = lc;
This is how I add the controls to the panel. I had to keep them somewhere, and i couldn't do it with the ViewState, so i used a Session, which is a bad idea.
You say that you are adding the user control dynamically. Are you having code like this:
void Page_Load(...)
{
if (!IsPostback)
// AddUserControl here.
}
You need to add the user control during every request, also postbacks, because it will not be stored in the view state that you have modified the control tree.
You problem that you have not recreated (for example at Page_Load) dynamically added control.
Make sure that control is recreated on IsPostBack

Categories

Resources