I have a menustrip consists of Menu and Tools
in "Menu" i have subMenus like msO1,msO2,msO3......., and on "Tools" i have subMenus like msP1,msP2,msP3.......,
on Form load all the subMenus visible is false..., On button Click user want to select which subMenus he want...,
in the textBox(txtSelect) if user enter 1,3..., he get msO1, msO3.....,
my code is a hardcode..., if i have 20 subMenus means this code is not helpfull anybody have an idea...,
private void btnSelect_Click_1(object sender, EventArgs e)
{
msO1.Visible = false;//msO1 is a submenu
msO2.Visible = false;
msO3.Visible = false;
msP1.Visible = false;
msP2.Visible = false;
msP3.Visible = false;
string word = txtSelect.Text;
string[] splt = word.Split(',');
int[] arrayItms = new int[splt.Length];
for (int x = 0; x < splt.Length; x++)
{
arrayItms[x]=Convert.ToInt32(splt[x].ToString());
if (splt.Length > 0)
{
switch (arrayItms[x])
{
case 1:
msO1.Visible = true; break;
case 2:
msO2.Visible = true; break;
case 3:
msO3.Visible = true; break;
case 4:
msP1.Visible = true; break;
case 5:
msP2.Visible = true; break;
case 6:
msP3.Visible = true; break;
}
}
}
}
Create an array of your MenuStrip
MenuStrip[] mstrip = new MenuStrip[]
{
msO1,msO2, msO3, msP1, msP2, msP3 // add other menus here when needed
};
now you could work on the array as a Whole to make visible or not your menus
for(int x = 0; x < menus.Length; x++)
mstrip[x].Visible = false;
and your code could be simplified with
for (int x = 0; x < splt.Length; x++)
{
int menuIndex;
if(Int32.TryParse(splt[x], out menuIndex))
{
menuIndex--;
if(menuIndex >= 0 && menuIndex < mstrip.Length)
mstrip[menuIndex].Visible = true;
}
}
Remember, arrays indexes start at zero (while your user will probably start counting a 1).
You could use something like this
string word = txtSelect.Text;
string[] splt = word.Split(',');
for (int x = 0; x < splt.Length; x++)
{
Control myControl1 = FindControl("ms" + splt[x]);
if ( myControl1 != null )
(ToolStripMenuItem)myControl1.Visible = true;
}
Untested but this should get you half way there I hope.
Loop through each ToolStripMenuItem control in the menu strip items and set them to visible.
You can add further conditions inside the loop to define which of the menu items should be made visible based on the users choice..
foreach (ToolStripMenuItem mi in menuStrip1.Items)
{
mi.Visible = true;
}
Related
I'm trying to turn textboxes and buttons visible when the number of tracks it's selected in a combobox.
For example: when I select 3, just 3 textboxes and the 3 respective buttons to select the tracks are enabled. How can I change this code that I've made to a simple foreach or a for?
if (numero_faixas == 1) {
txtFaixa1.Visible = true;
btnFaixa1.Visible = true;
} else if (numero_faixas == 2) {
txtFaixa1.Visible = true;
btnFaixa1.Visible = true;
txtFaixa2.Visible = true;
btnFaixa2.Visible = true;
} else if (numero_faixas == 3) {
txtFaixa1.Visible = true;
btnFaixa1.Visible = true;
txtFaixa2.Visible = true;
btnFaixa2.Visible = true;
txtFaixa3.Visible = true;
btnFaixa3.Visible = true;
}
You can reduce the lines of code by changing your conditions, so you don't have to reference the same control so many times:
if (numero_faixas > 0)
{
txtFaixa1.Visible = true;
btnFaixa1.Visible = true;
}
if (numero_faixas > 1)
{
txtFaixa2.Visible = true;
btnFaixa2.Visible = true;
}
if (numero_faixas > 2)
{
txtFaixa3.Visible = true;
btnFaixa3.Visible = true;
}
To use a foreach loop, you could cast the Controls collection to an IEnumerable<Control> and then, using System.Linq;, you can filter on controls of type TextBox and Button, where the control name contains "Faxia". Then, in the loop body, we can use int.TryParse to try to convert the last character of the control name to an int, and if that succeeds, then set the control to Visible if the control number is less than numero_faixas + 1:
foreach (Control control in Controls.Cast<Control>()
.Where(c => (c is Button || c is TextBox) && c.Name.Contains("Faixa")))
{
// Get the number associated with this control and compare it to numero_faixas
int controlNumber;
if (int.TryParse(control.Name.Substring(control.Name.Length - 1), out controlNumber) &&
controlNumber < numero_faixas + 1)
{
control.Visible = true;
}
}
Here's a proof of concept that you could respin using your business rules.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ShowHideButtons_47439046
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitOurThings();
}
private void InitOurThings()
{
//lets create a combo box with options to select
ComboBox combo = new ComboBox();
combo.Location = new Point(5, 5);//place it somewhere
//add selectable items
for (int i = 0; i < 10; i++)
{
combo.Items.Add(i);
}
combo.SelectedValueChanged += Combo_SelectedValueChanged;//the event which will handle the showing/hidding
Controls.Add(combo);//add the combo box to the form
//lets create some buttons and textboxes
int btnx = 5;
int btny = combo.Height + combo.Location.Y + 5;
for (int i = 0; i < 10; i++)
{
Button btn = new Button();
btn.Location = new Point(btnx, btny);
btn.Name = i.ToString();
btn.Text = i.ToString();
Controls.Add(btn);
btny += btn.Height + 5;
TextBox txtbx = new TextBox();
txtbx.Location = new Point(btn.Location.X + btn.Width + 5, btn.Location.Y);
txtbx.Name = i.ToString();
txtbx.Text = i.ToString();
Controls.Add(txtbx);
}
}
private void Combo_SelectedValueChanged(object sender, EventArgs e)
{
int selectedValue = int.Parse(((ComboBox)sender).SelectedItem.ToString());
foreach (Control item in Controls)
{
//show/hide the controls based on their Name being Equal Or Smaller than the selectedItem
if (item is TextBox)
{
int itemNumber = int.Parse(item.Name);
item.Visible = itemNumber <= selectedValue ? true : false;
}
if (item is Button)
{
int itemNumber = int.Parse(item.Name);
item.Visible = itemNumber <= selectedValue ? true : false;
}
}
}
}
}
I would like to display four images at the same time and upon form load the images switch places. Currently, images will appear in different numbers, for example: 1 image will appear or 2 images, etc up 4. I also want to ensure that no duplicates will appear.
Code from Form1_Load:
PictureBox[] boxes = new PictureBox[4];
boxes[0] = pictureBox0;
boxes[1] = pictureBox1;
boxes[2] = pictureBox2;
boxes[3] = pictureBox3;
for (int i = 0; i < boxes.Length; i++)
{
int switcher = r.Next(0, 5);
switch (switcher)
{
case 0:
{ boxes[i].Image = Properties.Resources.dog0; } break;
case 1:
{ boxes[i].Image = Properties.Resources.dog1; } break;
case 2:
{ boxes[i].Image = Properties.Resources.dog2; } break;
case 3:
{ boxes[i].Image = Properties.Resources.dog3; } break;
}
}
Two examples given above as to what currently happens.
Update - Working
The program now moves images around upon Load and there are no duplicates :)
List<Bitmap> resources = new List<Bitmap>();
resources.Add(Properties.Resources.dog0);
resources.Add(Properties.Resources.dog1);
resources.Add(Properties.Resources.dog2);
resources.Add(Properties.Resources.dog3);
resources = resources.OrderBy(a => Guid.NewGuid()).ToList();
for (int i = 0; i < resources.Count; i++)
{
pictureBox0.Image = resources[0];
pictureBox1.Image = resources[1];
pictureBox2.Image = resources[2];
pictureBox3.Image = resources[3];
}
Two example given above showing what happens now that it works.
The implementation is quite simple. Firstly, you need to shuffle the array and then iterate through it. Fisher–Yates shuffle.
Create a method ShuffleImages as below:
public void ShuffleImages(PictureBox[] img)
{
Random r = new Random();
for (int i = 0; i < img.Length - 1; i++)
{
int j = r.Next(i, img.Length);
PictureBox temp = img[j];
img[j] = img[i];
img[i] = temp;
}
}
and call the method in your Form1_Load event:
private void Form1_Load(object sender, EventArgs e)
{
PictureBox[] boxes = new PictureBox[4];
boxes[0] = pictureBox0;
boxes[1] = pictureBox1;
boxes[2] = pictureBox2;
boxes[3] = pictureBox3;
ShuffleImages(boxes); //call the method
for (int i = 0; i <= 3; i++)
{
switch (i)
{
case 0:
{ boxes[i].Image = Properties.Resources.dog0; }
break;
case 1:
{ boxes[i].Image = Properties.Resources.dog1; }
break;
case 2:
{ boxes[i].Image = Properties.Resources.dog2; }
break;
case 3:
{ boxes[i].Image = Properties.Resources.dog3; }
break;
}
}
}
As M.kazem Ahkhary points out you need to shuffle the images:
List<Bitmap> resources = new List<Bitmap>();
resources.Add(Properties.Resources.dog0);
resources.Add(Properties.Resources.dog1);
resources.Add(Properties.Resources.dog2);
resources.Add(Properties.Resources.dog3);
resources = resources.OrderBy(a => Guid.NewGuid()).ToList(); // Dirty but effective shuffle method
pictureBox0.Image = resources[0];
pictureBox1.Image = resources[1];
pictureBox2.Image = resources[2];
pictureBox3.Image = resources[3];
I have a Form that contains a Menu with two entries, which are Menu and Tools. The two Menues have some SubMenus.
Now i have a TextBox called txtSelect and a Button called btnVisible, if I enter 1,2 in the TextBox, the SubMenus in the Menu should not be visible. I written the following code, bit it is Hard-written.
ToolStripMenuItem[] mstrip = new ToolStripMenuItem[] { msO1, msO2, msO3, msP1, msP2, msP3 };
if (txtSelect.Text.Length > 2)
{
string word = txtSelect.Text;
string[] splt = word.Split(',');
for (int x = 0; x < mstrip.Length; x++)
mstrip[x].Visible = true;
for (int x = 0; x < splt.Length; x++)
{
int y = Convert.ToInt32(splt[x].ToString()) - 1;
if (y >= 0 && y < mstrip.Length)
mstrip[y].Visible = false;
textBox1.AppendText(mstrip[y].Text);
textBox2.AppendText(mstrip[y].OwnerItem.Text);
}
}
I want to use foreach loop instead in a Button Click Event and have attempted with the following, however the result is not the same as with the code above.
foreach (ToolStripMenuItem mnItem in msMenus.Items)
{
MessageBox.Show(mnItem.Text);
for (int i = 0; i < mnItem.DropDown.Items.Count; i++)
{
MessageBox.Show(mnItem.DropDown.Items[i].Text);
mnItem.DropDown.Items[i].Visible = true;
}
}
Well, may be you want something like :
List<Int32> lstindex = new List<Int32>();
String[] splt = txtSelect.Text.Split(',');
// initialize list of indexed for textbox
foreach (String str in splt)
{
lstindex.Add(Convert.ToInt32(str) - 1);
}
// for each menu
foreach (ToolStripMenuItem mnItem in msMenus.Items)
{
// for each menu item
foreach (ToolStripItem item in mnItem.DropDown.Items)
{
// if index of item is in the list of indexed, set visible to false, otherwise to true
item.Visible = lstindex.Contains(mnItem.DropDown.Items.IndexOf(item)) ? false : true;
}
}
I'm geting a StackOverflowException. Somehow, posting here seemed appropriate.
I'm using Windows Forms in a C# application. This application is intended to run on Linux, FreeBSD and Mac-OS, so I can't use WPF, so please don't suggest it.
My guess is that I'm missing a nuance of WinForms, but I cant seem to figure out what.
The ComboBox is generated by the GUI form builder in VS 2010.
The specific lines of code that are throwing the error are here:
if(cur_num_is_valid)
{
cbx_material_num.Text = num;
}
else
{
num = "0";
//I only have one of the following two at a time. Both overflow
cbx_material_num.SelectedIndex = 0;
cbx_material_num.Text = "0";
}
Since the code is somewhat complex, here's the whole function code. 'cbx_' indicates a combo box. 'txtb_' is a text box.
private void cbx_material_numobj_SelectedIndexChanged(object sender, EventArgs e)
{
string obj = cbx_material_obj.Text;
string num = cbx_material_num.Text;
int selnum = 0;
int n = 0;
//do we need to recreate the numbers array?
bool cur_num_is_valid = false;
cbx_material_num.Items.Clear();
if(obj != lastobj)
{
n = m_demo.get_object_modifiers(obj);
for(int i = 0; i <= n; i++)
{
string s = i.ToString();
if(s == num && i < n) cur_num_is_valid = true;
cbx_material_num.Items.Add(s);
}
}
if(cur_num_is_valid)
{
cbx_material_num.Text = num;
}
else
{
num = "0";
//Overflow here:
cbx_material_num.SelectedIndex = 0;
}
try
{
selnum = int.Parse(num);
}
catch(Exception)
{
MessageBox.Show("Error, second select menu after 'object modifiers' must be a number, not '"+num+"'.");
cbx_material_num.Text="0";
return;
}
if(selnum >= n)
{
txtb_material_param1.Text = "0";
txtb_material_param2.Text = "0";
txtb_material_param3.Text = "0";
txtb_material_param4.Text = "0";
}
else
{
MaterialFace face;
MaterialParameter parameter;
int typeid;
object paramdata;
m_demo.get_object_modifiers_material(obj, selnum, out face, out parameter, out typeid, out paramdata);
cbx_material_face.Text = face.ToString();
cbx_material_paramtype.Text = parameter.ToString();
switch(typeid)
{
case 0:
txtb_material_param1.Text = ((float)paramdata).ToString();
cbx_material_datatype.Text = "float";
goto case -1;
case 1:
float[] parsf = ((float[])paramdata);
txtb_material_param1.Text = parsf[0].ToString();
txtb_material_param2.Text = parsf[1].ToString();
txtb_material_param3.Text = parsf[2].ToString();
txtb_material_param4.Text = parsf[3].ToString();
cbx_material_datatype.Text = "float[]";
break;
case 2:
txtb_material_param1.Text = ((int)paramdata).ToString();
cbx_material_datatype.Text = "int";
goto case -1;
case 3:
int[] parsi = ((int[])paramdata);
txtb_material_param1.Text = parsi[0].ToString();
txtb_material_param2.Text = parsi[1].ToString();
txtb_material_param3.Text = parsi[2].ToString();
txtb_material_param4.Text = parsi[3].ToString();
cbx_material_datatype.Text = "int[]";
break;
case -1: //can't actuall be returned, used to 'blank' the last three as '0'
txtb_material_param2.Text = "0";
txtb_material_param2.Text = "0";
txtb_material_param3.Text = "0";
break;
case 4:
OpenTK.Graphics.Color4 paramc = ((OpenTK.Graphics.Color4)paramdata);
txtb_material_param1.Text = paramc.R.ToString();
txtb_material_param2.Text = paramc.G.ToString();
txtb_material_param3.Text = paramc.B.ToString();
txtb_material_param4.Text = paramc.A.ToString();
cbx_material_datatype.Text = "Color4";
break;
default: //5
Vector4 paramv = ((Vector4)paramdata);
txtb_material_param1.Text = paramv.X.ToString();
txtb_material_param2.Text = paramv.Y.ToString();
txtb_material_param3.Text = paramv.Z.ToString();
txtb_material_param4.Text = paramv.W.ToString();
cbx_material_datatype.Text = "Vector4";
break;
}
}
}
You need to check that the SelectedIndex isn't already 0 before you try to set it:
if (cbx_material_num.SelectedIndex != 0){
cbx_material_num.SelectedIndex = 0;
}
Otherwise you're re-firing the event every time through.
I think that whenever you set this cbx_material_num.SelectedIndex = 0; within the EventHandler you invoke your
cbx_material_numobj_SelectedIndexChanged(object sender, EventArgs e)
Each call invokes another eventHandler so the stack fills up after some time.
Basically, the fact that it is called SelectedIndexChanged doesn't mean that the value has to be different from the previous one but that the value is set through its setter.
How do I do this in a loop.
protected void ddlTool_SelectedIndexChanged(object sender, EventArgs e)
{
lblTool1.Visible = false;
txtTool1.Visible = false;
lblTool2.Visible = false;
txtTool2.Visible = false;
lblTool3.Visible = false;
txtTool3.Visible = false;
lblTool4.Visible = false;
txtTool4.Visible = false;
lblTool5.Visible = false;
if (ddlTool.SelectedValue == "1")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
}
if (ddlTool.SelectedValue == "2")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
}
if (ddlTool.SelectedValue == "3")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
lblTool3.Visible = true;
txtTool3.Visible = true;
}
if (ddlTool.SelectedValue == "4")
{
lblTool1.Visible = true;
txtTool1.Visible = true;
lblTool2.Visible = true;
txtTool2.Visible = true;
lblTool3.Visible = true;
txtTool3.Visible = true;
lblTool4.Visible = true;
txtTool4.Visible = true;
}
Instead of having a separate variable for each textbox and label, have a collection of them - whether that's a List<T> or an array or whatever.
Then you can do:
// Potentially use int.TryParse here instead
int visibleLabels = int.Parse(ddlTool.SelectedValue);
for (int i = 0; i < labels.Count; i++)
{
labels[i].Visible = (i < visibleLabels);
textBoxes[i].Visible = (i < visibleLabels);
}
(Alternatively use two loops, one to set some Visible properties to true, and one to set some to false.)
You can access a control by its name using
container.Controls["nameofcontrol"]
So technically, you could use this to lookup your control
(Untested code)
for(int index = 1; index <= Convert.ToInt32(ddlTool.SelectedValue); index++)
{
this.Controls["lblTool" + index.ToString()].Visible = true;
this.Controls["txtTool" + index.ToString()].Visible = true;
}
Use a UserControl for each set of connected controls and then enable/disable the UserControl instead of all the component controls. This is classic, basic modularization of your user interface.
Note that this will still require a little "redundant" code because you're working with an unusual UI paradigm by enabling up-to the ddlTool's selected value of your control. E.g., create your user control that contains a single Label and TextBox. Call it LabeledTextBox or something similar. Then you'd create a collection of your labeled text boxes and enable them up to int.Parse(ddlTool.SelectedValue) - 1.
foreach (Control ctrl in this.Controls)
{
int index = (int)ctrl.Name.Substring(ctrl.Name.Length - 1);
int maxIndex = (int)ddlTool.SelectedValue;
ctrl.Visible = (index <= maxIndex);
}
Here is an example with no error checking, but should match your code functionality.
protected void ddlTool_SelectedIndexChanged(object sender, EventArgs e)
{
int selectedValue = int.Parse(ddlTool.SelectedValue.ToString());
for (int i = 1; i <= 4; ++i)
{
bool state = i <= selectedValue;
this.Controls["lblTool" + i.ToString()].Visible = state;
this.Controls["txtTool" + i.ToString()].Visible = state;
}
}