c# adding checkboxes to panle wierd behavior - c#

i got a Class called AdvancePanle that drived from Panle, and i got a class call AdvnaceCheckBox that drived from CheckBox.
I created a AdvancePanle in my Form, and now i want to add some AdvnaceCheckBox's to it.
so i created this, simple method:
private void addCheckBox()
{
AdvancedCheckBox checkbox;
for (int i = 0; i < 10; i++)
{
checkbox = new AdvancedCheckBox();
checkbox.Location = new Point(0, i + 5);
checkbox.Text = "bla" + i;
selectablePanel1.Controls.Add(checkbox);
}
}
and i call this method in the Form onLoad:
protected override void OnLoad(EventArgs e)
{
addCheckBox();
selectablePanel1.AutoScroll = true;
base.OnLoad(e);
}
but afther the Form is opened, I can see only 1 CheckBox in the Panle.
i tried playing with the position, but i alwys see only 1 checkbox.
am I adding the CheckBoxs in a worng way?
(sorry for my english)

You're placing them too close to each other. (0, 5+i) will evaluate to:
(0,5)
(0,6)
(0,7)
(0,8)
...
Try this instead:
checkbox.Location = new Point(0, i*100 + 5);
or this:
checkbox.Location = new Point(0, i*checkbox.Height + 5);

Related

How to create MaterialSingleLineTextField Controls dynamically

I would like to add MaterialSingleLineTextField dynamically to a Form.
I have used MaterialSkin NuGet package:
I am trying to create multiple MaterialSkin TextBoxes dynamically on Form.Load. But no Controls are displaying in the hosing Panel.
private void Form1_Load(object sender, EventArgs e)
{
int n = 5;
int pointX = 30;
int pointY = 40;
//panel1.Controls.Clear();
for (int i = 0; i < n - 1; i++)
{
MaterialSingleLineTextField a = new MaterialSingleLineTextField();
a.Text = (i + 1).ToString();
a.Visible = true;
a.Location = new Point(pointX, pointY);
panel1.Controls.Add(a);
panel1.Show();
pointY += 20;
}
}
This code block works perfectly fine for normal TextBoxes.
Is there any way to add MaterialSingleLineTextField dynamically?
A sample Form initialization with default Theme values.
The MaterialSkinManager is initialized in the Form Constructor, setting the Theme to MaterialSkinManager.Themes.LIGHT and default color scheme. The Form base Type is set to MaterialForm.
A specified number of MaterialSingleLineTextField controls is added to a parent container (a Panel), starting from a defined Location downwards.
These Controls are anchored to the parent and the Height is set to Parent.Font.Height + 4.
It's important that you specify the Size of these Controls, otherwise you'll get a minimal size that prevents the Controls from showing their content.
As you can see in the AddTextFields() method, it's important that you dispose of the previous Controls added to the Parent container, if you want to replace the existing with new ones. Even more important using this Library.
Calling the Clear() method of a Control.Controls collection (as in the line you have commented out) doesn't dispose of anything, those controls are still alive.
public partial class Form1 : MaterialForm
{
private readonly MaterialSkinManager msManager = null;
public Form1()
{
InitializeComponent();
msManager = MaterialSkinManager.Instance;
msManager.AddFormToManage(this);
msManager.Theme = MaterialSkinManager.Themes.LIGHT;
}
private void Form1_Load(object sender, EventArgs e)
{
AddTextFields(panel1, 5, new Point(30, 10), false);
}
private void AddTextFields(Control parent, int controlsCount, Point startPosition, bool ClearExisting)
{
if (clearExisting && parent.Controls.Count > 0) {
for (int i = parent.Controls.Count - 1; i >= 0; i--) {
parent.Controls[i].Dispose();
}
}
int controlHeight = parent.Font.Height + 4;
int yIncrement = 0;
for (int i = 0; i < controlsCount; i++) {
var textField = new MaterialSingleLineTextField() {
Text = (i + 1).ToString(),
Size = new Size(parent.ClientSize.Width - startPosition.X - 4, controlHeight),
Location = new Point(startPosition.X, startPosition.Y + yIncrement),
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right
};
parent.Controls.Add(textField);
yIncrement += (controlHeight + 10);
}
}
private void matBtnChangeTheme_Click(object sender, EventArgs e)
{
msManager.Theme = MaterialSkinManager.Themes.DARK;
msManager.ColorScheme = new ColorScheme(Primary.Blue600, Primary.Blue900, Primary.Blue500, Accent.LightBlue200, TextShade.WHITE);
}
private void matBtnAddControls_Click(object sender, EventArgs e)
{
AddTextFields(panel1, 7, new Point(30, 10), true);
}
}
Sample functionality:

How can I retrieve the input values of dynamically created textfields?

Here is my code so far where I have a numericupdown item named numericUpDown and button. Once the user selects a number when they press the button it dynamically created the fields.
private void createPerson_Click(object sender, EventArgs e)
{
Label[] person_Name = new Label[(int)this.numericUpDown.Value];
TextBox[] person_txtinput = new TextBox[(int)this.numericUpDown.Value];
for (int i = 0; i < this.numericUpDown.Value; i++)
{
//create person name label
Person_Name[i] = new Label();
Person_Name[i].Location = new System.Drawing.Point(20, 114 + i * 25);
Person_Name[i].Size = new System.Drawing.Size(120, 15);
Person_Name[i].Text = (i + 1).ToString() + #")" + "Person Name:";
this.Controls.Add(Person_Name[i]);
//create person name textbox
PersonNameTxtInput[i] = new TextBox();
PersonNameTxtInput[i].Location = new System.Drawing.Point(140, 114 + i * 25);
PersonNameTxtInput[i].Size = new System.Drawing.Size(125, 20);
this.Controls.Add(PersonNameTxtInput[i]);
}
}
private void save_Click(object sender, EventArgs e)
{
for (int i = 0; j < this.numericUpDown.Value; i++)
{
MessageBox.Show("" + PersonNameTxtInput[i].Text);
}
}
My question is, how can I get all the values from the textboxes depending on how many fields are created by the user when the save button is pressed?
I have tried using the code within the save button listener however how can i make Label[] person_Name = new Label[(int)this.numericUpDown.Value]; a global variable so i can access it within the save button for loop.
Well, I don't know exactly why you are doing this in this particular way and I must admit it doesn't seem very effective, but you could just do what Ryan_L suggested and iterate through this.Controls like this
for(int i = 0; i < this.Controls.Count; i++)
{
if(this.Controls[i] is TextBox) //skip buttons and labels
{
MessageBox.Show("" + this.Controls[i].Text);
}
}
Now, regarding your question how to define a global variable so you can access it within the save button for loop...just define the two arrays outside of the createPerson_Click event like this:
Label[] person_Name;
TextBox[] person_txtinput;
private void button1_Click(object sender, EventArgs e)
{
person_Name = new Label[(int)this.numericUpDown.Value];
person_txtinput = new TextBox[(int)this.numericUpDown.Value];
//the rest of the code
}
Hope this helps. However, you might want to reconsider your entire approach.

Position buttons in control array

I'm trying to recall the buttons I created and position them on arrays that hold its location but FindControl gives Error.
'Form1' does not contain a definition for 'FindControl' and no extension method
'FindControl' accepting a first argument of type 'Form1' could be found (are you missing
a using directive or an assembly reference?)
My code is under a timer1.
private void timer1_Tick(object sender, EventArgs e)
{
...
if ...
{
...
Button btn = new Button();
{
btn.Name = "Btn-" + tail.ToString();
btn.Height = 10;
btn.Width = 10;
btn.Tag = tail+1;
btn.Location = new Point((stailX[1]-1)*10, (stailY[1] - 1) * 10);
}
this.Controls.Add(btn);
}
...
for (int i = 1; i <= tail; i++)
{
((Button)this.FindControl("Btn-" + tail.ToString())).Location = new Point((stailX[i] - 1) * 10, (stailY[i] - 1) * 10);
}
}
I've omitted parts of code not important. Please help.
My approach would include putting the controls in an array or a list for easy access later. Here is an example:
public partial class Form1 : Form
{
List<Button> buttonList = new List<Button>();
int i = 0;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
i++;
Button btn = new Button();
btn.Location = new Point(20 , i* 30);
buttonList.Add(btn); // add instance to list
this.Controls.Add(btn); // add the same instance to the form
for (int j = 0; j < buttonList.Count; ++j)
{
// do whatever you want here
buttonList[j].Text = j.ToString();
}
}
}
This way you don't need to find the control you want on every iteration.
I think you can achieve the same, by iterating through each controls in the form using this.Controls, and can be more specifically by filtering them using .OfType<Button>(). To make sure that those controls are dynamically created with specific Ids you can add the conditions as well. The code for this will looks like the following:
int i = 1;
foreach (Button childButton in this.Controls.OfType<Button>())
{
if (childButton.Name.StartsWith("Btn-"))
{
childButton.Location = new Point((stailX[i] - 1) * 10, (stailY[i] - 1) * 10);
}
i++;
}
Hope that it will help you
How about Controls.Find("controlname", true)

Array of buttons: change property

