C++-CLI Button Arrays to C# Button Arrays in Winforms - c#

I am designing an application in C# Winforms (for the first time). I've designed several applications in C++ in the past, and am having difficulty converting some of my C++-CLI functions to C#.
I have 5 buttons along a side bar that toggles the visibility of the button's corresponding panel per button click. In order to do this, I set the visibility of all other panels to false. In order to achieve this in C++-CLI, I've done the following:
private: System::Void panels_Click(System::Object^ sender, System::EventArgs^ e) {
System::Windows::Forms::Button ^ currentbutton = (System::Windows::Forms::Button ^) sender;
array < Panel ^ > ^ objects = { panel1, panel2, panel3, panel4, panel5, panel6};
array < Button ^ > ^ buttons = { button1, button2, button3, button4, button5, button6 };
for (int i = 0; i < 6; i++) {
if (buttons[i]->Equals(currentbutton)) {
objects[i]->Visible = true;
}
else objects[i]->Visible = false;
}
}
The issue I am having is with the " array Panel ^" portion, as I can not find an equivalent in C#. Any help is appreciated.

Arrays are declared in C# using TypeName[].
Panel[] objects = { panel1, panel2, panel3, panel4, panel5, panel6 };
Button[] buttons = { button1, button2, button3, button4, button5, button6 };

You can cast the Controls collection to a List<Control>, and then access the control name for comparison. The Cast<T>() method is a linq extension method, so you'll have to add using System.Linq; to your namespace:
private void panels_Click(object sender, EventArgs e)
{
List<string> panelNames = new List<string>
{"panel1", "panel2", "panel3", "panel4", "panel5", "panel6"};
List<string> buttonNames = new List<string>
{"button1", "button2", "button3", "button4", "button5", "button6"};
List<Control> panels = this.Controls.Cast<Control>()
.Where(ctrl => panelNames.Contains(ctrl.Name)).ToList();
List<Control> buttons = this.Controls.Cast<Control>()
.Where(ctrl => buttonNames.Contains(ctrl.Name)).ToList();
Button thisButton = sender as Button;
for (int i = 0; i < buttons.Count; i++)
{
if (i < panels.Count) panels[i].Visible = buttons[i] == thisButton;
}
}

Related

Create a List of existing Buttons

l've 10 ten button on my forms ( 0 to 9) to simulate a calculator
All my buttons are named like this btnCalc0,btnCalc1,btnCalc2,etc...
I want to create an array or list of these buttons to handle event but it's doesn't work because btnCalc doesnt exist(btnCalc+x).
List<Button> lstBtnCalc = new List<Button>();
for (int x = 0; x < 10; x++)
{
lstBtnCalc.Add(btnCalc+x));
}
private void myClick(object sender, EventArgs e)
{
int index = lstBtnCalc.IndexOf(sender as Button);
}
You could populate your array with a loop (See ASh's answer). However, in doing so, you make the code harder to read. The primary test of good code is readable code, so avoid "clever" solutions and keep it simple. In this case, a simple, easy to read and maintain, way is:
List<Button> lstBtnCalc = new List<Button>
{
btnCalc0, btnCalc1, btnCalc2, btnCalc3, btnCalc4,
btnCalc5, btnCalc6, btnCalc7, btnCalc8, btnCalc9
}
You can use Find method:
List<Button> lstBtnCalc = new List<Button>();
for (int x = 0; x < 10; x++)
{
var buttonName = string.Format("btnCalc{0}",x);
var button = this.Controls.Find(buttonName);
if (button != null)
{
lstBtnCalc.Add(button);
}
}
Try this
public partial class Form1 : Form
{
List<Button> lstBtnCalc = null;
public Form1()
{
InitializeComponent();
lstBtnCalc = new List<Button>() { button1, button2, button3, button4 };
}
}
a bit fluent:
List<Button> lstBtnCalc = this.Controls.OfType<Button>().Where(a => a.Name.StartsWith("btnCacl")).ToList();

C# - Use too many buttons as 1 variable

I have a fairly simple question. I want to change the background color of 15 buttons,
but is is very cumbersome to write
button1.backgroundColor = Color.black
button2.backgroundColor = Color.black
.
.
.
How i can assign the color to all these buttons at once?
Like:
something allButtons = { button1.backgroundColor, button2.backgroundcolor .... }
I know how to do this in obj-c:
for (int i = 1; i < 16; i++)
{
UIButton *button = (UIButton *)[tag:i];
button.backgroundColor = [UIColor Color.black];
}
but how to accomplish this in C#?
You might be able to iterate through all the controls on the form, looking for buttons.
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(Button))
{
c.BackColor = Color.Black;
}
}
You put your buttons in an button array
Button[] buttons = new Button[] {button1, button2, .....};
Or in a List<Button>
List<Button> buttons = new List<Button>() { button1, button2, ....);
Next you loop over the button array or the List in the same way
foreach(Button btn in buttons)
btn.BackColor = Color.Black;
Another way to change this property is looping using the Forms.Controls container. But this will work only if the buttons are all contained in the Form.Controls collection.
foreach (Control btn in this.Controls.OfType<Button>())
{
btn.BackColor = Color.Black;
}
To fix the problem of buttons contained in inner ControlCollection you should use a recursive function that loops on every control container and reach buttons eventually inside that container
public void SetBackground(Control.ControlCollection coll)
{
foreach(Control ctr in coll)
{
if(ctr.Controls.Count > 0)
SetBackground(ctr.Controls);
else
{
Button btn = ctr as Button;
if(btn != null) btn.BackColor = Color.Black;
}
}
}
and call it from the toplevel collection
SetBackground(this.Controls);
It is a lot more complicated, so I prefer to use an array to explicitily declare the buttons that need to be changed.

