2

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.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Daevin
  • 778
  • 3
  • 14
  • 31
  • Are you talking of collections? `var pics = new List(); ... var picOne = pics[0];` (note the brackets in C# instead of parentheses in VB) – Tim Schmelter Nov 22 '13 at 15:02
  • A control must have a unique name. Some controls have properties which are collections, which you can sometimes (most of the time actually) access by index. But I'm not even sure we're talking about controls here...are you talking about variables (arrays ?) ? – Laurent S. Nov 22 '13 at 15:03
  • @TimSchmelter I think so, I remember in VB6 you could create multiple, say, buttons with the same name, that would then share an event handler along with the index of the button that called it. I don't know if you can do this in .NET anymore. – helrich Nov 22 '13 at 15:04

5 Answers5

6

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();
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • What feature was it, i have used VB.NET for 12 years but i've never used such a "index-property"? – Tim Schmelter Nov 22 '13 at 15:11
  • It was called Control Arrays, and was part of VB6 and earlier. They were never implemented for VB.net (a good thing, imo. I wish they had been as smart with default form instances). – Joel Coehoorn Nov 22 '13 at 15:14
  • Thanks, Joel. I was really hoping it would be possible, it'd make my assignment easier :P. If I'm going to use either of your other suggestions, I have 2 questions: 1) If I use the handler, how can I differentiate between each box selected (what is contained in `sender`?) or 2) How can I organize the array to control which picBox gets which index in the array? – Daevin Nov 22 '13 at 15:26
  • @Daevin `sender` is the box that initiated the event. You click on a box, and that box will be the sender. It's index will be irrelevant. I promise. For (2), you can use an OrderBy()... but I think you'll find when you dig into this that you don't need to or, at least, if you're building a grid of theater seats, writing a line of code for each seat to assign it a specific spot in a 2-d array may be more appropriate. – Joel Coehoorn Nov 22 '13 at 15:29
  • @Joel Coehoorn Alright, thanks. So using your handler, I could have `var picBox = sneder As PictureBox` and then do `picBox.Name` and it would return the correct picture box's name? – Daevin Nov 22 '13 at 15:58
  • That is correct, but I would hesitate before doing that. It may indicate you're thinking too much in the old model. – Joel Coehoorn Nov 22 '13 at 16:02
  • Yeah, makes sense... so you would suggest just adding the seats line by line into a 2D array then? – Daevin Nov 22 '13 at 16:06
  • Maybe: I'd need to know a _lot_ more about your application to make that kind of recommendation. – Joel Coehoorn Nov 22 '13 at 16:07
  • Oh... well, it's an assignment for a class, I need to create a program that lets people reserve seats... I was thinking of using the handler, and having each box named picSeatA1/picSeatA2/picSeatB1/etc, then use `picSeat = sender As PictureBox` and `seatChoice = picSeat.Name` and use string manipulation to isolate the "A1"/"A2"/"B1"/etc, and have it store that beside their name in a listview box to track who has what seat... – Daevin Nov 22 '13 at 16:14
0

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.

Snorre
  • 955
  • 1
  • 5
  • 18
  • Every control which is placed in the designer must have a unique name, but it is possible (and not difficult) to create controls at run-time which do not have any sort of name (much less a unique one). Placing a control named `Foo` in the designer will create a class-level variable named `Foo` into which will be stored a reference to that control. Every control must be given a name which would be valid for its associated variable (and that in turn requires uniqueness). Code which creates controls at run time can store them however it sees fit; it need not use named variables. – supercat Dec 05 '13 at 18:01
0

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

Community
  • 1
  • 1
Fever
  • 251
  • 1
  • 5
  • 12
0

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]);
        }

        ...

    }  
gabmmm
  • 1
0

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;
}
vikingfabian
  • 451
  • 5
  • 5