i made a program that create many dynamic panel on button "ADD". The thing is that the name of the dynamic panel that have been created is by this way:
pArr[counter].Name = "panel" + (panel0.Controls.Count + 1);
And so on, so i guess the 5th panel would be named "panel5" if I'm right.
I added some buttons and a Textbox in these dynamically created panels. I don't understand how to use them. I have read a lot of posts in here about it but as its the first time I'm working with this kind of dynamic panels, its hard for me to understand. I found a lot of examples that seems to answer the question but I'm still confused about the names, how to controls buttons and/or textbox.
Per example, how will I set an Event from a button clicked from the 7th panel? It is complicated.
This is my code:
private void btnAdd_Click(object sender, EventArgs e)
{
Color color = ColorTranslator.FromHtml("#f0f0f0");
Color color2 = ColorTranslator.FromHtml("#4285f4");
System.Random R = new System.Random();
Panel p = new Panel();
Label lbl = new Label();
TextBox text = new TextBox();
Button btn = new Button();
Button btn2 = new Button();
Button btn3 = new Button();
int x = 100;
int y = 10;
int x2 = 300;
int y2 = 10;
int x3 = 380;
int y3 = 10;
int x4 = 20;
int y4 = 13;
int x5 = 500;
int y5 = 10;
int counter = 0;
Panel[] pArr = new Panel[25];
pArr[counter] = p;
pArr[counter].Name = "panel" + (panel0.Controls.Count + 1);
pArr[counter].BackColor = color;
pArr[counter].Size = new Size(panel0.ClientSize.Width, 40);
pArr[counter].BorderStyle = BorderStyle.Fixed3D;
pArr[counter].Dock = DockStyle.Top;
lbl.Text = "Name";
lbl.ForeColor = color2;
lbl.Font = new Font("Verdana", lbl.Font.Size);
lbl.Size = new Size(75, 20);
lbl.Location = new Point(x4, y4);
pArr[counter].Controls.Add(lbl);
text.Name = "txtBox" + (panel0.Controls.Count + 1);
text.Size = new Size(120, 20);
text.Location = new Point(x, y);
pArr[counter].Controls.Add(text);
btn.Name = "btnStart" + (panel0.Controls.Count + 1);
btn.Text = "Start";
btn.Font = new Font("Verdana", btn2.Font.Size);
btn.ForeColor = color2;
btn.Size = new Size(75, 20);
btn.Location = new Point(x2, y2);
pArr[counter].Controls.Add(btn);
btn2.Name = "btnStop" + (panel0.Controls.Count + 1);
btn2.Text = "Stop";
btn2.Font = new Font("Verdana", btn2.Font.Size);
btn2.ForeColor = color2;
btn2.Size = new Size(75, 20);
btn2.Location = new Point(x3, y3);
pArr[counter].Controls.Add(btn2);
btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
btn3.Text = "Close";
btn3.Font = new Font("Verdana", btn3.Font.Size);
btn3.ForeColor = color2;
btn3.Size = new Size(75, 20);
btn3.Location = new Point(x5, y5);
pArr[counter].Controls.Add(btn3);
panel0.Controls.Add(pArr[counter]);
panel0.AutoScroll = false;
panel0.HorizontalScroll.Enabled = false;
panel0.HorizontalScroll.Visible = false;
panel0.HorizontalScroll.Maximum = 0;
panel0.AutoScroll = true;
counter++;
}
Can someone explain me how to control panels/buttons/textbox?
Give this a go:
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
var color = ColorTranslator.FromHtml("#f0f0f0");
var color2 = ColorTranslator.FromHtml("#4285f4");
var r = new System.Random();
var p = new Panel();
var lbl = new Label();
var pnlTxtBox = new TextBox();
var pnlBtnStart = new Button();
var pnlBtnStop = new Button();
var pnlBtnClose = new Button();
p.Name = "panel" + (panel0.Controls.Count + 1);
p.BackColor = color;
p.Size = new Size(panel0.ClientSize.Width, 40);
p.BorderStyle = BorderStyle.Fixed3D;
p.Dock = DockStyle.Top;
lbl.Text = "Name";
lbl.ForeColor = color2;
lbl.Font = new Font("Verdana", lbl.Font.Size);
lbl.Size = new Size(75, 20);
lbl.Location = new Point(20, 13);
p.Controls.Add(lbl);
pnlTxtBox.Name = "txtBox";
pnlTxtBox.Size = new Size(120, 20);
pnlTxtBox.Location = new Point(100, 10);
p.Controls.Add(pnlTxtBox);
pnlBtnStart.Name = "btnStart";
pnlBtnStart.Text = "Start";
pnlBtnStart.Font = new Font("Verdana", pnlBtnStart.Font.Size);
pnlBtnStart.ForeColor = color2;
pnlBtnStart.Size = new Size(75, 20);
pnlBtnStart.Location = new Point(300, 10);
pnlBtnStart.Click += (s,e) => StartWasClicked(pnlTxtBox);
p.Controls.Add(pnlBtnStart);
pnlBtnStop.Name = "btnStop";
pnlBtnStop.Text = "Stop";
pnlBtnStop.Font = new Font("Verdana", pnlBtnStop.Font.Size);
pnlBtnStop.ForeColor = color2;
pnlBtnStop.Size = new Size(75, 20);
pnlBtnStop.Location = new Point(380, 10);
p.Controls.Add(pnlBtnStop);
pnlBtnClose.Name = "btnClose";
pnlBtnClose.Text = "Close";
pnlBtnClose.Font = new Font("Verdana", pnlBtnClose.Font.Size);
pnlBtnClose.ForeColor = color2;
pnlBtnClose.Size = new Size(75, 20);
pnlBtnClose.Location = new Point(500, 10);
pnlBtnClose.Click += (s,e) => CloseWasClicked(p);
p.Controls.Add(pnlBtnClose);
panel0.Controls.Add(p);
panel0.AutoScroll = false;
panel0.HorizontalScroll.Enabled = false;
panel0.HorizontalScroll.Visible = false;
panel0.HorizontalScroll.Maximum = 0;
panel0.AutoScroll = true;
}
void StartWasClicked(TextBox tb){
MessageBox.Show(tb.Text);
}
void CloseWasClicked(Panel p){
p.Visible = false;
}
}
pArr needs to be a member of the class, not a local variable. Then you can simply access pArr with an index like any other array.
The panel doesn't even need a name. Names are only useful in the Visual Studio designer so that it can generate the .Designer.cs file with a variable name.
As for the events, just add an event handler with btn.Click += OnStartClick; as you would do for a button normally. In the function declaration, you will get object sender which identifies the button. You can then use Array.IndexOf() MSDN to get the index.
private void OnStartClick(object sender, EventArgs e)
{
var button = (Button) sender;
var panel = button.Parent;
var index = Array.IndexOf(pArr, panel);
...
}
Hokay, so on a comment elsewhere you said you want to
MessageBox.Show("Button name pressed: " + buttonName + " panel position number: " + panelPositionNb)
It means minimally you can have a code that looks like: (the second to last line is new)
btn.Name = "btnStart" + (panel0.Controls.Count + 1);
btn.Text = "Start";
btn.Font = new Font("Verdana", btn2.Font.Size);
btn.ForeColor = color2;
btn.Size = new Size(75, 20);
btn.Location = new Point(x2, y2);
btn.Click += (s, e) => MessageBox.Show($"Button name pressed: {btn.Name}");
pArr[counter].Controls.Add(btn);
Taking this apart:
btn.Click += (s, e) => MessageBox.Show($"Button name pressed: {btn.Name}");
.Click is the event of the button. An event is simply a "list of methods that have a particular signature", and when you say += you add a method to the "list of methods that shall be called when the event is raised". There's no defined order; you can add multiple different methods and they will be called, but not necessarily in any particular sequence. Click has a type of EventHandler which sets out the number and type of arguments any method must have in order to qualify as an handler for any event that is shaped like an EventHandler
+= we've covered; if there is an event on the left, then the thing on the right must be a method with a particular signature (dictated by the event signature) i.e. in the case of a button your method on the right must be shaped like an EventHandler which means it must have a first argument of type object and a second argument of type EventArgs. Your btnAdd_Click is an example of a method that conforms to those rules
(s, e) is a method signature header. Specifically it's a mini method that we call a lambda. The compiler looks at the event signature and knows that the first thing has to be object and the second has to be EventArgs; you only have to give names - the compiler will fill in the types. Actually because we don't even use the names of the arguments in the method code, we could just write (_, _) (in .net core+; framework might complain about duplicate names) here which means "no name; throw it away".. But if we did use the variable in the lambda method we'd have to give it a name. We could give them types too: (object s, EventArgs e) and it starts to look a lot like a normal method if we do; we don't add these because mostly we don't need to; the compiler can usually figure them out on its own
=> is the thing that separates a lambda method signature from the body
MessageBox.Show($"Button name pressed: {btn.Name}") is the body of the method; the thing that will happen when the button is clicked.
Doing a panel close one:
btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
btn3.Text = "Close";
btn3.Font = new Font("Verdana", btn3.Font.Size);
btn3.ForeColor = color2;
btn3.Size = new Size(75, 20);
btn3.Location = new Point(x5, y5);
var pnl = pArr[counter];
btn3.Click += (s,e) => pnl.Visible = false;
pnl.Controls.Add(btn3);
Here we take the panel and capture it into a temporary variable. There are specific reasons for doing this, and it doesn't exactly apply to your code as written but I'm assuming at some point you'll upgrade this to use a loop; if we just did pArr[counter].Visible C# would take the resting value of counter as it was after all the looping is done, and hide that panel.. Any button would either cause an error, because counter would be off the end of the panels array, or some other wrong panel would hide.
We don't have to use these mini-methods (lambdas); we can pass this data around another way if you like..
Taking the example of the panel hide, because it's actually doing something interesting with the UI. Let's have a method that hides a panel that it finds in the Tag of the control in the sender:
private void HidePanelInTag(object sender, EventArgs e){
//get the sender as a button; we will only ever attach this code to buttons that have a Panel in their Tag
var b = sender as Button;
//get the Tag from the button and cast it to a panel
var p = b.Tag as Panel;
p.Visible = false;
}
Now we can tweak the loop that is creating the btn3 close buttons:
btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
btn3.Text = "Close";
btn3.Font = new Font("Verdana", btn3.Font.Size);
btn3.ForeColor = color2;
btn3.Size = new Size(75, 20);
btn3.Location = new Point(x5, y5);
btn3.Tag = pArr[counter];
btn3.Click += HidePanelInTag;
pnl.Controls.Add(btn3);
We've stored the panel in the Tag - this varies for every button, a different Panel. The event handler attachment looks simpler too, because whereas a lambda has a full method (header, and body) defined on the line it is encountered, in more old fashioned terms the method definition is separated from its use:
btn3.Click += HidePanelInTag;
Remember before we said += separates an event on the left, from a method on the right; so long as the method on the right obeys the signature of the event, we're allowed to "add it to the list of methods that are called when the event is raised".
When the button is clicked, HidePanelInTag is called. Windows Forms automatically puts the control that is raising the event (the button) into the object sender argument. That's how we retrieve the Panel to hide; every button has a different Panel in its tag. If you click the 25th button, the sender is the 25th button, and the Tag is the 25th panel
End of the day there are loads of ways to skin this cat. For example you don't have to store a panel in a button's Tag.. You could even do some crazy like this:
btn3.Click += (s, e) => {
var b = s as Button;
var pname = b.Name.Replace("btnClose", "panel");
var p = panel0.Controls[pname];
p.Visible = false;
};
Get the button name, change it to be what the panels name is, find the panel by name, hide it... All in a multi-line lambda. That's kinda nasty, just treat it "for educational purposes" - ultimately all these buttons you make end up stored in tree of controls (your form has a penal that has panels that have buttons..) that can be searched, so "name" does have a use.. But we probably wouldn't use it for this approach.
The main take-away from this is that just like setting the name, the text, the position etc dynamically you also need to wire up the click events dynamically. That's done using event_name_here += event_handler_method_name_without_parentheses_here; in this regard methods aren't really any different from data variables in the way they're passed around by name
Passing Methods Around Like We Pass Data
Edit, following on from a comment below
You're comfortable with Properties:
btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
Events are nearly exactly the same:
btn3.Click += (s,e) => pnl.Visible = false;
Let's have a table:
Property, btn3.Name
Event, btn3.Click
receives a string
receives a method
set with =
set with +=
can receive any string you want, for example "btnClose" + (panel0.Controls.Count + 1)
can receive any method you want, so long as the method has two arguments: an object and an EventArgs, for example (s,e) => pnl.Visible = false
Once you're happy that the following two things are essentially both methods, one called GetTime, and one without a name (because it doesn't need one):
(n) => "Hello " + n + ", the time is " + DateTime.Now;
public string GetTime(string n){
return "Hello " + n + ", the time is " + DateTime.Now;
}
the only mental block you might have, that we need to unblock, is this idea of "passing methods around like we pass data around".
Methods typically produce data when you call them, so you're used to using a method to produce data and assign data:
btn3.Text = GetGermanTranslationFor("Close");
That will call the method GetGermanTranslationFor passing in "Close", and the method returns "Schließen", then "Schließen" will be set as the text - that was all "passing data around"
But suppose a button had a MethodToCallToGetTheText property where instead of setting the data, we set the method to call to get the data and then button will call that method itself:
btn3.MethodToCallToGetTheText = GetGermanTranslationFor
There is no ( after the method name here; we don't want to call the method ourselves.. We want to give the method to the button so the button can call it.
This is what events are intended to do; a way of saying "here, when the click happens, call this method I'm giving you".
Microsoft can write a Button but they can't know what text I will put on it, so they provide a Text property and I set it myself
Microsoft can write a Button but they can't know what what code I'll run when the user clicks it so they just provide a facility where they say "put a method here, with these certain parameters, and we'll call it when the user clicks"
As it happens, Microsoft decided that the "put a method here" should actually be "put one or more methods here", which is why we use += to wire them up (because events are like a list of methods that you add to) but other than that, the theory is the same as setting a property; passing methods round like data is very useful
Related
As the title says i have buttons being created as anonymous objects after an event occurs(the click of another button).What i am trying to do is to make this buttons show a Messagebox when they are being clicked.I can't add this functionality to the buttons and i haven't found anything that solves my problem.Maybe it just can't happen this way.
Controls.Add(new Button { Size = new Size(50, 50),
Location = new Point(40 + i * 60, 100),
Text = i.ToString(),
BackColor = c,
//eventforshowingmessage()
});`
You could assign button to variable first, and then register event:
public AddButton()
{
var newButton = new Button { Text = "Button 1" };
newButton.Click += MyEventListener;
this.Controls.Add(newButton);
}
private void MyEventListener(object sender, EventArgs e)
{
var button = (Button)sender;
MessageBox.Show($"{button.Text} says: Hello, world");
}
I suggest a different syntax: Parent instead of Controls.Add:
for (int i ....) { // whatever loop
...
new Button {
Size = new Size(50, 50),
Location = new Point(40 + i * 60, 100),
Text = $"{i}", // May appear more readable than i.ToString()
BackColor = c,
Parent = this, // <- instead of this.Controls.Add
}.Click += eventforshowingmessage;
...
}
Demo: For instance, let's create 5 buttons and show up which button has been clicked:
for (int i = 0; i < 5; ++i) {
new Button {
Size = new Size(50, 50),
Location = new Point(40 + i * 60, 100),
Text = $"{i}",
BackColor = SystemColors.Control,
Parent = this,
}.Click += (ss, ee) => {
// Lambda: what shall we do on click
MessageBox.Show($"{(ss as Control).Text} clicked!");
};
}
i try to make an controls in runtime (not one, "n" controls in runtime)
but now i want to create event for every single controls
i made one but it just work for the last control i create in runtime
how can i create event for every controls?
private void CreateRuntimeControl(PictureBox pic)
{
lbl = new Label();
number++;
locationX = locationX + 20;
locationY = locationY + 20;
lbl.Name = number.ToString();
lbl.Size = new System.Drawing.Size(30, 20);
lbl.Location = new System.Drawing.Point(10 + locationX, 10 + locationY);
lbl.Text = number.ToString();
lbl.BackColor = Color.Gray;
pic.Controls.Add(lbl);
lbl.MouseDown += lbl_MouseDown;
}
and event
private void lbl_MouseDown(object sender, MouseEventArgs e)
{
MessageBox.Show(lbl.Name);
}
Best Regards
When you create your label. Do this lbl.MouseDown += lbl_MouseDown;
Then in your EventHandler:
MessageBox.Show(((Label)sender).Name);
To clarify; sender will be the object triggering the event so you need to cast it to Label and then you will be able to use its properties.
What is lbl in your lbl_MouseDown method? If it's a class-wide member field which you use as a temporary storage for you just created label objects then you experience quite an expected behaviour. Use the sender argument of your method instead.
You can use a closure for this. It keeps your code nice and clean.
Like this:
var lbl = new Label();
lbl.MouseDown += (s,e) => this.HandleMouseDownOnLabel(lbl);
private void HandleMouseDownOnLabel(Label lbl)
{
Messagabox.Show(lbl.Name);
}
I'm working on a mind-map project. I'm trying to get the "New Bubble" button to create a new textbox into a FREE space on the form. So I want to check if there is another bubble in the place where it's getting created. If it already has a textbox then I want it to find a new place and repeat the process.
How can I do this?
public partial class frmMap : Form
{
private void btnProperties_Click(object sender, EventArgs e)
{
new frmProperties().Show();
}
private void btnNewBubble_Click(object sender, EventArgs e)
{
var tb = new TextBox();
tb.Multiline = true;
tb.BorderStyle = BorderStyle.FixedSingle;
tb.Top = 100;
tb.Left = 200;
tb.Size = new Size(100, 100);
this.Controls.Add(tb);
}
}
You can check "collision" with other controls like so:
foreach (Control checkControl in Controls)
{
if (tb.Bounds.IntersectsWith(checkControl.Bounds))
...
}
Of course, thats a lot of checking to do! If you are just going to "grid" the controls, it would be faster/easier to just layout a bool array that holds the state of each "cell" (filled/empty) then pick the first empty one you find.
Create dynamic textbox:
var tb = new TextBox();
tb.Multiline = true;
tb.BorderStyle = BorderStyle.FixedSingle;
tb.Top = 100;
tb.Left = 200;
tb.Size = new Size(100, 100);
Then use Rectangle.IntersectWith to check if new textbox intersects with other already added texboxes (you can remove control type filter, if you have other type of controls to check):
while(Controls.OfType<TextBox>().Any(x => tb.Bounds.IntersectsWith(x.Bounds))
{
// adjust tb size or position here
}
And last step - add textbox to form:
Controls.Add(tb);
I am creating a C# application which fetches data from a database, and dynamically creates 5 textBoxes and one button in a single row.
The number of rows present in the database equals the number of rows of textBoxes and buttons that are created.
I could successfully create the rows of textBoxes and buttons, the textBoxes are even capable of displaying data that is being fetched from the database.
My trouble however is that the button that is generated, does nothing when clicked, now that is not unexpected since i haven't created a handler to handle the click event. But i am confused on how to dynamically create the click even handler for the buttons that are again generated dynamically.
Below is the code sample that generated the textBoxes and buttons.
for (int i = 3; i <= count; i++)
{
com.Parameters[0].Value = i;
using (SqlCeDataReader rd = com.ExecuteReader())
if (rd.Read())
{
pname = (rd["pname"].ToString());
cname = (rd["cname"].ToString());
budget = (rd["budget"].ToString());
advance = (rd["advance"].ToString());
ddate = (rd["ddate"].ToString());
TextBox tobj = new TextBox();
tobj.Location = new Point(10, (40 + ((i - 2) * 20)));
tobj.Tag = 1;
tobj.Text = pname;
tobj.AutoSize = false;
tobj.Width = 150;
tobj.ReadOnly = true;
this.Controls.Add(tobj);
TextBox tobj1 = new TextBox();
tobj1.Location = new Point(160, (40 + ((i - 2) * 20)));
tobj1.Tag = 2;
tobj1.Text = cname;
tobj1.AutoSize = false;
tobj1.Width = 150;
tobj1.ReadOnly = true;
this.Controls.Add(tobj1);
TextBox tobj2 = new TextBox();
tobj2.Location = new Point(310, (40 + ((i - 2) * 20)));
tobj2.Tag = 3;
tobj2.Text = budget;
tobj2.AutoSize = false;
tobj2.Width = 100;
tobj2.ReadOnly = true;
this.Controls.Add(tobj2);
TextBox tobj3 = new TextBox();
tobj3.Location = new Point(410, (40 + ((i - 2) * 20)));
tobj3.Tag = 4;
tobj3.Text = advance;
tobj3.AutoSize = false;
tobj3.Width = 100;
tobj3.ReadOnly = true;
this.Controls.Add(tobj3);
TextBox tobj4 = new TextBox();
tobj4.Location = new Point(510, (40 + ((i - 2) * 20)));
tobj4.Tag = 5;
tobj4.Text = ddate;
tobj4.AutoSize = false;
tobj4.Width = 100;
tobj4.ReadOnly = true;
int due = 0;
due = int.Parse(ddate);
if (due < 5)
{
tobj4.BackColor = System.Drawing.Color.Red;
}
this.Controls.Add(tobj4);
Button button = new Button();
button.Left = 620;
button.Tag = i;
button.Height = 20;
button.Text = "Details";
button.Top = (40 + ((i - 2) * 20));
this.Controls.Add(button);
}
}
Please give me some ideas on how to generate the click event handler.
Answer part:
Add this:
button.Tag = i;
button.Click += handleTheClick;
...
private void handleTheClick(object sender, EventArgs e){
Button btn = sender as Button;
int row = (int)btn.Tag;
}
Un-answer:
You should reconsider your design. Including coordinates in your data processing code is a really bad idea in 2013, try using ListView, ListBox, GridView or better - switch to WPF.
You need to subscribe to the Click events:
button.Click += ... some event handler ...
You can use a method for the handler:
button.Click += MyEventHandlerMethod;
// put this method somewhere in your Form class
void MyEventHandlerMethod( object sender, EventArgs args )
{
...
Or even a lambda:
button.Click += ( s, e ) => HandleClick( ... any parameters here ... );
// put this method somewhere in your Form class
void HandleClick( ... required parameters ... )
{
...
As a hint, you can look in the .designer.cs file of a normal Form to see how things are done.
I have a dataset that returns questions and answers from the database, each answer in answer table is linked via a forgein key to the question table.
What I would like to achive is the following:
That a a single dynamic form is created on the first question with all the questions listed under it, meaning the FK_table_Answers = PK_table_Questions on the table_Answers:
(eg) This is Form for Question One:
Question One: How old are you?
Answer One (this is a radio button)
Answer Two (this is a radio button)
Answer Three (this is a radio button)
I have managed to get the above kind of working but the problem is my code keeps generating the forms (eg) 3 times becuase there are three answers, so can anyone point me in right direction how to generate the form dynamically but only ONCE - meaning each successive form is created only once as per the question and that particular questions answers under it.
Kind regards
UPDATED code:
private void LoadDataSets()
{
if (_dataSetQuestionnaire.tbl_QuestionnaireQuestion.Rows.Count == 0)
{
try
{
//Questionnaire:
DataSet1TableAdapters.tbl_QuestionnaireTableAdapter questionnaireAdapter =
new DataSet1TableAdapters.tbl_QuestionnaireTableAdapter();
questionnaireAdapter.Fill(_dataSetQuestionnaire.tbl_Questionnaire);
//Category:
DataSet1TableAdapters.tbl_QuestionnaireCategoryTableAdapter categoryAdapter =
new DataSet1TableAdapters.tbl_QuestionnaireCategoryTableAdapter();
categoryAdapter.Fill(_dataSetQuestionnaire.tbl_QuestionnaireCategory);
//QuestionnaireQuestion:
DataSet1TableAdapters.tbl_QuestionnaireQuestionTableAdapter questionnaireQuestionAdapter =
new DataSet1TableAdapters.tbl_QuestionnaireQuestionTableAdapter();
questionnaireQuestionAdapter.Fill(_dataSetQuestionnaire.tbl_QuestionnaireQuestion);
//QuestionnaieAnswer:
DataSet1TableAdapters.tbl_QuestionnaireAnswerTableAdapter questionnaireAnswerAdapter =
new DataSet1TableAdapters.tbl_QuestionnaireAnswerTableAdapter();
questionnaireAnswerAdapter.Fill(_dataSetQuestionnaire.tbl_QuestionnaireAnswer);
using (DataSet1 dSet = new DataSet1())
{
//Questionnaire:
dSet.Merge(_dataSetQuestionnaire.tbl_Questionnaire);
//Category:
dSet.Merge(_dataSetQuestionnaire.tbl_QuestionnaireCategory);
//QuestionnaireQuestion:
dSet.Merge(_dataSetQuestionnaire.tbl_QuestionnaireQuestion);
//QuestionnaieAnswer:
dSet.Merge(_dataSetQuestionnaire.tbl_QuestionnaireAnswer);
int primaryKeyQuestionnaire = Convert.ToInt32(_dataSetQuestionnaire.tbl_Questionnaire.Rows[0][0]);
foreach (DataSet1.tbl_QuestionnaireRow questionnaire
in _dataSetQuestionnaire.Tables["tbl_Questionnaire"].Select(String.Format("pk_tbl_Questionnaire = {0}", primaryKeyQuestionnaire)))
{
foreach (DataSet1.tbl_QuestionnaireCategoryRow category
in _dataSetQuestionnaire.Tables["tbl_QuestionnaireCategory"].Select(String.Format("fk_tbl_Questionnaire = {0}", questionnaire.pk_tbl_Questionnaire)))
{
foreach (DataSet1.tbl_QuestionnaireQuestionRow question
in _dataSetQuestionnaire.Tables["tbl_QuestionnaireQuestion"].Select(String.Format("fk_tbl_QuestionnaireCategory = {0}", category.pk_tbl_QuestionnaireCategory)))
{
int radiobuttonPosition = 0;
foreach (DataSet1.tbl_QuestionnaireAnswerRow answer
in _dataSetQuestionnaire.Tables["tbl_QuestionnaireAnswer"].Select(String.Format("fk_tbl_QuestionnaireQuestion = {0}", question.pk_tbl_QuestionnaireQuestion)))
{
//Gets the questins via the FK_questionnaireQuestion and fill the _dataSetRadioButtons to generate on dynamic form.
DataSet1TableAdapters.tbl_QuestionnaireAnswerTableAdapter a =
new DataSet1TableAdapters.tbl_QuestionnaireAnswerTableAdapter();
DataSet dSetRadioButtons = new DataSet();
dSetRadioButtons.Merge(a.GetDataByQuestionnaireQuestion(answer.fk_tbl_QuestionnaireQuestion));
_dataSetRadioButtons = dSetRadioButtons;
string theQuestion = question.tbl_QuestionnaireQuestion_Description.ToString();
Form form = new Form();
_form = form;
if(_form == null)
{
_form = new Form();
}
else
{
form.Height = 400;
form.Width = 550;
form.StartPosition = FormStartPosition.CenterScreen;
Label label = new Label();
label.Location = new System.Drawing.Point(5, 10);
label.Size = new System.Drawing.Size(450, 25);
label.Text = theQuestion;
Panel panel = new Panel();
panel.Size = new System.Drawing.Size(300, 200);
panel.Location = new System.Drawing.Point(15, 50);
panel.BackColor = Color.Yellow;
System.Windows.Forms.RadioButton[] radioButtons = new System.Windows.Forms.RadioButton[_dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count];
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].Text = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i]["tbl_QuestionnaireAnswer_Description"].ToString();
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
//panel.Controls.Add(radioButtons[i]);
radioButtons[i].Click += new EventHandler(Form1_Click);
Int64 item = Convert.ToInt64(_dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[0].ItemArray[3].ToString());
panel.Controls.Add(radioButtons[i]);
}
Button nextButton = new Button();
nextButton.Text = "Next";
nextButton.Name = "button";
nextButton.Location = new System.Drawing.Point(200, 300);
nextButton.Size = new System.Drawing.Size(150, 25);
nextButton.Click += new EventHandler(nextButton_Click);
form.Controls.AddRange(new Control[] { panel, label, nextButton });
form.ShowDialog();
CreateBoxAndQuestion(form, panel, label);
//form.Dispose();
}
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show("Error");
}
}
private void CreateBoxAndQuestion(Form f, Panel p, Label l)
{
for (int i = p.Controls.Count - 1; i >= 0; i--)
{
p.Controls.RemoveAt(i);
}
}
If I understand correctly, you call CreateBoxAndQuestion every time a new question is selected.
But you create (and destroy) the form each time your code enters in this method.
A first approach would be to keep the form, label, button and panel creation outside the method (perhaps in design mode) then passing these controls to the method as
EDIT: Somewhere in your code before entering the load of your next question:
frmQuestion _form = null; // Global
// Create a global instance and keep it without displaying
if(_form == null) _form = new frmQuestion(); // frmQuestion created with panel, label e button via FormDesigner
then when you need to populate _form call
CreateBoxAndQuestion(_form, _form.Panel, _form.Label, questionText);
In this example I pass the _form to CreateBoxAndQuestion, but this is not necessary because is a global. You could change CreateBoxAndQuestion to use directly the global instance.
private void CreateBoxAndQuestion(frmQuestion f, Panel p, Label l, string _label)
{
// Do not display your form here....
}
Now when entering the method clear every RadioButton controls in the panel.Controls collection
for (int i = p.Controls.Count - 1; i >= 0; i--)
{
p.Controls.RemoveAt(i);
}
the rest of the code should change only to reflect the new text assigned to the label and controls and the re-adding of the RadioButtons to the panel. No more creation and reinitialization for Form Label, Button.
label.Text = _label;
Don't forget to destroy _form at the end of your program with _form.Dispose();