I am semi new to C# and have made multiple instances of a User Control as such
StackPanel StkPnl = new StackPanel();
StkPnl = SP; //SP being the static objRef of the StackPanel in the MainWindow
for (int i = 0; i < 5; i++)
{
UserControl UsrCtrl = new UserControl();
UsrCtrl = new UserControl1();
UserControl1.TB.Text = "Text:"+i; //TB being the static objRef of the textblock that is in the user control
UsrCtrl.Name = "UsrCtrl" + i;
StkPnl.Children.Add(UsrCtrl);
}
What I am wanting to do is be able to call each user control i made independently and edit that specific textblock.text. eg: edit UsrCtrl3's textblock without altering the other 4 user controls created.
I found it kinda hard to explain myself. Let me know if you need any clarification and ill try to do my best to explain.
You can access a specific element in a collection using the index like this:
StkPnl.Children[3].TB.Text = "Some Text"; // edit fourth user control (UsrCtrl3)
Or you can use LINQ to search on the name.
The method SingleOrDefault() expects at most one match. If no match is found, it returns null.
var thirdUserControl = StkPnl.Children.SingleOrDefault(x => x.Name == "UsrCtrl3");
if (thirdUserControl != null)
thirdUserControl.TB.Text = "Some Text";
I've found similar answers to my question before, but not quite to what I'm trying to do...
In Visual Basic (last I used it, in 06/07) there was an "Index" property you could assign to multiple controls with the same name. I used this primarily to loop through controls, i.e.:
For i = 1 to 500
picSeat(i).Print "Hello"
Next i
Is there a way to do this in C#? I know there is a .IndexOf(), but would that really help for what I'm doing? I want to have multiple controls with the same name, just different index.
This is a Windows Form Application, and I'm using Visual Studio 2012. I am talking about controls, not arrays/lists; this was possible in VB and I was wondering if it was possible at all in C#. So I want to have, say, 30 seats in a theatre. I want to have each seat represented by a picturebox named "picSeat". VB would let me name several objects the exact same, and would assign a value to a control property "Index". That way, I could use the above loop to print "Hello" in every picture box with only 3 lines of code.
No, this feature does not exist in C#, and was never implemented in the transition from classic VB to VB.Net.
What I normally do instead is put each of the controls in question in a common parent container. The Form itself can work, but if you need to distinguish these from others of the same type a GroupBox or Panel control will work, too. Then, you access the controls like this:
foreach (var picBox in parentControl.Controls.OfType<PictureBox>())
{
// do something with each picturebox
}
If you want to use a specific control, just write by name:
pictureBox6.SomeProperty = someValue;
If you need to change a specific control determined at run-time, normally this is in response to a user event:
void PictureBox_Click(object sender, EventArgs e)
{
var picBox = sender As PictureBox;
if (picBox == null) return;
//picBox is now whichever box was clicked
// (assuming you set all your pictureboxes to use this handler)
}
If you really really want the Control Arrays feature, you can do it by adding code to create the array to your form's Load event:
PictureBox[] pictureBoxes = Me.Controls.OfType<PictureBox>().ToArray();
Are we talking WinForms here? I'm not sure, but I don't think you can have multiple controls in winforms with same name. But I vaguely recall doing something similar and the solution was to name them Button_1, Button_2 etc. Then you can iterate through all controls and get your own index.
Beware though that if you want to instanciate a separate control for each seat in a theatre, you might run into some serious performance issues :) I've done something similar to that as well and ended up drawing the whole thing on a canvas and using mouse coordinates to handle the events correctly.
You may want to check out the Uid property of controls.
(http://msdn.microsoft.com/en-us/library/system.windows.uielement.uid(v=vs.110).aspx)
You can access Control through Uid property with the following
private static UIElement FindUid(this DependencyObject parent, string uid)
{
var count = VisualTreeHelper.GetChildrenCount(parent);
if (count == 0) return null;
for (int i = 0; i < count; i++)
{
var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (el == null) continue;
if (el.Uid == uid) return el;
el = el.FindUid(uid);
if (el != null) return el;
}
return null;
}
And simply use
var control = FindUid("someUid");
I copied code from this post
If you create an indexed dictionary of your user control, it will behave pretty much the same as in VB6, though you'll not see it on the VS C# GUI. You'll have to get around the placement issues manually. Still - and most importantly -, you'll be able to refer to any instance by the index.
The following example is for 3 pieces for clarity, but of course you could automate every step of the process with appropriate loops.
public partial class Form1 : Form
{
...
Dictionary<int, UserControl1> NameOfUserControlInstance = new Dictionary<int, UserControl1>()
{
{ 1, new UserControl1 {}},
{ 2, new UserControl1 {}},
{ 3, new UserControl1 {}}
};
private void Form1_Load(object sender, EventArgs e)
{
NameOfUserControlInstance[1].Location = new System.Drawing.Point(0, 0);
NameOfUserControlInstance[2].Location = new System.Drawing.Point(200, 0);
NameOfUserControlInstance[3].Location = new System.Drawing.Point(400, 0);
Controls.Add(NameOfUserControlInstance[1]);
Controls.Add(NameOfUserControlInstance[2]);
Controls.Add(NameOfUserControlInstance[3]);
}
...
}
I like using Tags to apply any type of meta data about the controls
for (int i = 0; i< 10; ++i)
{
Button button = new Button();
button.Tag = i;
}
I'm currently working on a small side project as a way of getting used to Forms in Visual Studio 2012, as I usually only work with Console Applications. My current layout is designed to use tabs, and the user is to specify how many of the tabs they need for this application. They then fill out some information and it will be formatted and output to a file at a location specified by the user. On to the questions.
In order to stop duplicate tabs from existing, I'm using the following:
private void comboTabs_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboSkills.SelectedIndex == 0)
{
tabControl1.TabPages.Remove(tab8);
tabControl1.TabPages.Remove(tab7);
tabControl1.TabPages.Remove(tab6);
tabControl1.TabPages.Remove(tab5);
tabControl1.TabPages.Remove(tab4);
}
//repeat for Index 1, 2 and so on
}
There will always be a minimum of 3 tabs, so the first selection on the combo box removes tabs 4 through 8. The next selection does the same, but then adds tab4 back again. This goes on for the following selections. Is there any way I can do this more conveniently?
Second question, each tab has a series of text boxes and combo boxes that users are to select information from. The problem I'm having is that I need to identify how many tabs the user has selected and then only pull information from those tabs. I'm aware that I can get the number of tabs with:
int numberoftabs = tabControl1.TabCount;
But after that I can't seem to read the information from them. I'm intending to do
for (int i = 0; i < numberoftabs; i++)
{
//get textbox text of tab i and so on
}
Is there any way I can do this? I was hoping to use a tab layout since I like my current layout very much. If it makes a difference, all the tabs have the same layout, and share a naming convention such as tab 1 text box 1 is textTab1Name, tab 2 text box 2 is textTab2Name and so on.
For the first part of your question, you can handle all cases with this piece of code:
var tabCount = 5 - comboBox1.SelectedIndex;
for (var i = 0; i < tabCount; i++)
{
tabControl1.TabPages.RemoveAt(7-i);
}
For the second part you will have to create this method:
private T GetControl<T>(string name) where T : Control
{
return (T) this.Controls.Find(name, true).FirstOrDefault();
}
Then you can write your text retrieval loop like this:
for (int i = 0; i < numberoftabs; i++)
{
//get textbox text of tab i and so on
TextBox textBox1 = GetControl<TextBox>("textTab" + i + "Name");
...
etc..
}
I have a TabControl that starts with three TabPages in it. On the first tab there is a NumericUpDown (spinner) which displays the number of tabs and allows a user to add up to 10 extra tabs. Once they add more than about 5 or 6 it goes beyond the width of the form and the rest of the tabs are accessible by a couple of left/right arrows at the top. When going all the way to the right and then using the spinner to go back down to 0 (removing all the extra tabs and leave the starting three) it removes all tabs from the top of the pane and only by setting the spinner back to 1 does it refresh and display all 4 (3 from the start plus the 1 from the spinner).
I have tried several commbinations of
Application.DoEvents()
this.Refresh()
this.Invalidate()
this.Update()
but nothing seems to work. can anybody suggest a reason why it is not updating/refreshing?
public partial class Form1 : Form
{
TabPage[] tabs;
public Form1()
{
InitializeComponent();
tabs = new TabPage[tabControl1.Controls.Count];
tabs[0] = tabPage1;
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
int numTabs = tabControl1.Controls.Count;
decimal spinnerValue = numericUpDown1.Value;
if (numTabs < spinnerValue) //add a tab
{
TabPage[] newTabs = new TabPage[(int)spinnerValue];
for (int i = 0; i < numTabs; i++)
{
newTabs[i] = tabs[i];
}
TabPage tab = new TabPage("Tab " + numTabs);
newTabs[(int)spinnerValue-1] = tab;
tabControl1.Controls.Add(tab);
tabs = newTabs;
}
else //remove a tab
{
TabPage[] newTabs = new TabPage[(int)spinnerValue];
for (int i = 0; i < spinnerValue; i++)
{
newTabs[i] = tabs[i];
}
tabControl1.Controls.Remove(tabs[(int)spinnerValue]);
tabs = newTabs;
}
}
}
Without seeing any code or knowing what type of project this is winforms, WPF, ASP.NET etc..
it's hard to give a definite answer, I am going to assume that this is WinForms
I'm not sure if you can. The following is a quote from MSDN:
"Controls contained in a TabPage are not created until the tab page is shown, and any data bindings in these controls are not activated until the tab page is shown."
However, instead of having the update code get the values from the controls directly, maybe you could create a class that could hold the Data you use to populate the controls and then when the update code is called it asks the class for the value and the class checks if the control is loaded and otherwise it gets the value from the Data instead.
I would like to know how it's possible to change button properties by a code when we don't know a button name while writing it.
For example, I have a loop like this:
for (int i=0; i<5; ++i) {
int buttonName = "button_" + i;
buttonName.enabled = false;
}
Thanks in advance!
You can access the Controls collection of the parent containing the button like this:
if(parent.Controls.ContainsKey(buttonName))
{
Button myButton = (Button)parent.Controls[buttonName];
myButton.Enabled = false;
}
This will need a little extra work if your buttons are not contained within the same parent; ie. some buttons on a Form, some buttons on a Panel contained within that same form.