2

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.

5 Answers 5

5

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"); } 
Sign up to request clarification or add additional context in comments.

1 Comment

the simplicity of this answer compared to what I had is undeniable - thank you very much for this.
1

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"; } } 

Comments

1

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.

1 Comment

Finally, I was shocked no one has pointed this out much earlier... Not typical SOF
0

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"; 

4 Comments

This is a heuristic code sample. It might work but can produce unexpected results.
@Vash: OP just asked for code that does the same but is more concise("significantly reduce the amount of code would be much appreciated"). Here it is. It's also safe, it will not throw exceptions if you change a name.
That is true see at the Gzaxx answer. It meet OP requirements and will work in every case. The issue in your method is that if there ware two btnAddCase placed somewhere in hierarchy of frmAdmin then you code might fail.
@Vash: of course, but again, it is what was required. With the same arguments you could prohibit to use Control.ControlCollection.Find in general(at least the recursive). If you know what you do it might be appropriate. That said, Gzaxx answer is the better approach in every sense.
0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.