Form cannot be displayed dynamically - c#

I trying to build a method to draw my form dynamically, this method receives a list of questions, from this we draw a form and show each question (label) and an option (yes/no - radio buttons).
I can add each control created before in my Forms.Controls, but when the form opens, just one question is rendered passing a list with more than 20 questions. Why? Did I forget to do something?
This method builds all my components to the form based on my list of questions.
private void BuildComponents(List<Question> properties)
{
this.propertyList = new List<System.Windows.Forms.Control>();
for (int i = 0; i < properties.Count; i++)
{
var newLabel = new System.Windows.Forms.Label
{
AutoSize = true,
Location = new System.Drawing.Point(13 + i + 5, 13),
Name = properties[i].Label,
Size = new System.Drawing.Size(699, properties[i].Description.Length),
TabIndex = i,
Text = properties[i].Description,
};
var newYesRadioButton = new System.Windows.Forms.RadioButton
{
AutoSize = true,
Location = new System.Drawing.Point(13 + i + 5, 34),
Name = "radioButton" + i + 1,
Size = new System.Drawing.Size(52, 21),
TabIndex = i + 1,
TabStop = true,
Text = "Sim",
UseVisualStyleBackColor = true
};
var newNoRadioButton = new System.Windows.Forms.RadioButton
{
AutoSize = true,
Location = new System.Drawing.Point(71 + i + 5, 34),
Name = "radioButton" + i + 2,
Size = new System.Drawing.Size(55, 21),
TabIndex = i + 1,
TabStop = true,
Text = "Não",
UseVisualStyleBackColor = true
};
propertyList.Add(newLabel);
propertyList.Add(newYesRadioButton);
propertyList.Add(newNoRadioButton);
};
}
This method initializes my form and add all properties built in this.Controls
private void InitializeComponent()
{
this.BuildComponents(questions);
foreach (var property in propertyList)
{
this.Controls.Add(property);
}
}

I would recommend you to use FlowLayoutPanel and UserControls. With FlowLayoutPanel you can put usercontrols one after another and you dont need to deal with the location property.
In addition, you should not change InitializeComponent..
Actually, you dont need to touch the code in the designer file!

Related

Set controls inside a control inside same row of TableLayoutPanel

I create a TableLayoutPanel where I want to add two buttons one next to other so I try:
First I create panel as:
var pnlButtons = new TableLayoutPanel
{
Name = "pnlButtons",
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
Dock = DockStyle.Bottom,
RowCount = 1,
TabIndex = 1
};
pnlButtons.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
pnlButtons.ColumnStyles.Add(new ColumnStyle());
pnlButtons.RowStyles.Add(new RowStyle());
pnlButtons.HandleCreated += new EventHandler(pnlButtons_Created);
this.Controls.Add(pnlButtons);
Then I add buttons in event handler:
private void pnlButtons_Created (object sender, EventArgs e)
{
var pnl = (TableLayoutPanel)sender;
var btnSetAmount = new Button
{
Text = "Set Amounts",
Name = "btnSetAmount",
Anchor = AnchorStyles.Top | AnchorStyles.Right,
TabIndex = 0,
UseVisualStyleBackColor = true
};
pnl.Controls.Add(btnSetAmount);
var btnCancel = new Button
{
Text = "Cancel",
Name = "btnCancel",
Anchor = AnchorStyles.Top | AnchorStyles.Left,
TabIndex = 1,
UseVisualStyleBackColor = true
};
pnl.Controls.Add(btnCancel);
}
But when I run it I see something like this:
It is in a different row. How can I do in order to set in the same row? Regards
Update: after comments above now it show it like:
The TableLayoutPanel has an override on the Controls collection that allows you to specify the column and row:
pnl.Controls.Add(btnSetAmount, 0, 0);
pnl.Controls.Add(btnCancel, 1, 0);

How to get the index of dynamically created multiple panels in C# GUI form,when a checkbox is clicked in one of the dynamically created panel

