Remove Rows from TableLayoutPanel [duplicate] - c#

I'm currently trying to fill a TableLayoutPanel through a method which goes as follows:
private int _rowCount;
public void InitPaths()
{
int c = 1;
int a = 1;
while (a < _PathRows.Length - 1)
{
var label = new Label();
//
// Label - Format.
//
label.Dock = DockStyle.Fill;
label.AutoSize = false;
label.Text = _pfadZeilen[a];
label.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
label.Size = new System.Drawing.Size(22, 13);
label.BackColor = System.Drawing.Color.Transparent;
TableLayoutP.Controls.Add(label, 3, c);
//Checkboxen Einfügen
var cbox = new CheckBox();
//
//Checkbox Format.
cbox.Anchor = System.Windows.Forms.AnchorStyles.None;
cbox.AutoSize = true;
cbox.CheckAlign = System.Drawing.ContentAlignment.MiddleCenter;
cbox.Name = "checkBoxPfad" + a;
cbox.Size = new System.Drawing.Size(15, 14);
cbox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
cbox.UseVisualStyleBackColor = true;
TableLayoutP.Controls.Add(cbox, 0, c);
a++;
c++;
}
this._rowCount = BibTable.GetRowHeights().Length; // which seems to be Holding the value only within the method
}
and then delete all rows on Action, through the following Method:
public void RemoveRows()
{
for (int row = _rowCount; row >= 0; row--)
{
BibTable.RowStyles.RemoveAt(row);
BibTable.RowCount--;
}
}
Now the Problem is, if I try to do anything with the TableLayoutP outside of the method where all rows are initialized, it will tell me:
Object reference not set to the instance of an object.
What can I do? Is there a way to get a method inside a method (I'm realising just how stupid that sounds while typing it) or any other way to deal with this Situation?

You are ittering through GetRowHeights(), returning the height of each row. But you are deleting from the RowStyles collection which is not directly related to the first collection. I assume that GetRowHeights() returns much more rows, than RowStyles has.
Why not:
BibTable.RowCount = 0;
BibTable.RowStyles.Clear();

You are ittering through GetRowHeights(), returning the height of each row. But you are deleting from the RowStyles collection which is not directly related to the first collection. I assume that GetRowHeights() returns much more rows, than RowStyles has.
Why not:
BibTable.RowCount = 0;
BibTable.RowStyles.Clear();

Related

C# : bool array is not updating during execution

i have this sample code which basically reads some string data from csv file and updates in textboxes and some variables.
The csv file is of the format 10,0,20,0,0,30,0..etc with 20 values. The idea is, if any of the value in csv file is 0, the isCashAvailable variable should be set to false and vice versa. Below is my code.
int[] cash = new int[20];
bool[] isCashAvailable = new bool[20];
public void UpdateCash()
{
var cashCSV = File.ReadAllText("cash.csv");
List<string> cashVal = cashCSV.Split(',').ToList();
for (int i = 1; i <= 20; i++)
{
var control = this.Controls.Find("textBox" + i.ToString(), true).FirstOrDefault() as TextBox;
if (cashVal[i - 1] != "0")
{
isCashAvailable[i - 1] = true;
control.Text = cashVal[i - 1];
cash[i - 1] = int.Parse(cashVal[i - 1]);
}
else
{
isCashAvailable[i - 1] = false;
control.Text = cashVal[i - 1];
cash[i - 1] = int.Parse(cashVal[i - 1]);
}
}
}
Now the issue is, when I try to update the value of the isCashAvailable and cash in runtime, its not updating. Whereas if am debugging it by stepping over each iteration, its updating. Can't seem to find why this is happening.
Try this:
int[] cash = new int[20];
bool[] isCashAvailable = new bool[20];
var cashCSV = File.ReadAllText("cash.csv");
List<string> cashVal = cashCSV.Split(',').ToList();
// changing this allows you to use i+1 just once, instead of doing i-1 over and over
for (int i = 0; i < 20; i++)
{
// this way it will throw an error if TextBox is not found instead of
// not throwing it here and then throwing NullReference later
var control = this.Controls.Find("textBox" + (i+1).ToString(), true).First() as TextBox;
//if-else is not needed here
//TryParse to make sure it always works
int.TryParse(cashVal[i], out cash[i]);
isCashAvailable[i] = (cash[i] > 0);
control.Text = cashVal[i];
//it works
Debug.Print($"{i}: isCashAvailable = {isCashAvailable[i]}, cashVal = {cashVal[i]}");
}

Fill an array with a loop

I want to get a shorter code than now but I don't know how.
What I do now is like the code below.
arrPictureBox[0] = picChair0;
arrPictureBox[1] = picChair1;
arrPictureBox[2] = picChair2;
arrPictureBox[3] = picChair3;
arrPictureBox[4] = picChair4;
arrPictureBox[5] = picChair5;
arrPictureBox[6] = picChair6;
arrPictureBox[7] = picChair7;
arrPictureBox[8] = picChair8;
arrPictureBox[9] = picChair9;
arrPictureBox[10] = picChair10;
arrPictureBox[11] = picChair11;
(pic) is a picturebox.
But I want less code but I don't know if it possible to do this with a loop (for loop).
for (int i = 0 ; i < arrPictureBox.Length; i++)
{
arrPictureBox[i] = picChair + i;
}
If picChairN is a local variable then there's nothing you can do to simplify it as much as you'd like. The best you can do is
arrPictureBox = new [] { picChair0, picChair1, picChair2, picChair3,
picChair4, picChair5, picChair6, picChair7,
picChair8, picChair9, picChair10, picChair11};
If picChairN is a class member (e.g. a field created by the designer) then you could use reflection, but considering you already have the array method typed out I don't see much benefit.
Let's predict you're on WinForms and the pictureBoxes already exist, then you can use the following:
for (int i = 0; i < arrPictureBox.Length; i++)
{
arrPictureBox[i] = this.Controls["picChair" + i];
}
Which actually does this:
get the first Control (a PictureBox for example) with the given name
add the found control to the array of pictureboxes
EDIT:
It might be useful to check for non existing pictureBoxes:
for (int i = 0 ; i < arrPictureBox.Length; i++)
{
var pb = this.Controls["picChair" + i] as PictureBox;
if (pb != null)
{
arrPictureBox[i] = pb;
}
}
You can use al List like below.
List<string> arrPictureBox = new List<string>();
for (int i = 0; i < 20; i++)
{
arrPictureBox.Add("picChair" + i);
}
var result = arrPictureBox.ToArray();
Hope it helps.
If all the picture boxes are on the same form and are the ONLY picture boxes on the form, you can loop through them with something like the following:
int x = 0;
foreach(Control c in this.Controls)
{
if(c is PictureBox)
{
arrPictureBox[x++] = c
}
}

Access / update textbox value after creating it on runtime

I'm creating multiple textboxes at runtime. The problem is that I cannot seem to update their value individually after rendering on runtime. The textbox.text always ends up showing its initial text ("Hello") in the GUI rather than what I want to show after changing it ("World"):
public Dictionary<int,TextBox> txtbx123dictionary = new Dictionary<int,TextBox>
public void LoadParameters()
{
DataSet ds = new DataSet();
ds = GetParameters();
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
paramtxtbx = new System.Windows.Forms.TextBox();
txtbx123dictionary.Add(i, paramtxtbx);
txtbx123dictionary.ElementAt(i).Value.Text = "Hello"
txtbx123dictionary.ElementAt(i).Value.Name = "TextBox" + i.ToString();
txtbx123dictionary.ElementAt(i).Value.Location = new System.Drawing.Point(320, (i * 25));
txtbx123dictionary.ElementAt(i).Value.Size = new System.Drawing.Size(150, 20);
txtbx123dictionary.ElementAt(i).Value.Visible = true;
panel123.Controls.Add(paramdict.ElementAt(i).Value);
//panel123.Add(i, paramtxtbx);
}
}
public void function()
{
LoadParameters();
for (int i = 0; i < txtbx123dictionary.Count(); i++)
{
txtbx123dictionary.ElementAt(i).Value.Text = "World";
txtbx123dictionary.ElementAt(i).Value.Update();
panel123.Update();
}
}
e.g I need to change the textbox.text to "World" but when running the code the text box keeps on showing "Hello".
Help would be appreciated. Thanks.
txtbx123dictionary.ElementAt(i) not the same as txtbx123dictionary[i]
ElementAt(i) is extensions method from IEnumerable<T>
You add TextBox to the dictionary by key i then try it get by index i.

