Home > Software engineering >  Call public method from Form Collection Question
Call public method from Form Collection Question

Time:11-30

I am hiding and showing forms through Form Collection as a user timeout feature and need to call a public method in each form as I am showing it again to update the form with the logged in user (in the event it changes).

I am, however, having issue with this as it does not seem that I am able to do this direct from the iteration of the form collection. Does anyone have any recommendations?

Here is the code that I am working off of. Any help is very much appreciated!

FormCollection fc = Application.OpenForms;

foreach (Form frm in fc)
{
  if (frm.Visible == false && frm.Name != "FStart" && frm.Name != "FMain")
  {
     //Here I would like to call frm.UpdateUser(.....);
     frm.Show();
  }
}

I appreciate everyone's help. The method is a public void in each form.

I've tried to access the public method from the form collection and I've tried to access the method directly.

CodePudding user response:

The first potential issue in your code is that you are iterating the Application.OpenForms collection in hopes of finding instances where Visible==false. However, the Application.OpenForms won't contain forms that have never been visible and (depending on the method of closure) may not contain forms that are subsequently hidden. Since your first loop condition may evaluate to false, the frm.Show() line is not guaranteed to execute.

One solution would be to make your own collection of Forms and iterate that instead.

public partial class MainForm : Form
{
    /// <summary>
    /// Mixed list of Form references where "some" will implement `UpdateUser`
    /// </summary>
    List<Form> AllForms = new List<Form>();

    public MainForm()
    {
        InitializeComponent();
    }
    protected override void onl oad(EventArgs e)
    {
        base.OnLoad(e);
        AllForms.Add(this);
        AllForms.Add(new UserFormA());
        AllForms.Add(new UserFormB());
    }
}

The second issue is that your syntax tells the compiler to interpret the loop object as a Form in your loop foreach (Form frm in fc)... however the Form class itself doesn't have a UserUpdate method. Before the UpdateUser method can be called we need to ascertain that the specific inherited class in your collection is one that supports the UpdateUser method and one of the more robust ways to do this is make an interface (we can call it IUpdatableUserForm) and choose which of your inherited Form classes will implement it. For example:

interface IUpdatableUserForm
{
    void UpdateUser();
    string Name { get; set; }
    bool Visible { get; set; }
    public void Show(IWin32Window owner);
}
public class UserFormA : Form, IUpdatableUserForm
{
    public UserFormA()
    {
        Name = nameof(UserFormA);
    }
    public void UpdateUser()
    {
        Size = new Size(500, 300);
        Text = Name;
    }
}

Now, as you iterate the collection on Form you can ensure that a particular inherited Form implements the UpdateUser method using the is operator and only call the method if it is present. (By way of comparison, the dynamic keyword will throw an exception if it encounters a derivative of Form that does not implement UpdateUser).

private void onTest()
{
    foreach (Form frm in AllForms)
    {
        if (frm is IUpdatableUserForm safeForm)
        {
            if (!safeForm.Visible)
            {
                switch (safeForm.Name)
                {
                    case "FStart":
                    case "FMain":
                        break;
                    default:
                        // Here I would like to call frm.UpdateUser(.....);
                        safeForm.UpdateUser();
                        safeForm.Show(this);
                        break;
                }
            }
        }
    }
}

screenshot

CodePudding user response:

Try using the dynamic keyword to access the method, UpdateUser. Here is an example:

FormCollection fc = Application.OpenForms;

foreach (dynamic frm in fc)
{
    if (frm.Name != "FStart" && frm.Name != "FMain")
    {
       frm.UpdateUser(); //You will still have to add the arguments....
       frm.Show();
    }
 }

Just remember that when you use the dynamic keyword, it does not care what methods you try to call, or the arguments you supply to them, so just be careful when using it.

  • Related