I have a split container panel in GUI Form.When a button is clicked in left panel,it pulls out information along with multiple checkboxes on dynamically created panels on the right panel using a loop.Each panel on the right side can have multiple checkboxes based on some condition.For example, the first panel has one checkbox and the second panel below the first has got 8 checkboxes in the same row.When one of the checkboxes in second panel is clicked, I have to get the index of the that panel to do some manipulation. Tab index does not help me to get one as each panel can have any number of checkboxes.I spent a day to get around the problem with no luck. Your help will be much appreciated. I have posted the code below.
for (int j = 0; j < numOfSensors.Count; j++)
{
sensorpanel = new Panel();
sensorpanel.Size = new Size(800, 60);
sensorpanel.Location = new Point(0, Y);
sensorpanel.BackColor = Color.LightGray;
sensorpanel.Paint += new PaintEventHandler(panel_Paint);
Button sensor = new Button();
sensor.Size = new Size(200, 50);
sensor.Location = new Point(1, 1);
sensor.FlatStyle = FlatStyle.Flat;
sensor.FlatAppearance.BorderColor = Color.LightGray;
String sensorType = "Occupancy";
sensor.TextAlign = ContentAlignment.MiddleLeft;
sensor.BackColor = Color.LightGray;
sensor.ForeColor = Color.Black;
sensorpanel.Controls.Add(sensor);
if (sensorType.Equals("Occupancy"))
{
CheckBox cb = new CheckBox();
cb.Location = new Point(380, 15);
cb.Size = new Size(20, 17);
cb.Checked = checkBox(j,0);
cb.Text = "Occupancy";
checksensorbuttons.Add(cb);
cb.CheckedChanged += new EventHandler(cb_CheckChanged);
sensorpanel.Controls.Add(cb);
}
else if (sensorType.Equals("Multi-input:Digital"))
{
int xLoc = 210;
int yLoc = 15;
for (int k = 16; k <32; k+=2)
{
CheckBox cb = new CheckBox();
cb.Location = new Point(xLoc, yLoc);
cb.Size = new Size(20, 17);
cb.Checked = checkBox(j,k);
cb.Text = "Multi-input";
cb.CheckedChanged += new EventHandler(cb_CheckChanged);
sensorpanel.Controls.Add(cb);
xLoc += 30;
}
splitContainer.panel2.Controls.Add(sensorpanel);
}
//checkedchanged eventhandler
private void cb_CheckChanged(object sender, EventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
if (checkbox.Text.Equals("Occupancy"))
{
// How to get the index of the panel when a checkbox in corresponding panel is checked?
if (checkbox.Checked == true)
{
//some manipulation
}
else
{
//some manipulation
}
}
else if (checkbox.Text.Equals("Multi-input"))
{
//get index of the panel where one of the checkboxes are clicked
if (checkbox.Checked == true)
{
//do some manipulation
}
else
{
//do some manipulation
}
}
There are multiple ways
Use Name property of the checkbox. When the checkbox is created assign it a logical name which makes it easier to identify it. Only string can be used here.
Use Tag property of the checkbox to preserve the data you want to refer it. Its good place to store any object and not just string.
Use Parent property of the checkbox to access checkbox's parent properties.
As a best practice, assign a logical name to the dynamic controls. This is the best way to identify the control.
sensorpanel.Name = "panel" + j.ToString();
this.Controls.Add(sensorpanel);
:
:
cb.Text = "Occupancy";
cb.Tag = "panel Index = " + j.ToString();
cb.Name = "panel" + j.ToString() + "_" + "cb_" + cb.Text;
sensorpanel.Controls.Add(cb);
void cb_CheckedChanged(object sender, EventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
string mssg;
mssg = "Name = " + checkbox.Name;
mssg = "tag = " + checkbox.Tag;
mssg = "Parent text = " + checkbox.Parent.Text;
mssg = "Parent name = " + checkbox.Parent.Name;
MessageBox.Show(mssg);
}

How can i add Events to hard coded forms in c#?

I've tried to create a form that will create buttons based on the number of items in database
my int count is equal to the number of count in my database
I'd like to add events or functions to the created label, that when i click the label it will display in the MesssageBox the name of the label
below is my code,
int Count;
List<Panel> pnl = new List<Panel>();
List<Label> tasklevel = new List<Label>();
List<Label> taskStatus = new List<Label>();
List<Label> taskname = new List<Label>();
List<PictureBox> image = new List<PictureBox>();
for (int i = 0; i < Count; i++)
{
Panel pan = new Panel();
pan.Name = "panel" + i;
pan.BackColor = Color.White;
pan.Dock = DockStyle.Top;
pan.Padding = new Padding(10, 0, 10, 10);
pan.Height = 80;
pnl.Add(pan);
Label lbl = new Label()
{
Name = "lbl" + i,
ForeColor = Color.Black,
//Dock = DockStyle.Left,
AutoSize = false,
Width = 0,
BackColor = Color.Silver,
TextAlign = ContentAlignment.MiddleLeft,
Padding = new Padding(10, 10, 10, 10),
Text = "Designing",
}; tasklevel.Add(lbl);
Label lblname = new Label()
{
Name = "lblname" + i,
ForeColor = Color.Black,
Dock = DockStyle.Left,
AutoSize = false,
Width = 0,
BackColor = Color.Gray,
TextAlign = ContentAlignment.MiddleLeft,
Padding = new Padding(10, 10, 10, 10),
Text = "Designing",
}; taskStatus.Add(lblname);
Label tskname = new Label()
{
Name = "tskName" + i,
ForeColor = Color.FromArgb(31, 31, 31),
Font = new Font("Segoe UI", 11, FontStyle.Regular),
Dock = DockStyle.Left,
AutoSize = false,
Width = 200,
BackColor = Color.Gainsboro,
TextAlign = ContentAlignment.MiddleCenter,
Padding = new Padding(10, 10, 10, 10),
Text = "Task Name",
}; taskname.Add(tskname);
PictureBox picBox = new PictureBox()
{
Name = "picBox" + i,
Dock = DockStyle.Fill,
AutoSize = false,
Image = DreametryMIS.Properties.Resources.f1,
SizeMode = PictureBoxSizeMode.StretchImage,
BackColor = Color.FromArgb(240,240,240),
Padding = new Padding(10, 10, 10, 10),
}; image.Add(picBox);
pan.Controls.Add(picBox);
pan.Controls.Add(lblname);
pan.Controls.Add(lbl);
pan.Controls.Add(tskname);
FlowPanel.Controls.Add(pan);
}
I'm new at c#, I hope some can help me
Implement an event handler like this:
public void label_Clicked(object sender, EventArgs e)
{
Label label = sender as Label;
if (label == null) return;
MessageBox.Show("Name: " + label.Name + " Text: " + label.Text);
}
You can now add this handler to the Click event of your labels, for example:
lblname.Click += label_Clicked;
tskname.Click += label_Clicked;
When one of the labels is clicked now, the method label_Clicked gets called with the label as argument for sender. So by casting the sender to Label you can easily access the clicked label's properties.
Note that you cannot add the handler inside the label's object initializer as you did with the other properties, but need to do it in an extra statement like I showed.
You can too:
lblname.Click += delegate { nameOfUrFunction (lblname) };
private void nameOfUrFunction (Label lbl)</code>
{
}
TableCell cel2 = new TableCell();
Label lbl2 = new Label();
lbl2.Text = s;
cel2.Controls.Add(lbl2);
tr.Cells.Add(cel2);
TableCell cel3 = new TableCell();
DropDownList ddlcountry = new DropDownList();
ddlcountry.ID = s;
cel3.Controls.Add(ddlcountry);
tr.Cells.Add(cel3);
table.Rows.Add(tr);
form1.Controls.Add(table);
DropDownList ddl1 = (DropDownList)form1.FindControl("CountryId");
DropDownList ddlstate = (DropDownList)form1.FindControl("StateId");
ddl1.AutoPostBack = true;
ddl1.SelectedIndexChanged += new EventHandler(ddl1_SelectedIndexChanged);
protected void ddl1_SelectedIndexChanged(object sender, EventArgs e)
{
}

WinForms how to show specific panel from FlowDirectionPanel

i have the following FlowDirectionPanel http://prntscr.com/aao6lt as you can see those are achievements for a poker game.When you get a new achievement a yes/no messageBox pops up and it ask's you if you want to go and check out your new acquirement if you press yes I want to be able to automatically navigate to the newly unlocked achievement which are contained in the FlowDirectionPanel which looks like in the image above. Also each achievement is contained in another panel which is children of the flowPanel if you look closer you can see that they have some outline border. I create and add the panels dynamically but they do have names which can help me to navigate to the desired panel. This is how i create them:
public void PanelForAchievements(Form currentForm, FlowLayoutPanel flp, AchivementRequirements achivement)
{
FlowLayoutPanel retFlp = flp;
string pGetAchivementName = #"pGet" + achivement.Name;
string lbAchivementName = #"lb" + achivement.Name;
string lbAchivementRewardName = #"lb" + achivement.Name + #"Reward";
string cbGetAchivementName = #"cbGet" + achivement.Name;
string pbAchivementName = #"pb" + achivement.Name;
var pGetAchivement = new Panel
{
Name = pGetAchivementName,
Size = new Size(retFlp.Width, 100),
BorderStyle = BorderStyle.FixedSingle,
};
currentForm.Controls.Add(pGetAchivement);
var lbAchivement = new Label
{
Name = lbAchivementName,
Location = new Point(pGetAchivement.Location.X, pGetAchivement.Location.Y),
Size = new Size(135, 30),
AutoSize = false,
BorderStyle = BorderStyle.FixedSingle,
Font = new Font("Microsoft Sans Serif", 10F, FontStyle.Regular, GraphicsUnit.Point, (byte)0),
Text = achivement.TitleText,
};
var lbAchivementReward = new Label
{
Name = lbAchivementRewardName,
AutoSize = true,
Top = (pGetAchivement.Height - pGetAchivement.Height) / 2,
Text = achivement.RewardLabelText,
TabIndex = 2,
BorderStyle = BorderStyle.FixedSingle,
Location = new Point(lbAchivement.Location.X, lbAchivement.Location.Y + lbAchivement.Height + 5)
};
var cbGetAchivement = new CheckBox
{
Name = cbGetAchivementName,
AutoCheck = false,
AutoSize = true,
Location = new Point(lbAchivement.Location.X + lbAchivement.Width + 10, lbAchivement.Location.Y),
TabIndex = 1,
UseVisualStyleBackColor = true
};
achivement.IsUnlocked(MainPoker.AllAchievements[achivement.EnumCasted], achivement.Requirement,cbGetAchivement);
var pbAchivement = new PictureBox
{
BorderStyle = BorderStyle.Fixed3D,
Name = pbAchivementName,
Dock = DockStyle.Right,
BackgroundImageLayout = achivement.PictureBoxImageLayout,
//Location = new Point(pGetAchivement.Right, pGetAchivement.Location.Y),
Size = new Size(145, 90),
SizeMode = PictureBoxSizeMode.Zoom,
TabIndex = 9,
TabStop = false,
Image = achivement.PackPreview,
};
pGetAchivement.Controls.Add(lbAchivement);
pGetAchivement.Controls.Add(lbAchivementReward);
pGetAchivement.Controls.Add(cbGetAchivement);
pGetAchivement.Controls.Add(pbAchivement);
retFlp.Controls.Add(pGetAchivement);
achivement.Title = lbAchivement;
achivement.RewardLabel = lbAchivementReward;
achivement.Unlocked = cbGetAchivement;
achivement.Preview = pbAchivement;
}
It's just simple code and this is how i initialize them :
public static RoyalFlush RoyalFlush = new RoyalFlush(1, new Tuple<string, int?>("Royal Card Pack", 100000));
private readonly CreatePanels _createAchivementPanels = new CreatePanels();
foreach (var achi in AchivementRequirements.AchivementList)
{
_createAchivementPanels.PanelForAchievements(this, pAchievementsCards, achi);
//im also doing other stuff here..
//pAchivementsCards is the name of the FlowDirectionPanel
}
Now by the time the yes/no messageBox is shown i already know which achievement is unlocked and also my achievements have classes as seen above public static RoyalFlush RoyalFlush and those classes have property - Name which obviously contains the name of the achievement im using this name to create respective names for each control i create from public static RoyalFlush RoyalFlushfor example :
string pGetAchivementName = #"pGet" + achivement.Name;
p stands for panel and i simply just get the current achievement name using the property achivement.Name and we end up with something like this : pRoyalFlush as a name for our panel. Now that i know the name of the panel and which achievement is being unlocked i need to navigate through my FlowDirectionPanel and find the specific panel and leave the focus there. I have no idea how to do that i will show an example with pictures of what i want if it's not clear by now :
First we unlock new achievement and we get the yes/no mbox : http://prnt.sc/aaodyr
Now we press the Yes button which will redirect us to my new form and show us the achievement FlowDirectionPanel : h.t.t.p.:/./.prntscr.com/aaofft here the program see's that the achievement for Full House is completed and it should show it in the middle of the screen with a nice border just like so : h.t.t.p.:././.prntscr.com/aaoh40
I dont have reputation to post more than 2 links so i had to put some dots in them ..
It's my first question and my native language is not English so excuse me for any mistakes I made.
you may make some foreahc loop, where you compare names, and then, when you find the control you need, scroll your flowlayoutpanel to it. For example, my flowlayoutpanel has 4 buttons, and only 2 of them are visible, and I want to scroll to button4:
foreach (Control c in flowLayoutPanel1.Controls)
{
if ((c as Button).Name == "button4")
{
(c as Button).Focus();
flowLayoutPanel1.ScrollControlIntoView(c);
break;
}
}
Hope I andrestand your question correctly.

New window replicates

I am working on an interface that uses a Wcf to obtain data from out database, I am having the following issue, I am using a dynamic window to display information as well as some buttons for date times, and close, etc...
However when I close the window and reopen it, it adds everything back to the form that was already there, which creates double and is causing some problems, any advice would be great, thanks in advance
Here is some code to better describe what I have....
This is the button I have on my primary form, which creates the new window
private void butMoreInf_Click(object sender, RoutedEventArgs e)
{
winMain.DataContext = null;
winMainContainer.DataContext = null;
winMainContainerLeft.DataContext = null;
winMainContainerRight.DataContext = null;
datGrid.DataContext = null;
//Generate the new window and panel to go within the window
winMain.Height = 750;
winMain.Width = 950;
winMainContainer.Width = 1000;
winMainContainer.HorizontalAlignment = HorizontalAlignment.Left;
winMainContainerLeft.Width = 120;
winMainContainerLeft.HorizontalAlignment = HorizontalAlignment.Left;
winMainContainerRight.Width = 880;
winMainContainerRight.HorizontalAlignment = HorizontalAlignment.Left;
//Generate the datagrid to contain the date to be changed etc.
datGrid.Margin = new Thickness(0, 12, 12, 12);
datGrid.HorizontalAlignment = HorizontalAlignment.Right;
//Generate a datepicker (start) and label
Label labS = new Label();
labS.Content = "Pick a start date";
labS.Width = 100;
labS.Margin = new Thickness(12, 1, 0, 1);
labS.HorizontalAlignment = HorizontalAlignment.Left;
DatePicker datPickStart = new DatePicker();
datPickStart.Width = 100;
datPickStart.Margin = new Thickness(12, 12, 1, 0);
datPickStart.HorizontalAlignment = HorizontalAlignment.Left;
datPickStart.SelectedDate = DateTime.Now.AddDays(-7);
datStartPick = datPickStart.SelectedDate == null ? DateTime.Now : Convert.ToDateTime(datPickStart.SelectedDate);
//Generate a datepicker (end) and label
Label labE = new Label();
labE.Content = "Pick an end date";
labE.Width = 100;
labE.Margin = new Thickness(12, 1, 0, 1);
labE.HorizontalAlignment = HorizontalAlignment.Left;
DatePicker datPickEnd = new DatePicker();
datPickEnd.Width = 100;
datPickEnd.Margin = new Thickness(12, 12, 1, 0);
datPickEnd.HorizontalAlignment = HorizontalAlignment.Left;
datPickEnd.SelectedDate = DateTime.Now;
datEndPick = datPickEnd.SelectedDate == null ? DateTime.Now : Convert.ToDateTime(datPickEnd.SelectedDate);
//Generate dropdown and label for that box
Label labY = new Label();
labY.Content = "";
labY.Width = 100;
labY.Margin = new Thickness(12, 1, 0, 1);
labY.HorizontalAlignment = HorizontalAlignment.Left;
ComboBox txtY = new ComboBox();
txtY.Width = 100;
txtY.Margin = new Thickness(12, 12, 1, 0);
txtY.HorizontalAlignment = HorizontalAlignment.Left;
txtY.SelectedIndex = 0;
txtY.SelectionChanged += CLLoadErrors;
txtY.SelectedIndex = 0;
//Generate error list button
Button butError = new Button();
butError.Width = 100;
butError.Margin = new Thickness(12, 12, 1, 0);
butError.HorizontalAlignment = HorizontalAlignment.Left;
butError.Content = "Get Errors";
butError.Click += CLLoadErrors;
//Generate clear button
Button butClear = new Button();
butClear.Width = 100;
butClear.Margin = new Thickness(12, 12, 1, 0);
butClear.HorizontalAlignment = HorizontalAlignment.Left;
butClear.Content = "Clear Grid";
butClear.Click += clearDataGrid;
//Generate close button
Button butClose = new Button();
butClose.Width = 100;
butClose.Margin = new Thickness(12, 12, 1, 0);
butClose.HorizontalAlignment = HorizontalAlignment.Left;
butClose.Content = "Close";
butClose.Click += CLHide;
//Add elements to the stackpanel / Also updates them before each instance
winMainContainerLeft.UpdateLayout();
winMainContainerLeft.Children.Add(labS);
winMainContainerLeft.Children.Add(datPickStart);
winMainContainerLeft.Children.Add(labE);
winMainContainerLeft.Children.Add(datPickEnd);
winMainContainerLeft.Children.Add(labY);
winMainContainerLeft.Children.Add(txtY);
winMainContainerLeft.Children.Add(butError);
winMainContainerLeft.Children.Add(butClear);
winMainContainerLeft.Children.Add(butClose);
winMainContainerRight.UpdateLayout();
winMainContainerRight.Children.Remove(datGrid);
winMainContainerRight.Children.Add(datGrid);
winMainContainer.UpdateLayout();
winMainContainer.Orientation = Orientation.Horizontal;
winMainContainer.Children.Remove(winMainContainerLeft);
winMainContainer.Children.Add(winMainContainerLeft);
winMainContainer.Children.Remove(winMainContainerRight);
winMainContainer.Children.Add(winMainContainerRight);
winMain.ResizeMode = ResizeMode.NoResize;
//Display the new form
winMain.UpdateLayout();
winMain.Content = winMainContainer;
winMain.Show();
datGrid.MouseDoubleClick += datGridDClick;
txtY.SelectionChanged += new SelectionChangedEventHandler(txtY_SelectionChanged);
}
Will provide more code if needed.
You are reusing the same window again and again (why?), so you need to clear out the children collections before you add new elements, otherwise every click on your button will show the window + every control you add, resulting in double/triple/... controls.
Update: I assume you use StackPanels (from your comment / having Children enumerations). The Children enumeration is a UIElementCollection which allows to invoke the Clear method. Just call this prior to adding new controls. (on winMainContainer, winMainContainerRight and winMainContainerLeft)
Where do you initialize winMain? Is it a static variable or does it live within your current form?
I'm guessing that you keep adding controls to an existing object(which causes the duplication effect). To fix this you could either reinitialize the form object
winMain = new WinMainForm();
or you could remove all controls on the winMain variable right before adding the new children
foreach(var c in winMainContainer.children){
winMainContainer.children.remove(c)
}
It looks like you aren't creating a new window at all, rather just performing operations on 'winMain' which exists at some higher scope. So every time you call the function you are just adding more and more children to the stackpanel.
You can solve the problem by doing something like this in the beginning of your method.
winMainContainerLeft.Clear();
winMainContainerRight.Clear();
winMainContainer.Children.Clear();
I also noticed that you have included the following lines in your example:
winMainContainer.Children.Remove(winMainContainerLeft);
winMainContainer.Children.Add(winMainContainerLeft);
winMainContainer.Children.Remove(winMainContainerRight);
winMainContainer.Children.Add(winMainContainerRight);
But you don't need to remove them before adding them (this doesn't really make sense anyway.)

Categories

Resources