Verify which dynamically created Radiobutton is checked in C#

I am developing an application with multiple Panels (eight, to be precise) on one Form. In each Panel there are one TableLayoutPanel with three Radiobuttons (among of few other unimportant components). The Radiobuttons set the priority of the specific Panel's input (Priority 1, 2 and 3).
I have no intention of placing three Radiobuttons on each of the eight Panels as I believe there are more effective ways of doing this. Below is the code used to place the Radiobuttons:
private void AddPriorityRadBtn(TableLayoutPanel lLayoutTable, int lTableLayoutColumn, int lTableLayoutRow)
{
int lPriority = -1;
try
{
for (int i = lTableLayoutRow; i < (lTableLayoutRow+ 3); i++)
{
RadioButton lRadBtn = new RadioButton();
lPriority = i - lLayTblStRow + 1;
lRadBtn.Name = "radP_" + lPriority.ToString();
lRadBtn.Text = "Priority Level " + lPriority.ToString();
lRadBtn.Anchor = AnchorStyles.Left;
lLayoutTable.Controls.Add(lRadBtn);
if (lPriority < 3)
{
lRadBtn.Checked = false;
}
else if(lPriority == 3)
{
lRadBtn.Checked = true;
}
lTableLayout.Controls.Add(lRadBtn, lTableLayoutColumn, i);
}
}
catch
{
Console.WriteLine(ex);
}
}
The lTableLayoutColumn and lTableLayoutRow are used to set the column in which the Radiobuttons are placed. lPriority are used to calculate the Priority of the button and always has a value from 1 to 3.
I can add the Radiobuttons with the above code. I suspect this is where the problem is.
The next piece of code is where the problem becomes more evident:
private int GetSelectedRadioBtn()
{
RadioButton lRadBtnPriority = new RadioButton();
try
{
for (int i = 1; i < 4; i++)
{
lRadBtnPriority.Name = "radP_" + i.ToString();
if (lRadBtnPriority.Checked == true)
{
return i;
}
}
return -1;
}
catch (Exception ex)
{
return -1;
}
}
This function always returns -1 from the try block. Thus my application can't see which one of the Radiobuttons is selected.
What would be the reason for this? Any kind of help would be much appreciated.
Your GetSelectedRadioBtn() creates its own radio button how is it supposed to be linked to the previous buttons?
lRadBtnPriority.Name = "radP_" + i.ToString();
doing this doesnt magicly link your new button to the previusly created ones.
One way of doing what you want to do is subscribing a checkedChanged event to the radio buttons and changing a global variable called selectedRadio.
for (int i = lTableLayoutRow; i < (lTableLayoutRow+ 3); i++)
{
RadioButton lRadBtn = new RadioButton();
lPriority = i - lLayTblStRow + 1;
lRadBtn.Name = "radP_" + lPriority.ToString();
lRadBtn.Text = "Priority Level " + lPriority.ToString();
lRadBtn.Anchor = AnchorStyles.Left;
lRadBtn.Tag = i;
lRadBtn.CheckedChanged +=(ss,ee)=>{
selectedRadio = (int)((RadioButton)ss).Tag;
};
lLayoutTable.Controls.Add(lRadBtn);
if (lPriority < 3)
{
lRadBtn.Checked = false;
}
else if(lPriority == 3)
{
lRadBtn.Checked = true;
}
lTableLayout.Controls.Add(lRadBtn, lTableLayoutColumn, i);
}
then in GetSelectedRadioBtn you do this
private int GetSelectedRadioBtn()
{
return selectedRadio;
}
The easiest way to do it is to store a reference to the radio buttons created in the AddPriorityRadBtn. You can keep them for example, in a dictionary which uses the Panel as key, and the three radio buttons in an array.
Then, you just have to look at the dictionary to recover the radio buttons and check its state.

