Hi I have a small winforms program that will soon develop into something more. The program has 2 panels panel1 and panel2 these panels are populated dynamically with some form controls. the first panel is populated with combo-boxes and the second with a grid of buttons. What I want to achieve is to be able to disable the right button depending on what the user selects from the combobox. Each column of the grid represent a day of the week and the combobox will be used to disable the wanted day by selecting it from the list if you like.
To do this statically is straight forward, however my program will soon expand so that it can handle a large database so that's why I am doing this dynamically. Basically this is where I'm stuck at the moment I want to simply disable the right button.
Below is the interface that i have so far:
And this is my code if any help:
public Form1()
{
InitializeComponent();
}
Button[] btn = new Button[2];
ComboBox[] cmb = new ComboBox[1];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
public void createColumns(int s)
{
for (int i = 0; i < btn.Length; ++i)
{
btn[i] = new Button();
btn[i].SetBounds(40 * i, s, 35, 35);
btn[i].Text = Convert.ToString(i);
panel1.Controls.Add(btn[i]);
}
for (int i = 0; i < cmb.Length; ++i)
{
cmb[i] = new ComboBox();
cmb[i].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[i].Text = "Disable";
cmb[i].Items.Add("Monday");
cmb[i].Items.Add("Tuesday");
cmb[i].SetBounds(40 * i, s, 70, 70);
panel2.Controls.Add(cmb[i]);
}
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
if (senderCmb.SelectedIndex == 1)
{
//MessageBox.Show("Tuesday");
btn[1].Enabled = false;
}
}
public void placeRows()
{
for (int i = 0; i < 80; i = i + 40)
{
createColumns(i);
}
}
}
Alternative 1
Every control has a Tag property.
You can set the Tag property of your buttons to represent the column they are in.
When a selection is made in the combo box, simply search through all buttons, and enable or disable the button based on whether each button's Tag property matches the selected text in the combo box.
Alternative 2
Create a
Dictionary<string, List<Button>> buttonMap;
where the key is the value representing the column ("Tuesday") and the value is a list of buttons with that tag. When creating the buttons initially, also populate that dictionary.
If you go with Alternative 2, you'll have to remember the previously selected value of the checkbox so you can re-enable buttons that are no longer disabled.
If you have lots of buttons, you may find that Alternative 2 is noticeably faster.
UPDATE
Here's a complete working sample of Alternative 1.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const int ROWS = 2;
const int COLS = 2;
Button[,] btn = new Button[ROWS,COLS];
ComboBox[] cmb = new ComboBox[ROWS];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
private readonly string[] cbTexts = new string[] { "Monday", "Tuesday" };
public void createColumns(int rowIndex)
{
int s = rowIndex * 40;
// Your original code kept overwriting btn[i] for each column. You need a 2-D array
// indexed by the row and column
for (int colIndex = 0; colIndex < COLS; colIndex++)
{
btn[rowIndex, colIndex] = new Button();
btn[rowIndex, colIndex].SetBounds(40 * colIndex, s, 35, 35);
btn[rowIndex, colIndex].Text = Convert.ToString(colIndex);
btn[rowIndex, colIndex].Tag = cbTexts[colIndex];
panel1.Controls.Add(btn[rowIndex, colIndex]);
}
cmb[rowIndex] = new ComboBox();
cmb[rowIndex].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[rowIndex].Text = "Disable";
foreach (string cbText in cbTexts)
{
cmb[rowIndex].Items.Add(cbText);
}
cmb[rowIndex].SetBounds(40, s, 70, 70);
cmb[rowIndex].Tag = rowIndex; // Store the row index so we know which buttons to affect
panel2.Controls.Add(cmb[rowIndex]);
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
int row = (int)senderCmb.Tag;
for (int col = 0; col < COLS; col++)
{
Button b = btn[row, col];
// These three lines can be combined to one. I broke it out
// just to highlight what is happening.
string text = ((string)b.Tag);
bool match = text == senderCmb.SelectedItem.ToString();
b.Enabled = match;
}
}
public void placeRows()
{
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
createColumns(rowIndex);
}
}
}
Related
so i i hade 10x10 grid with pics and i want to swap by drag and drop and i actually cant get
the imgages the targeted and the selected in order to make the spaw
i made all from view model code
in the evens the sender is a grid and the e is DragEventArgs
public MainViewModel()
{
GameGrid = new Grid { AllowDrop = true };
GameGrid.DragOver += GameGrid_DragOver;
GameGrid.Drop += GameGrid_Drop;
for (int row = 0; row < 10; row++)
{
GameGrid.RowDefinitions.Add(new RowDefinition());
for (int col = 0; col < 10; col++)
{
if (row == 0)
GameGrid.ColumnDefinitions.Add(new ColumnDefinition());
var image = new Image { Source = logic.GetImage(), CanDrag = true, AllowDrop = true };
Grid.SetRow(image, row);
Grid.SetColumn(image, col);
GameGrid.Children.Add(image);
}
}
}
private void GameGrid_DragOver(object sender, Windows.UI.Xaml.DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Move;
}
private async void GameGrid_Drop(object sender, Windows.UI.Xaml.DragEventArgs e)
{
if (logic.IsValidSwap(selected, selected))
{
}
}
// but i cant get the imeges to send the func is validswap
Instead of assigning in the event to the grid:
GameGrid.DragOver += GameGrid_DragOver;
GameGrid.Drop += GameGrid_Drop;
It should be assigned to each image inside the for loop:
image.Drop += GameGrid_Drop;
image.DragOver += GameGrid_DragOver;
And than the sender will be the image—you can know the col and row and make switches.
I want create dynamic comboboxes in wpf stack panel, retrive their values and delete them when the user enters the number in a textbox. Following is the code that I have used, that when the user enter the number in the textbox, (on TextEventChaged) to add comboboxes to the stackpanel(i.e, VehiclesPerday):
<TextBox x:Name="NumberOfVehciles" FontSize="15" HorizontalAlignment="Left" Height="40" TextChanged="NumberOfVehciles_TextChanged"/>
<WrapPanel x:Name="VehiclesPerday" HorizontalAlignment="Left">
</WrapPanel>
BackEnd
private void NumberOfVehciles_TextChanged(object sender, TextChangedEventArgs e)
{
int _count = Convert.ToInt32(NumberOfVehciles.Text.Trim());
for (int x = 1; x <= _count; x++)
{
ComboBox cmb = new ComboBox();
cmb.Name = "cmbd" + x.ToString();
cmb.Height = 40;
cmb.HorizontalAlignment = HorizontalAlignment.Left;
cmb.FontSize = 15;
cmb.Width = 200;
cmb.VerticalAlignment = VerticalAlignment.Top;
cmb.Margin = new Thickness(50, 40, 0, 0);
VehiclesPerday.Children.Add(cmb);
}
}
SubmitButton for retrieving data i have tried, it show null value to comboxbox when i debug it
private void SubmitButton_Click(object sender, RoutedEventArgs e)
{
int _count = Convert.ToInt32(NumberOfVehciles.Text.Trim());
for (int x = 1; x <= _count; x++)
{
ComboBox _vehicle = (ComboBox)this.VehiclesPerday.FindName("cmbd" + x.ToString());
}
}
And also when the user changes the value in the textbox, it should remove the combo boxes created in the stack panel and do the vice-versa after changing his value, Eg.
If the user on first go enters 2 in the textbox, 2 combo boxes should be created.
Now if user wants to change the value to 2 to 1 , it should delete the created combo boxes from the stack panel and recreate.
I've added checking if text in your textbox is number and can be converted to int
Added call VehiclesPerday.Children.Clear() just for tests
Added foreach loop to find the proper ComboBox by Name
private void NumberOfVehciles_TextChanged(object sender, TextChangedEventArgs e)
{
if (int.TryParse(NumberOfVehciles.Text.Trim(), out int _count))
{
VehiclesPerday.Children.Clear(); // for tests
for (int x = 1; x <= _count; x++)
{
ComboBox cmb = new ComboBox // Visual studio simplified object creation here
{
Name = "cmbd" + x.ToString(),
Height = 40,
HorizontalAlignment = HorizontalAlignment.Left,
FontSize = 15,
Width = 200,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(50, 40, 0, 0)
};
VehiclesPerday.Children.Add(cmb);
}
}
}
private void SubmitButton_Click(object sender, RoutedEventArgs e)
{
if (int.TryParse(NumberOfVehciles.Text.Trim(), out int _count))
{
for (int x = 1; x <= _count; x++)
{
ComboBox _vehicle = null;
foreach (ComboBox box in VehiclesPerday.Children)
{
if (box.Name == "cmbd" + x.ToString())
{
_vehicle = box; // ComboBox found
break;
}
}
MessageBox.Show(_vehicle?.Name ?? "ComboBox not found!");
}
}
}
I am making a N*M size SUDOKU game. Every number are on a button.
When the program start all button is empty and I would like if I click to a button it is make a little panel on it with buttons for each number to choose one.
private void adatB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
Panel szamok = new Panel
{
Location = MousePosition,
Size = new Size(100, 100)
};
Controls.Add(szamok);
TableLayoutPanel minitabla = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = szorzat,
RowCount = szorzat,
};
for (int i = 0; i < szorzat; i++)
{
minitabla.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
minitabla.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
}
szamok.Controls.Add(minitabla);
Button[,] szamokB = new Button[meret[0], meret[1]];
int d = 1;
for (int i = 0; i < meret[0]; i++)
{
for (int j = 0; j < meret[1]; j++)
{
szamokB[i, j] = new Button();
szamokB[i, j].Tag= hely[0]+","+hely[1];
szamokB[i, j].Text = d.ToString();
szamokB[i, j].Dock = DockStyle.Fill;
szamokB[i, j].Click += szamokB_Click;
minitabla.Controls.Add(szamokB[i, j], i, j);
d++;
}
}
}
private void szamokB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
adatB[hely[0], hely[1]].Text = button.Text;
}
The problem with it when I click a button the pane isn't created.
meret[0] variable is the N, meret[1] is M, adatB is the arry of buttons with the positons in tag.
And If I choosed the number how can I close that panel?
First of all, you should calculate the mouseposition correctly.
From MSDN:
Gets the position of the mouse cursor in screen coordinates.
You should use something like this:
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y)
You will probably need this, to bring your panel to the front:
Controls.Add(szamok);
szamok.BringToFront();
To close the panel you can store the chooser panel and you can remove it from the controls later, use something like this:
public partial class Form1 : Form
{
private Panel myPanel = null;
private void adatB_Click(object sender, EventArgs e)
{
...
Panel szamok = new Panel
{
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y),
Size = new Size(100, 100)
};
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
}
this.myPanel = szamok;
Controls.Add(szamok);
szamok.BringToFront();
...
}
private void szamokB_Click(object sender, EventArgs e)
{
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
this.myPanel = null;
}
...
}
}
I have a button when clicked creates textboxes dynamically:
for (int i = 0; i < length; i++)
{
Name.Add(new TextBox());
System.Drawing.Point locate = new System.Drawing.Point(137, 158 + i * 25);
(Name[i] as TextBox).Location = locate;
(Name[i] as TextBox).Size = new System.Drawing.Size(156, 20);
StartTab.Controls.Add(Name[i] as TextBox);
}
I want to get the text entered in Name[i] convert to a string then set it to labels
You can use Control.ControlCollection.Find.
UPDATED:
TextBox txtName = (TextBox)this.Controls.Find("txtNameOfTextbox", true)[0];
if (txtName != null)
{
return txtName.Text;
}
You don't say what type that Name is, it looks like a list of some sort. Try using a List<TextBox> that way you can just access the TextBox properties directly. Something like this. I am also not sure what Control that StartTab is, so I just used a Panel for this test code. (you should also be aware that Name masks the Form's Name property that is why I changed your list to name)
public partial class Form1 : Form
{
List<TextBox> name = new List<TextBox>();
int length = 5;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < length; i++)
{
name.Add(new TextBox() { Location = new System.Drawing.Point(137, 158 + i * 25),
Size = new System.Drawing.Size(156, 20) });
StartTab.Controls.Add(name[i]);
}
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < length; i++)
{
StartTab.Controls.Add(new Label() {Location = new System.Drawing.Point(name[i].Location.X + name[i].Width + 20,
name[i].Location.Y),
Text = name[i].Text,
AutoSize = true });
}
}
}
Is there any way to dynamically create and display 'n' Labels with 'n' corresponding Textboxs when we know value of 'n' after for example, clicking "Display" button.
Let me know if anything make you don't understand my question. Thank you!
I am working with VS C# Express 2010 Windows Form.
I would create a user control which holds a Label and a Text Box in it and simply create instances of that user control 'n' times. If you want to know a better way to do it and use properties to get access to the values of Label and Text Box from the user control, please let me know.
Simple way to do it would be:
int n = 4; // Or whatever value - n has to be global so that the event handler can access it
private void btnDisplay_Click(object sender, EventArgs e)
{
TextBox[] textBoxes = new TextBox[n];
Label[] labels = new Label[n];
for (int i = 0; i < n; i++)
{
textBoxes[i] = new TextBox();
// Here you can modify the value of the textbox which is at textBoxes[i]
labels[i] = new Label();
// Here you can modify the value of the label which is at labels[i]
}
// This adds the controls to the form (you will need to specify thier co-ordinates etc. first)
for (int i = 0; i < n; i++)
{
this.Controls.Add(textBoxes[i]);
this.Controls.Add(labels[i]);
}
}
The code above assumes that you have a button btnDisplay and it has a onClick event assigned to btnDisplay_Click event handler. You also need to know the value of n and need a way of figuring out where to place all controls. Controls should have a width and height specified as well.
To do it using a User Control simply do this.
Okay, first of all go and create a new user control and put a text box and label in it.
Lets say they are called txtSomeTextBox and lblSomeLabel. In the code behind add this code:
public string GetTextBoxValue()
{
return this.txtSomeTextBox.Text;
}
public string GetLabelValue()
{
return this.lblSomeLabel.Text;
}
public void SetTextBoxValue(string newText)
{
this.txtSomeTextBox.Text = newText;
}
public void SetLabelValue(string newText)
{
this.lblSomeLabel.Text = newText;
}
Now the code to generate the user control will look like this (MyUserControl is the name you have give to your user control):
private void btnDisplay_Click(object sender, EventArgs e)
{
MyUserControl[] controls = new MyUserControl[n];
for (int i = 0; i < n; i++)
{
controls[i] = new MyUserControl();
controls[i].setTextBoxValue("some value to display in text");
controls[i].setLabelValue("some value to display in label");
// Now if you write controls[i].getTextBoxValue() it will return "some value to display in text" and controls[i].getLabelValue() will return "some value to display in label". These value will also be displayed in the user control.
}
// This adds the controls to the form (you will need to specify thier co-ordinates etc. first)
for (int i = 0; i < n; i++)
{
this.Controls.Add(controls[i]);
}
}
Of course you can create more methods in the usercontrol to access properties and set them. Or simply if you have to access a lot, just put in these two variables and you can access the textbox and label directly:
public TextBox myTextBox;
public Label myLabel;
In the constructor of the user control do this:
myTextBox = this.txtSomeTextBox;
myLabel = this.lblSomeLabel;
Then in your program if you want to modify the text value of either just do this.
control[i].myTextBox.Text = "some random text"; // Same applies to myLabel
Hope it helped :)
Here is a simple example that should let you keep going add somethink that would act as a placeholder to your winform can be TableLayoutPanel
and then just add controls to it
for ( int i = 0; i < COUNT; i++ ) {
Label lblTitle = new Label();
lblTitle.Text = i+"Your Text";
youlayOut.Controls.Add( lblTitle, 0, i );
TextBox txtValue = new TextBox();
youlayOut.Controls.Add( txtValue, 2, i );
}
Suppose you have a button that when pressed sets n to 5, you could then generate labels and textboxes on your form like so.
var n = 5;
for (int i = 0; i < n; i++)
{
//Create label
Label label = new Label();
label.Text = String.Format("Label {0}", i);
//Position label on screen
label.Left = 10;
label.Top = (i + 1) * 20;
//Create textbox
TextBox textBox = new TextBox();
//Position textbox on screen
textBox.Left = 120;
textBox.Top = (i + 1) * 20;
//Add controls to form
this.Controls.Add(label);
this.Controls.Add(textBox);
}
This will not only add them to the form but position them decently as well.
You can try this:
int cleft = 1;
intaleft = 1;
private void button2_Click(object sender, EventArgs e)
{
TextBox txt = new TextBox();
this.Controls.Add(txt);
txt.Top = cleft * 40;
txt.Size = new Size(200, 16);
txt.Left = 150;
cleft = cleft + 1;
Label lbl = new Label();
this.Controls.Add(lbl);
lbl.Top = aleft * 40;
lbl.Size = new Size(100, 16);
lbl.ForeColor = Color.Blue;
lbl.Text = "BoxNo/CardNo";
lbl.Left = 70;
aleft = aleft + 1;
return;
}
private void btd_Click(object sender, EventArgs e)
{
//Here you Delete Text Box One By One(int ix for Text Box)
for (int ix = this.Controls.Count - 2; ix >= 0; ix--)
//Here you Delete Lable One By One(int ix for Lable)
for (int x = this.Controls.Count - 2; x >= 0; x--)
{
if (this.Controls[ix] is TextBox)
this.Controls[ix].Dispose();
if (this.Controls[x] is Label)
this.Controls[x].Dispose();
return;
}
}