I'm not sure if the title is correct because I wasn't sure how to explain it. I've encountered many scenarios where being able to dynamically modify part of a variable name such a suffixing integer could save me a great deal of time and keep my code much cleaner but I'm not sure how to do it. Here's an example of my most recent encounter.
I have 9 PictureBox's in a 3 x 3 grid. Each PictureBox has a name of cell followed by it's number so cell1, cell2, cell3 etc. I want to get the background colour of each of these cells and assign them to a variable whilst converting them to strings... something like this:
for (int i = 1; i < 10; i++)
{
string ci = celli.BackColor.ToString();
}
Is there a way I can have the i variable insert only it's numeric value to the placeholder rather than appending an i to the variable name? Can I wrap it in some sort of bracket? I've tried Googleing this but I'm finding it difficult to search for using just keywords.
Thanks in advance.
You are probably using a visual form editor, the best way to do this whould probably be to generate the grid by code (and not visually).
Another solution is to make it a matrix:
PictureBox[,] cell = new PictureBox[,] {
{ cell1, cell2, cell3 },
{ cell4, cell5, cell6 },
{ cell7, cell8, cell9 }
};
string[,] c = new string[3, 3];
for(int y=0; y<3; y++)
for(int x=0; x<3; x++)
c[x, y] = cell[x, y].BackColor.ToString();
Good luck with your code.
You would like to generate a list or collection of all your pictureboxes so that you can access them by specifying their index. One way is to generate the PictureBoxes on runtime:
Like this:
List<PictureBox> myPics = new List<PictureBox>();
int picWidth = 100;
int picHeight = 100;
for (x = 0; x <= this.Width; x += picWidth) {
for (y = 0; y <= this.Height; y += picHeight) {
PictureBox pic = new PictureBox();
pic.Image = pic.Image;
// Your image
pic.Location = new Point(x, y);
this.Controls.Add(pic);
myPics.Add(pic);
}
}
// Do something with myPics...
The other method is that when you do have all the pictureboxes on your form already, you can iterate through all the controls, check which ones are pictureboxes and then check their Name property to identify their index. Then do something with them accordingly.
foreach (void ctrl_loopVariable in this.Controls) {
ctrl = ctrl_loopVariable;
if (ctrl.GetType() == typeof(PictureBox)) {
if (ctrl.Name == "your picture box name to test") {
// Do something here with ctrl
}
}
}
(The above code is converted from VB to C#, excuse conversion issues)
Your intend here is to dynamically reference those controls.
In order to achieve this, there is two options:
You create those controls dynamically
You create dynamic references for the controls created by your form-designer
The first point is explained ny Shreyas Kapur's answer.
The second could be cone like this,
readonly Dictionary<Point,PictureBox> _dynamicMappedBoxes =
new Dictionary<Point,PictureBox>();
// Call this once in the beginning ofr your program
void createDynamicMapping()
{
foreach(PictureBox box in Controls.OfType<PictureBox>())
{
Point coords = getCoordinatesFromName(box);
_dynamicMappedBoxes.Add(coords, box);
}
}
Point getCoordinatesFromName(PictrueBox box)
{
int x = int.Parse(box.Name.SubString(IdontKnow);
int y = int.Parse(box.Name.SubString(IdontKnow);
retrun new Point(x,y);
}
//usage
string colorName = dynamicMappedBoxes[new Point(x,y)].BackColor.ToString();
Related
So, we have a way to dynamically create an array of x by y of texboxes to input values into it to later on do some matrix calculation, like determine the rank of the matrix.
To generate the array we use this:
protected void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < LinhaText; row++)
{
List<TextBox> newLin = new List<TextBox>();
textboxes.Add(newLin);
for (int col = 0; col < ColunText; col++)
{
TextBox newbox = new TextBox();
newbox.Width = textboxWidth;
newbox.Height = textboxHeight;
newbox.Top = (row * (textboxHeight + spacing)) + spacing + vOffset;
newbox.Left = (col * (textboxWidth + spacing)) + spacing + hOffset;
newLin.Add(newbox);
this.Controls.Add(newbox);
}
}
}
This stands on the second form, as in the first one we input the dimensions of the array. When we input the values on the textboxes they should get sent to the third form to get used by the other calculations.
We are wondering how we grab the values and send them to the other form to later on display the results.
Any further information you need, just ask!
I'm assuming that these are not modal windows and that the user can switch between them at any point? If that is the case then I would suggest using a design pattern like MVC or MVVM, separating your data, view, and control logic. By keeping the data layer distinct from the view, you can have all of your windows (views) share the same underlying data. Of course, you'll want to use events to notify the various windows of when the data is changed (see the INotifyPropertyChanged Interface).
I would not pass around textboxes, instead store the numbers in a 2-dimensional array (matrix). Also I would use binding to automatically bind the matrix values to the textboxes. To make binding work, you need a helper class containing your values, because binding needs to bind to a property.
private class Data // Can be a nested private class in Form2.
{
public double Value { get; set; }
public override string ToString() => Value.ToString(); // Not strictly necessary, but
// makes debugging easier.
}
We create a _matrix field as well as a property converting this Data[,] matrix to a double[,] matrix and returning it (in Form2):
private Data[,] _matrix;
public double[,] Matrix
{
get {
var m = new double[LinhaText, ColunText];
for (int row = 0; row < LinhaText; row++) {
for (int col = 0; col < ColunText; col++) {
m[row, col] = _matrix[row, col].Value;
}
}
return m;
}
}
Now create the textboxes and bind them to a Data object (In Form2_Load or in the form constructor after InitializeComponent):
_matrix = new Data[LinhaText, ColunText];
for (int row = 0; row < LinhaText; row++) {
for (int col = 0; col < ColunText; col++) {
var newbox = new TextBox {
Width = textboxWidth,
Height = textboxHeight,
Top = (row * (textboxHeight + spacing)) + spacing + vOffset,
Left = (col * (textboxWidth + spacing)) + spacing + hOffset
};
// Create Data object, add it to the matrix and bind it to the TextBox.
var data = new Data();
_matrix[row, col] = data;
newbox.DataBindings.Add(new Binding("Text", data, "Value", true));
Controls.Add(newbox);
}
}
Note that binding works two way. If you initialize the matrix with numbers, they will be displayed in the textboxes when opening the form. Numbers entered in textboxes will be stored in the matrix.
Now, on the other form, you need a reference to this form. Then you can get the matrix with
double[,] matrix = frmMartixInput.Matrix;
If you have difficulties passing around form references, then use a static property in a static class for the matrix, that can be referenced by all the forms.
public static class Globals
{
public static double[,] Matrix { get; set; }
}
You can also pass data to a form through constructor parameters (either a reference to another form or the matrix itself).
I'm working on a program that functions as a carpark simulator. I want the user interface to display how many spaces are available on each level at any given time. I've attempted to do this using listboxes (one for level number, one for number of spaces on that level), but can't get it to work. For some reason, the listbox that displays the spaces available (listboxSA) always comes up blank and I have no idea why.
The code that creates the listboxes is shown below:
public void updateLevelLabels(Simulator simulator)
{
//constant integers used for label positioning
//y coordinate for first label
const int YSTARTPOINT = 12;
//x coordinate for all labels
const int XSTARTPOINT = 104;
//create new listbox to show level IDs
ListBox listboxLevels = new ListBox();
//position listbox on form
//constant x-coordinate
listboxLevels.Left = XSTARTPOINT;
//constant y-coordinate
listboxLevels.Top = YSTARTPOINT;
//auto-assumes size depending on content
listboxLevels.AutoSize = true;
//create new listbox to show spaces available
ListBox listboxSA = new ListBox();
//set x and y coordinates
//constant x coordinate
listboxSA.Left = XSTARTPOINT + 38;
//constant y coordinate
listboxSA.Top = YSTARTPOINT;
//auto-resizes depending on content
listboxSA.AutoSize = true;
//populate listboxes
for (int i = 0; i < Length(); i++)
{
//identify level at current index
Level lev = At(i);
//add level unique ID to list
listboxLevels.Items.Add(lev.getLevelID());
//add number of spaces (available) on level to list
listboxSA.Items.Add(lev.getNumSpaces().ToString());
}
//place listboxes on form
simulator.Controls.Add(listboxLevels);
simulator.Controls.Add(listboxSA);
}
I've debugged the code and the value for the lev.numSpaces variable is what I'd expect it to be. I've also tried to select the indices of the listboxSA after it's creation and the created indices are selectable (listbox item becomes highlighted), but there is still no text in them.
I honestly have no idea what could be causing this to happen, especially weird considering the same procedure is essentially carried out on both listboxes with a differe get() function.
If anyone can spot what might be throwing it off, I'd really appreciate any advice!
Code of called functions called shown below:
//from `Levels` class
//Levels acts as a public interface for a `List<Level>`
public int Length()
{
//return number of `Level` instances in collection (int)
return levelList.Count;
}
//from `Level` class
//obtain unique identifer of level
public string getLevelID()
{
//return unique Level name
return levelID;
}
//from `Level` class
//obtain number of spaces on level
//all spaces assumed to be free
public int getNumSpaces()
{
//should = value of Levels.Length()
return numSpaces;
}
Thanks in advance,
Mark
You should better check data which you are trying to apply to listbox or seek problem in other place. I made test which is doing the same as your code and there is no problem.
string[] stringArray = new string[] { "one", "two", "three", "four" };
int[] intArray = new int[] { 1, 2, 3, 4 };
private void Addlistboxes()
{
ListBox lb1 = new ListBox();
ListBox lb2 = new ListBox();
lb1.Left = 10;
lb1.Top = 60;
lb1.AutoSize = true;
lb2.Left = 15 + lb1.Width;
lb2.Top = 60;
lb2.AutoSize = true;
for (int i = 0; i < 4; i++)
{
lb1.Items.Add(stringArray[i]);
lb2.Items.Add(intArray[i]);
}
this.Controls.Add(lb1);
this.Controls.Add(lb2);
}`
1st of all I will show my code, its very simple.
FileStream fs = new FileStream("Stock.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);
string line = "";
string[] Produtos = new string[] { };
int count = 1;
int i = 0;
int x = 25;
int y = 25;
while ((line = sr.ReadLine()) != null)
{
if (!string.IsNullOrEmpty(line))
{
ListagemProdutos myPanel = new ListagemProdutos();
myPanel.Location = new Point(x, y);
this.Controls.Add(myPanel);
y = y + 25;
x = x + 25;
i++;
}
}
Now the problem is, every time I get a line != null, it means I have a product which I will display like this
ProductName ProductPrice ProductQuantity Picture
That is what the usercontrol has, just 3 labels and a picturebox, then I want to call it and fill it until the end of my file. The code works perfect with only a MAIN problem since I'm declaring the instance like this
ListagemProdutos myPanel = new ListagemProdutos();
I think he is overwriting , and instead getting lets say I have 5 products get 5 rows (5 times the user control) I only get the last line.. I think I should do it something like this mypanel+[i] ,so it would be mypanel1,mypanel2 but I am not getting the way to do it, cause we can't just do
ListagemProdutos myPanel+[i] = new ListagemProdutos();
Thank you all for reading this, and sorry for any grammar errors hope you could understand anyway!
EDIT: This is a print showing my problem, in a simpler way. Why I can't have 2 or more instances of my user control? why only shows only 1 always?
http://epvpimg.com/Be8tc
Romero, Instead incrementing both x & y axis at the end of the foreach loop, increment only y axis. May be your control is going out of the window area.
Just a suggestion, adding control the way you are attempting could be cumbersome instead try using a grid control and add new rows to it with desired values.
This question already has answers here:
Loop through Textboxes
(12 answers)
Closed 8 years ago.
I have a form with a tabbed control (5 tabs) and on one tab I have 10 picture boxes, named pic1, pic, pic3 and so on. In VBA it is possible to loop through the controls using something like this:
For i = 1 To 10
Me.Controls("Img" & i).Picture = Me.cboProperty.Column(i)
Next
At the moment I have
this.pic1.DataBindings.Add("ImageLocation", this.mainTableBindingSource, "localPic1");
this.pic2.DataBindings.Add("ImageLocation", this.mainTableBindingSource, "localPic2");
this.pic3.DataBindings.Add("ImageLocation", this.mainTableBindingSource, "localPic3");
until 10, but surely there is a better way?
Like that, no. Normally, you would acceess a group of controls like this:
foreach (var pictureBox in PictureTab.Controls.OfType(Of PictureBox)())
{
pictureBox.Picture = //...
}
Of course, the trick here is that there is no index, to know which column to look at. But that's easy enough to get around:
int i = 0;
foreach (var pictureBox in PictureTab.Controls.OfType<PictureBox>())
{
pictureBox.Picture = cboProperty.Column[i];
i++;
}
Based on your edit, you may want this:
int i = 0;
foreach(var pictureBox in PictureTab.Controls.OfType<PictureBox>())
{
picutreBox.DataBindings.Add("ImageLocation", mainTableBindingSource, string.Format("loalPic{0}", i));
i++;
}
Perhaps something like this:
var pictureBoxes = this.Controls.OfType<PictureBox>().ToList();
for (int i = 0; i < pictureBoxes.Count; i++) {
pictureBoxes[i].DataBindings.Add("ImageLocation",
this.mainTableBindingSource,
"localPic" + (i + 1).ToString());
}
You can Search for the name of the pictureBox in form controls and loop increasing the value of each like Pic1, Pic2, etc.
for (int a = 1; a <= 10; a++)
{
string name = "pic" + a;
PictureBox pic = (PictureBox)(this.Controls.Find(name, true))[0];
pic.DataBindings.Add("ImageLocation", this.mainTableBindingSource, "localPic3");
}
iterate through all form controls
List<Control> lstOfControls = new List<Contol>();
public void AllPictureControls(Control control, bool enabled)
{
foreach(Control child in control.Controls)
{
if(child.Name.StartsWith("pic"))
{
lstOfControls.Add(control);
}
}
}
Put references of all your picture controls into a data structure, e.g. an array, and iterate over them.
Something similar to:
PictureBox[] picBoxArray = new PictureBox[50];
// 50 iterations for 50 object instantiations.
for (int i=0; i<picBoxArray.Length; i++) {
// create an pictureBox instance.
picBoxArray[i] = new PictureBox();
}
PictureBox pb = null;
// 50 iterations for calling methods on each of the 50 objects.
for (int i=0; i<picBoxArray.Length; i++) {
pb = picBoxArray[i];
// do something with the picturebox e.g. pb.SetPicture(...)
}
I am new to C#.I have been thinking of adding a ButtonControlArray where i can store each button control.Here is part of my code.I am creating a 6*6 array of button Control.
ButtonControl buttonControl;
ButtonControl[,] arrayButtons = new ButtonControl[6,6];
public void createGrid()
{
l = 0;
for (int i = 0; i < numberOfButtons; i++)
{
for (int k = 0; k < numberOfButtons; k++)
{
buttonControl = new ButtonControl();
buttonControl.Location = new Point(l,j);
j += 55;
arrayButtons[i, k] = buttonControl;
//After the above statement if i print Console.WriteLine(""+arrayButtons[i,k]); i am getting only my projectname.buttoncontrol
myGridControl.Controls.Add(buttonControl);
}
l += 55; j = 10;
}
}
I want to access each variable in arrayButtons[][]..like in a 3*3 matrix..if i want 2nd row 1 column element..then i get something like arrayname[2][1]..same way if i want 2nd button in 2nd row how can i get..i tried doing one way but i couldnt figure it out...Can you help me out with this..
What are you having difficulty with?
If you're running into bounds checking problems, you should know that C# arrays start at zero, not one. So the button in the second row, first column is a[1,0] not a[2,1]
If you Google Control Arrays in C# you will get several good matches, including this one.