Assign checkboxes to an checkbox-array using a for loop in C#

I'd like to do this:
CheckBox[] boxarray = new CheckBox[4];
boxarray[0] = checkBox1;
boxarray[1] = checkBox2;
boxarray[2] = checkBox3;
boxarray[3] = checkBox4;
using a for loop - because I have about 600 checkboxes. I thought about this:
for (int i = 0 ; i<= 600; i++)
{
boxes[i] = checkBox[i] ;
}
But whatever I tried - it didn't work. I hope you know what I mean.
Thanks for your help!
If you have these CheckBoxes on your form, then you can add them to an array (or List, which would be much easier to do) like that:
List<CheckBox> checkBoxesList = new List<CheckBox>();
foreach (Control ctrl in FormName.Controls)
{
if (ctrl.GetType() == typeof(CheckBox))
{
checkBoxesList.Add(ctrl as CheckBox);
}
}
Remember, simply writing:
checkBox1, checkBox2
won't make it possible to get them like checkBox[0] - it's not an array, it's just a name with '1' or '2' in the end.
Using the current setup, you'll have to use FindControl (assuming ASP.net, winforms and WPF work differently):
for(int i = 0; i <= 600; i++)
{
boxes[i] = Page.FindControl("checkbox" + i);
}
Update for windows forms: There is actually a method you can use to find all controls of a specific type:
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
Here's another option for you. I tested it by creating a sample
application, I then put a GroupBox and a GroupBox inside the initial
GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a
button. This is the code I used (even includes the recursion you were
looking for)
public IEnumerable<Control> GetAll(Control control,Type type) {
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
To test it in the form load event I wanted a count of all controls inside
the initial GroupBox
private void Form1_Load(object sender, EventArgs e) {
var c = GetAll(this,typeof(TextBox));
MessageBox.Show("Total Controls: " + c.Count());
}
And it returned the proper count each time, so I think this will work perfectly for
what you're looking for :)
If you have other checkboxes on your form that you don't want to add, you'll have to use the following method:
for(int i = 0; i <= 600; i++)
{
boxes[i] = this.Controls.Find("checkbox" + i, true).FirstOrDefault() as CheckBox;
}
you are not able to specifiy the name of the checkboxes in the code like you have done, because i wont get changed.
you have to create new instances of CheckBox like:
for (int i = 0 ; i<= 600; i++)
{
//This will create a new instance of a CheckBox
CheckBox cb = new CheckBox()
//At this point the checkbox is empty and not visible anywhere
//So you have to change some properties:
cb.Text = "Check me!";
cb.Top = Ycoord; //you should change this depending on i like +(i*30)
cb.Left = Xcoord;
cb.name = "checkbox" + i.toString();
//To recognize if one of your Checkboxes is checked/unchecked you need to add
//an event like this (for the event see down below)
cb.CheckedChanged += checkedChangedEvent;
//then you need to add the checkbox to your Array
boxes[i] = cb;
//to make those checkboxes visible you need to add them to your form
//or Panel:
myForm.Controls.Add(cb);
}
The Event:
public void checkedChangedEvent(Object sender, EventArgs e)
{
MessageBox.Show(((CheckBox)sender).name + " is now Checked == " + ((CheckBox)sender).Checked.toString();
}
you have to specify which Checkbox was Checked/Unchecked by its name, because every CheckBox is firing the same event.
EDIT2:
to get the number of the checkbox you can do something like this in the event:
int cbNumber = 0;
try
{
cbNumber = System.Convert.toInt32(((CheckBox)sender).name.Replace("checkbox",""));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n\n" + ex.StackTrace);
}

How to change properties of a Control that is in List<UIControl> without using Loop?

I have the following code where a click event will dynamically create additional Canvas to the WrapPanel, and each Canvas contains a TextBox and a Button. Once the Button on one Canvas is click, TextBox.Text and Button.Content change from "Foo" to "Jesus".
The below code works, but it's not ideal. Because each property Change ("Foo" to "Jesus), I have to run a loop. I have to run two loops just to change the text on the TextBox and Button. Is there a direct way to change the Properties other then a Loop? My actually application contains 30+ controls in a Canvas, I don't want to run 30+ loops each time just to change some text.
List<Canvas> cvList = new List<Canvas>();
List<TextBox> tbList = new List<TextBox>();
List<Button> FooList = new List<Button>();
WrapPanel wp = new WrapPanel();
private void createbtn1_Click(object sender, RoutedEventArgs e)
{
Canvas cv = new Canvas();
StackPanel sp = new StackPanel();
TextBox tb = new TextBox();
Button Foo = new Button();
sp.Orientation = Orientation.Vertical;
sp.Children.Add(tb);
sp.Children.Add(Foo);
cv.Children.Add(sp);
wp.Children.Add(cv);
cvList.Add(cv);
tbList.Add(tb);
FooList.Add(Foo);
cv.Width = 100;
cv.Height = 100;
tb.Text = "#" + (cvList.IndexOf(cv)+1);
tb.Width = 50;
tb.Height = 30;
Foo.Content = "Foo";
Foo.Click += destroy_Click;
}
private void Foo_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
var bIndex = FooList.IndexOf(b);
foreach (TextBox t in tbList)
{
if (tbList.IndexOf(t) == bIndex)
{
t.Text = "Jesus";
}
}
foreach (Button f in FooList)
{
if (FooList.IndexOf(t) == bIndex)
{
t.Content = "Jesus";
}
}
}
Just access the text boxes by index and set the content of the button directly:
if(bIndex < tbList.Count && bIndex != -1)
tbList[bIndex].Text = "Jesus";
if(b != null && bIndex != -1)
b.Content = "Jesus";
why can't you just get the item at the index and set that items text:
tbList[bindex].Text="Jesus";
As for setting the buttons content, you already have the button from the click event, so just use that:
b.Content = "Jesus";
You current code just loops through each item in the list and gets the index of the item and sees if it is the index you want. Accessing by the indexer of the list directly will give you what you want.
You will probably want to do some error checking, but that is not currently done in your existing code either.
Some info on using indexers from MSDN

Create button during runtime in C#.net?

I know how to create button during runtime.
Button button1 = new Button();
button1.Location = new Point(20,10);
button1.Text = "Click Me";
// adding to groupBox1
groupBox1.Controls.Add(button1);
But the problem is i want to add multiple buttons like this..
for(int i = 1; i < 30; i++) {
Button button[i] = new Button();
// Button customization here...
...
groupBox1.Controls.Add(button[i]);
}
The code above is false code. How can I make this happen true in C#.net? i want to create multiple buttons with button name, button1, button2, button3, button4, .... button30;
You can't declare extra variables at execution time in C# - but you really don't want to anyway, as you wouldn't be able to access them dynamically afterwards. Just create an array:
// buttons would be declared as Button[] as a member variable
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++) {
buttons[i] = new Button();
// Button customization here...
...
groupBox1.Controls.Add(buttons[i]);
}
Alternatively, use a List<Button>, which will certainly be more convenient if you don't know how many buttons you need beforehand. (See the obligatory "arrays considered somewhat harmful" blog post.)
Of course, if you don't actually need to get at the buttons later, don't bother assigning them to anything visible outside the loop:
for(int i = 0; i < 30; i++) {
Button button = new Button();
// Button customization here...
...
groupBox1.Controls.Add(button);
}
You need to think about what information you need access to when... and how you want to access it. If you logically have a collection of buttons, you should use a collection type variable (like a list or an array).
Frankly I think it's one of the curses of the VS designers that you end up with horrible names such as "groupBox1" which carry no information beyond what's already in the type declaration, and encourage developers to think of collections of controls via individually-named variables. That's just me being grumpy though :)
Try this
for(int i = 1; i < 30; i++) {
Button button = new Button();
// Button customization here...
button.Name = "Button" + i.ToString();
groupBox1.Controls.Add(button);
}
You seem like you're almost on the right track:
// in form class
Button[] m_newButtons = new Button[30];
// in your trigger function
for(int i = 0; i < 30; ++i)
{
m_newButtons[i] = new Button();
// ...
groupBox1.Controls.Add(m_newButtons[i]);
}
If you try and do this more than once you may have to remove the old buttons from the control before adding the new ones.
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++) {
buttons[i] = new Button();
groupBox1.Controls.Add(buttons[i]);
}
this code will work but button will be added one over other so set location also
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++)
{
buttons[i] = new Button();
Point p=new Point(xvalue,yvalue);
buttons[i].Location = p;
groupBox1.Controls.Add(buttons[i]);
}
one thing you want to remember increment the x or y position by which you want to display it
Try this one out, I have just learned it myself:
public partial class Form1 : Form
{
Button[] btn = new Button[12];// <--------<<<Button Array
public Form1()
{
InitializeComponent();
}
private void Form1_Load (object sender, EventArgs e)
{
for (int i = 0; i < 12; i++)
{
btn[i] = new Button ( );
this.flowLayoutPanel1.Controls.Add(btn[i]);
}
}
// double click on the flow layoutPannel initiates this code
private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e)
{
}
}

Categories