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