PJW
PJW

Reputation: 5397

Need a better way to Iterate through Form Controls

In my WinForms application written in C# there is a Button on one Form which needs to slightly alter the appearance of a second Form (just change the Text on a Button).

I have managed to do this, but the code is horribly long, and I believe there must be a much more concise way of achieving the same thing.

Here is my code for the Button on Form frmConflicts and how it changes the Text on the Button btnAddCase on Form frmAdmin (works, but seems too long) -

private void btnNoConflicts_Click(object sender, EventArgs e)
    {
        try
        {
            foreach (Form f in Application.OpenForms)
            {
                if (f.Name == "frmAdmin")
                {
                    frmAdmin a = (frmAdmin)f;
                    a.conflictsClear = true;
                    foreach (Control ctrl in a.Controls)
                    {
                        if (ctrl.Name == "panAdmin")
                        {
                            foreach (Control ctrl2 in ctrl.Controls)
                            {
                                if (ctrl2.Name == "tabControlAdmin")
                                {
                                    TabControl tab = (TabControl)ctrl2;                                        
                                    foreach(TabPage page in tab.TabPages)
                                    {
                                        if (page.Name == "pageNewCase")
                                        {
                                            foreach (Control ctrl3 in page.Controls)
                                            {
                                                if (ctrl3.Name == "panCaseDetails")
                                                {
                                                    foreach (Control ctrl4 in ctrl3.Controls)
                                                    {
                                                        if (ctrl4.Name == "btnAddCase")
                                                        {
                                                            ctrl4.Text = "Add Case";                                                                
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            this.Close();
        }
        catch (Exception eX)
        {
            MessageBox.Show("frmConflicts: btnNoConflicts()" + Environment.NewLine + eX.Message);
        }

Any help to significantly reduce the amount of code would be much appreciated, as I am going to need to do similar interactions between Forms elsewhere in my application.

Upvotes: 2

Views: 126

Answers (5)

Daniel Lane
Daniel Lane

Reputation: 2593

You could create a public property and subscribe to a PropertyChanged event from your form, you'll need your class that has the public variable to extend INotifyPropertyChanged.

//Your class
public class ButtonText : INotifyPropertyChanged
{
   private string _buttonText;

   public string ButtonValue
   {
      get{ return _buttonText; }
      set
      {
         //Sets the value of _buttonText to the value passed in an argument 
         _buttonText = value;
         RaisePropertyChanged("ButtonValue");
      }
   }
   protected void RaisePropertyChanged(string propertyName)
   {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
         handler(this, new PropertyChangedEventArgs(propertyName));
      }
   }

   public event PropertyChangedEventHandler PropertyChanged;
}

In your form class you'd bind to the property ButtonValue property of the ButtonText class like so:

ButtonText buttonObj = new ButtonText();
//Property field to bind, object to bind, property to bind
btnAddCase.DataBindings.Add("Text", buttonObj,"ButtonValue");
buttonObj.ButtonText = "Your text to bind.";

Because the btnAddCase.Text property is bound to the ButtonValue property of the ButtonText class, your btnAddCase.Text property will reflect the value of your ButtonText.ButtonValue property at all times, it's also a two way binding.

Upvotes: 0

If the the appearance of second from require a change on first from you should solve this in another way.

The best is that your button that require a change should be open for capture the event of form two open and then apply required change.

In the place where you declare your button you should assign to it a listener that will capture the Form2 opening and then apply action.

so in the method private void btnNoConflicts_Click(object sender, EventArgs e) you should trigger event for that button to capture instead off searching it.

Upvotes: 1

progpow
progpow

Reputation: 1580

I think it`s help to you

foreach (Form f in Application.OpenForms)
{
     var controls =this.Controls.Find("btnAddCase", true);
     if(controls!=null)
        foreach(var control in controls)
        {
            control.Text="Add case";
        }
}

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460058

You could use LINQ + ControlCollection.Find:

Control btnAddCase = Application.OpenForms.Cast<Form>()
    .Where(f => f.Name == "frmAdmin")
    .SelectMany(f => f.Controls.Find("btnAddCase", true)) // true means recursive
    .FirstOrDefault();
if(btnAddCase != null)
    btnAddCase.Text = "Add Case"; 

Upvotes: 0

gzaxx
gzaxx

Reputation: 17590

If your button is added through designer and is not dynamically created the solution is simple: add a method inside your frmAdmin like

public void ChangeCaption(string caption)
{
     btnAddCase.Text = "Add case";
}

and then

var frmAdmin = Application.OpenForms.OfType<Form>().FirstOrDefault(x => x.GetType() == typeof(frmAdmin));

if (frmAdmin != null)
{
    frmAdmin.ChangeCaption("Add case");
}

Upvotes: 5

Related Questions