Creating automatic labels in form to display value from database

Was trying out a simple FB API app to retrieve status.
So what i am intending to do is to perform a word check with my dictionary.
I have a database which stores emotive data on the feeling % and the genre of the feeling.
If the status contains the emotive word, i wish to perform a word analysis.
For instance: "I am feeling sad and angry"
So what i want it to display is like...
"Username"
was feeling
50% angry
and 25% sad.
*% is calculated by random function.
However, i think its impossible for me to keep creating labels. What if my status has > 5 emotions? Is it possible to create automatic labels which would display the output?
Below is my code:
private void EmotionAnalysis_Load(object sender, EventArgs e)
{
label1.Text = tpc.loadInfo(currentId)["target_name"].ToString();
//List<DataRow> result = dict.AngerPercent(fbStatus);
CalculateAndDisplayAnalysis("Angry", topPercentLabel, topFeelingLabel);
CalculateAndDisplayAnalysis("Caring", bottomPercentLabel, bottomFeelingLabel);
//var item = new ListViewItem(new[] { "", String.Format("{0}%", percent.ToString()), result[0]["Genre"].ToString() });
//listViewEmotion.Items.Add(item);
}
private void CalculateAndDisplayAnalysis(string genre, Label percentLabel, Label feelingLabel)
{
List<DataRow> result = dict.GenrePercent(fbStatus, genre);
var rnd = new Random();
int total = 0;
for (int i = 0; i < result.Count; i++)
{
total += rnd.Next(Convert.ToInt32(result[i]["Min_Percentage"]), Convert.ToInt32(result[i]["Max_Percentage"]));
}
if (result.Count != 0)
{
int percent = total / result.Count;
percentLabel.Text = String.Format("{0}%", percent.ToString());
feelingLabel.Text = result[0]["Genre"].ToString();
}
}
You can create as many labels as you want. you just need to set the position of the label and add it to the forms Controls enumeration:
Label lbl = new Label();
lbl.Text = "MyText";
lbl.Location = new Position(xPos, yPos);
this.Controls.Add(lbl);
You will have to keep track of the new position which is in this case determined by xPos and yPos

Categories