C# GUI – Finding controls by name

With a C# GUI created in WPF, you can end up with large amounts of mark-up code in XAML defining your UI, and even more C# controlling the UI behaviours and propagating changes to the back-end. In some cases, you might have twenty controls with similar names. Hard-coding the name of the control each time you wish to use it means you need to repeat a lot of code. For example, if you were making a checker board of squares, each square would be its own control on the UI canvas. This can quickly add up to a lot of code, and a lot of controls which you wish to modify.

If we work with the example of changing the fill colours of rectangles based on some user input (button click, etc.), then we can see that we can end up with a lot of repetitive mark-up very quickly. If we have eight rectangles, we have eight control names to deal with. But if we only want to change the colour of the even-numbered rectangles, we would end up with a lot of repetitive code to do this using the control names manually (see the example below).

private void ChangeColour
{
    var converter = new System.Windows.Media.BrushConverter();
    var b = (Brush)converter.ConvertFromString("#000000");
    R2.Fill = b;
    R4.Fill = b;
    R6.Fill = b;
    R8.Fill = b;
    //So on and so forth....
}

As we can see in the example above, we can quickly end up with large methods just to change the colour of some rectangles. But there is a simpler way.

Using the grid component

In this previous post I showed how we can use the grid component to allow us to put multiple UI controls within the group box component. We can also use the grid component to group similar items without adding anything to the UI, which can come in useful for the back-end when you don’t need to show the user that these elements are grouped.

As with all controls, you can give a name to the grid area to uniquely identify it on the canvas and in the code. This allows us to call the grid component within the C# code. For the purpose of demonstration, assume we have a grid with the name “CheckerBoard” which looks after our range of rectangles.

Finding a control by its name

Using the grid component to look after all our rectangles gives us access to a method by which we can begin to find other UI controls by their name.

object i = CheckerBoard.FindName("R1");
Rectangle myRect = (Rectangle)i;

The “FindName” method takes a string parameter which would be the name of the control you wish to find. The method returns an object which you would then need to cast back to the control type you’re using, as we’ve done in the example to cast the object back to a rectangle. From there, we can access the control as we would normally.

However, simply finding the name based on the string of the name doesn’t save us any additional code, as we’d simply have to type the control name each time we wanted to find it. But we can save this with a nice for loop.

Using a loop to change multiple controls

Let’s assume we want to change the colour of the even-numbered rectangles again. If we store the names of the controls in a list of strings (which we can create in the constructor very easily), then we can loop through the list to find the controls we want to modify.

Quickly fill a list with names

Because we have a naming convention for our rectangles (letter R followed by a number), we can quickly populate a list in the constructor like so:

List<String> myNames;
public MyConstructor()
{
    myNames = new List<String>();
    for(int x = 1; x < 9; x++)
    {
        //From 1 - 8
        myNames.Add("R" + x.ToString());
    }    
}

Looping through the list to find controls

Using the pre-populated list above, we can then loop through the list of names to find controls and make modifications without repeating large amounts of code, like so:

private void ChangeColour()
{
    var converter = new System.Windows.Media.BrushConverter();
    var b = (Brush)converter.ConvertFromString("#000000");
    for(int x = 1; x < myNames.Count; x+=2)
    {
        //Skipping every other name to only get the even numbers. x starts at 1 because the first name in the list is "R1" with a 0 index. So the first name with an even number is at index 1
        object r = CheckerBoard.FindName(myNames[x]);
        Rectangle myRec = (Rectangle)r;
        
        myRec.Fill = b;
    }
}

Hopefully this saves you from having to repeat tedious amounts of code to change multiple controls at the same time, or for programmatically finding the names of components (e.g. based on user text input for example) to modify.

Leave a Reply

Your email address will not be published. Required fields are marked *