I have an array of buttons, like this:
int x = 0, y = 0;
butt2 = new Button[100];
for (int i = 0; i < 100; i++)
{
butt2[i] = new Button();
int names = i;
butt2[i].Name = "b2" + names.ToString();
butt2[i].Location = new Point(525 + (x * 31), 70 + (y * 21));
butt2[i].Visible = true;
butt2[i].Size = new Size(30, 20);
butt2[i].Click += new EventHandler(butt2_2_Click); //problem lies here (1)
this.Controls.Add(butt2[i]);
}
private void butt2_2_Click(object sender, EventArgs e)
{
// want code here
}
I want to change the back color of the button when clicked. I was thinking of passing i to be able to do this:
butt2[i].BackColor = Color.Green;
This should do the trick:
private void butt2_2_Click(object sender, EventArgs e)
{
Button pushedBtn = sender as Button;
if(pushedBtn != null)
{
pushedBtn.BackColor = Color.Green;
}
}
And this holds for most UI events, the 'object sender' parameter refers to the control that 'sent'/'fired' the event.
To learn more about C# event handling, I would start here.
Also, here is a SO question about GUI event handling, answered nicely by Juliet (accepted answer).
Hope this helps.

Referencing a newly created control

If i create a control on the fly, as below
private void button10_Click(object sender, EventArgs e)
{
CheckedListBox CheckedListBox1 = new CheckedListBox();
CheckedListBox1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(224)), ((System.Byte)(192)));
CheckedListBox1.ItemHeight = 16;
CheckedListBox1.Location = new System.Drawing.Point(12, 313);
CheckedListBox1.Name = "CheckedListBox1";
CheckedListBox1.Size = new System.Drawing.Size(168, 244);
CheckedListBox1.TabIndex = 0;
Controls.Add(CheckedListBox1);
Button button12 = new Button();
button12.Location = new Point(900, 500);
button12.Size = new Size(75, 23);
button12.Click += new System.EventHandler(button12_Click);
button12.Name = "button12";
button12.Text = "Toggle All";
Controls.Add(button12);
}
what is the best way to reference that control from a function outside of the local scope? would it be best creating a static class to somehow hold a reference to the control that can be accessed outside the local scope or is there a findcontrol function for winforms ( i think findcontrol is just for web).
i want
private void button12_Click(object sender, EventArgs e)
{
for (int i = 0; i <= (CheckedListBox1.Items.Count - 1); i++)
{
if (CheckedListBox1.GetItemCheckState(i) == CheckState.Checked)
{
CheckedListBox1.SetItemCheckState(i, CheckState.Indeterminate);
}
else if (CheckedListBox1.GetItemCheckState(i) == CheckState.Indeterminate)
{
CheckedListBox1.SetItemCheckState(i, CheckState.Checked);
}
}
}
to be able to work but im going wrong because of scope? pls help a newbie
thanks
I'm assuming the two functions button12_Click and button10_Click are members of a From class. In this case, your should make your CheckListBox1 and button12 members of the From class. That way, the button12_Click will be able to reference the controls you will have created.
public partial class Form1 : Form
{
CheckedListBox CheckedListBox1 = null;
Button button12 = null;
private void button10_Click(object sender, EventArgs e)
{
CheckedListBox1 = new CheckedListBox();
CheckedListBox1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(224)), ((System.Byte)(192)));
CheckedListBox1.ItemHeight = 16;
CheckedListBox1.Location = new System.Drawing.Point(12, 313);
CheckedListBox1.Name = "CheckedListBox1";
CheckedListBox1.Size = new System.Drawing.Size(168, 244);
CheckedListBox1.TabIndex = 0;
Controls.Add(CheckedListBox1);
button12 = new Button();
button12.Location = new Point(900, 500);
button12.Size = new Size(75, 23);
button12.Click += new System.EventHandler(button12_Click);
button12.Name = "button12";
button12.Text = "Toggle All";
Controls.Add(button12);
}
private void button12_Click(object sender, EventArgs e)
{
for (int i = 0; i <= (CheckedListBox1.Items.Count - 1); i++)
{
if (CheckedListBox1.GetItemCheckState(i) == CheckState.Checked)
{
CheckedListBox1.SetItemCheckState(i, CheckState.Indeterminate);
}
else if (CheckedListBox1.GetItemCheckState(i) == CheckState.Indeterminate)
{
CheckedListBox1.SetItemCheckState(i, CheckState.Checked);
}
}
}
}
When there is only one CheckedListBox make it a class variable. But when you have always only one CheckedListBox - why do you create it dynamically?
If you're adding the controls to the page's Controls collection, just go look there. If you know the index of the control you can reference it that way. if you're adding the control to some container's Control's collection (say, a panel), look for it there

Categories

Resources