Search code examples
c#linqcontrolsreadonlytabstop

Is there a LINQy way to set all ReadOnly controls' TabStop to false?


I'm setting the TabStop property of all controls whose ReadOnly property is true to false with this code:

foreach (Control control in this.Controls)
{
    if (control is TextBox)
    {
        //if (((TextBox)control).ReadOnly)
        //{
        //    control.TabStop = false;
        //}
        control.TabStop = (!((TextBox)control).ReadOnly);
    }
}

...but I reckon there's probably a more "modern" (elegant/fancy) way of doing this, probably with LINQ.

UPDATE

Okay, so I thought, based on the answers, that this would work:

private void FrmDelivery_Load(object sender, EventArgs e)
{
    var q = Controls.SelectMany(c => Walk(c)).OfType<TextBox>().Where(c 
=> c.ReadOnly);
    foreach (var control in q)
    {
        control.TabStop = false;
    }
}

IEnumerable<Control> Walk(Control control)
{
    yield return control;
    foreach (var child in control.Controls.SelectMany(c=> Walk(c)))
    {
        yield return c;
    }
}

...but I get:

"'System.Windows.Forms.Control.ControlCollection' does not contain a definition for 'SelectMany' and no extension method 'SelectMany' accepting a first argument of type 'System.Windows.Forms.Control.ControlCollection' could be found (are you missing a using directive or an assembly reference?)"

-in both instances where SelectMany is used (and it doesn't appear to be resolvable); and, on the "yield return c" line:

"The name 'c' does not exist in the current context"

UPDATE 2

For my simple scenario (no containers / controls within controls), this works

foreach (Control control in this.Controls)
{
    var txtbx = control as TextBox;
    if (txtbx != null)
    {
        txtbx.TabStop = (!txtbx.ReadOnly);
    }
}

Solution

  • To linqify your example:

    foreach (var control in Controls.OfType<TextBox>().Where(c => c.ReadOnly)
    {
        control.TabStop = false;
    }
    

    However, your example does not process all controls because a Control can contain other control. You will need a recursive descent algorithm.

    IEnumerable<Control> Walk(Control control)
    {
       yield return control;
       foreach (var child in control.Controls.SelectMany(c=> Walk(c)))
       {
          yield return c;
       }
    }
    
    var q = Controls
      .SelectMany(c => Walk(c))
      .OfType<TextBox>().
      .Where(c => c.ReadOnly);
    foreach (var control in q)
    {
        control.TabStop = false;
    }