AnnNeedsHelp

Suppose you have the name of the form :
string fname = "FormSomething";

How do I create a form object with fname as name Apparently this is not enough:
Form f = new Form();
f.Name = fname;

Also tried:
f.CreateControl();


Can anyone please tell me how to get the form object Thanks!!!


Re: Windows Forms General from string to form

Brendan Grant

Assuming you know the full name of the form (namespace & class name) and what assembly it is in you can do something like this:

Type t = Assembly.GetExecutingAssembly().GetType("MyTestApp.FormSomething");
Form f = (Form)Activator.CreateInstance(t);

This code does three things. First, it located a specified assembly, in this case the main executing one, you could also use GetCallingAssembly() or GetEntryAssembly() depending on your needs.

From that we request information on the specified type, if found we end up with a reference to a Type instance that describes the type in question.

Assuming the return value is not null (which I didn¡¯t check for above), we use Activator.CreateInstance() to create a new instance of the specified type and so we can reference it like a form, we typecast the result as well.






Re: Windows Forms General from string to form

AnnNeedsHelp

I get an error on the second line:

A MissingMethodException exception is thrown when there is an attempt to dynamically access a method that does not exist.

Associated Tips

If a method in a class library has been removed or renamed, recompile any assemblies that reference that method.

This exception is typically thrown when an attempt is made to dynamically access a deleted or renamed method of an assembly that is not referenced by its strong name.


Could you help me again, please





Re: Windows Forms General from string to form

Figo Fei - MSFT

Hi,

What about form.name (its property). So, what do you really want To call the form by "FormSomething" Or some other use

If you want to show the "name" on the title bar just use form.text

Thanks






Re: Windows Forms General from string to form

Figo Fei - MSFT

Anyway, this may be helpful to you: http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.name(VS.80).aspx

Thanks






Re: Windows Forms General from string to form

Mark Dawson

Hi,

do you have an empty constructor defined in your form I believe you will need one to allow the object to be created this way.

Mark.






Re: Windows Forms General from string to form

AnnNeedsHelp

Thx for the replies, but it works once. It's in a while loop and it does what it should do the first time. The second time it gives the error mentioned above.




Re: Windows Forms General from string to form

AnnNeedsHelp

Anyone on the MissingMethodException error It's driving me nuts. I don't understand why it would work once and then go wrong on the second time.




Re: Windows Forms General from string to form

Mark Dawson

Hi,

do you have a code sample that shows the problem

Mark.






Re: Windows Forms General from string to form

AnnNeedsHelp

public class FormsCollection : CollectionBase
{
public Form Add(Form FormObject)
{
base.List.Add(FormObject);
return (FormObject);
}
}
private void butCreateAll_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.GetExecutingAssembly();
ArrayList result = new ArrayList();

foreach (Type type in asm.GetTypes())
{
if (type.IsSubclassOf(typeof(Form)) && type.Namespace == "ns")
{
result.Add(type);
CreateForm(type);
}
}
}
public Form CreateForm(Type formType)
{
if (formType == null) throw new ArgumentNullException("");
object obj = Activator.CreateInstance(formType);
return obj as Form;
}

For now, there is a collection 'result', creating a collection of all forms in my application. I won't need it if the CreateForm were to work. Basically, I have two options. Either the CreateForm (CreateInstance) works or I use the items in the result Collection. I thought I would be able to use the items in result as Forms, but apparently I can't.




Re: Windows Forms General from string to form

Mark Dawson

Hi,

I ran this little exaple using your code and it works correctly, where two forms are created:

using System;

using System.Collections;

using System.Collections.Generic;

using System.Windows.Forms;

using System.Reflection;

namespace ns

{

static class Program

{

[STAThread]

static void Main()

{

FormsCollection fc = new FormsCollection();

fc.butCreateAll_Click(null, null);

Application.Run();

}

}

class Form1 : Form

{

public Form1()

{

this.Text = "Form1";

}

}

class Form2 : Form

{

public Form2()

{

this.Text = "Form2";

}

}

public class FormsCollection : CollectionBase

{

public void butCreateAll_Click(object sender, EventArgs e)

{

Assembly asm = Assembly.GetExecutingAssembly();

foreach (Type type in asm.GetTypes())

{

if (type.IsSubclassOf(typeof(Form)) && type.Namespace == "ns")

{

Form f = CreateForm(type);

f.Show();

}

}

}

public Form CreateForm(Type formType)

{

if (formType == null) throw new ArgumentNullException("");

object obj = Activator.CreateInstance(formType);

return obj as Form;

}

}

}

Mark






Re: Windows Forms General from string to form

AnnNeedsHelp

I don't get it. If I disregard the FormsCollection part (since you're not really using it and I might not either), the code seems to be the same. No




Re: Windows Forms General from string to form

JJ Jordan - MSFT

Hi Ann,

I'm a bit confused regarding the nature of your question. Are you trying to go from a string that specifies the name (type) of a form to a Form of that type I'm assuming this is the case (if not, then please let me know).

As for the MissingMethodException, my guess (aligned with Mark Dawson's earlier comment) is that one of the forms in your project does not have a no-argument constructor. This is why you see the exception sometimes but not others. You can track it down by changing your CreateForm method as follows:

public Form CreateForm(Type formType)
{
  if (formType == null) throw new ArgumentNullException("");
  Debug.Assert(formType.GetConstructor(Type.EmptyTypes) != null, string.Format("{0} does not have a no-arg constructor", formType.Name));
  object obj = Activator.CreateInstance(formType);
  return obj as Form;
}

Make a debug build and run the app (note that Debug is in System.Diagnostics). You should see assertion windows that give you all the information you need to debug it. For any Form type that gives this assertion, make sure that the form has a no-argument constructor (add one if necessary). If you can't for any reason, then it may be time to re-think what you're doing.

Also, you can't treat the objects inside 'results' like Forms, because the objects inside of 'results' are Type objects, not Form objects. The former represents the reflected CLR type (see the Type class: http://msdn2.microsoft.com/en-us/library/system.type.aspx) complete with methods, properties, constructors, et al. The latter are the actual, running Form objects that are instantiated from the type. The objects are related, but not identical.

Hope this helps,






Re: Windows Forms General from string to form

AnnNeedsHelp

Seems you're right. Apparently, 93 of the 254 forms don't have a no-argument constructor. Now, if anyone could tell me how to handle this...

Let me give you a little more of what I want to do. I have a project with lots of forms that each get translated through a function called in each form, that is, every ".Text" of each control on the form gets written in the database to be translated. If the translation is available the form will display the translated ".Text" otherwise it just uses the standard English text. All of this is regulated by that one function. Problem is, the text of the controls only makes it to the database after a form has been opened. I hate going through each form every time there's a new version of the software just to be able to translate. I also always seem to miss some of them. So I want to write something that does this for me.

There are two ways of doing this:
1. for each form: show, create an instance or whatever
2. just use the function on each form without showing, ... it

First I tried finding each form through the solution or application, but since I couldn't make it work, I then listed all the forms by searching the directories for their files. Thus, the question how to go from a string to a form.

A few days ago, I found the code above through the assembly (which works great), so I'm no longer going from a string to a form, but from a type to a form. And that's where it goes wrong!




Re: Windows Forms General from string to form

John.Doe

Change your CreateForm method to this one below. The idea is that if a default constructor exists, just use it as your current one does. Otherwise loop through the available constructors and try to create the required parameters. This works only if the parameters do have a default constructor at least or if they do have a complex type as a parameter with a non default constructor, but the parameter is allowed to be null. But even that might still fail IF:
- the form requires special values to work, e.g. one of the parameters is an int, but it has to be in between 100 and 200 - the default value generated would always be 0, so the constructor might then blow up
- the form has a complex type with a non default constructor and the value cannot be null

Hope that helps, I put a few comments in there, too...

public Form CreateForm(Type formType)

{

if (formType == null) throw new ArgumentNullException("");

object obj = null;

ConstructorInfo[] constructors = formType.GetConstructors();

// try to find a default constructor

ConstructorInfo defaultConstructor = null;

foreach (ConstructorInfo constructor in constructors)

{

ParameterInfo[] parameters = constructor.GetParameters();

if (parameters.Length == 0)

{

defaultConstructor = constructor;

break;

}

}

 

// found one perfect, use it

if (defaultConstructor != null)

{

obj = Activator.CreateInstance(formType);

}

else

{

// no default constructor...

// try each constructor if we can create the required parameters

foreach (ConstructorInfo constructor in constructors)

{

try

{

ParameterInfo[] parameters = constructor.GetParameters();

object[] p = new object[parameters.Length];

for (int i=0; i<parameters.Length; i++)

{

// ignore failed approaches to create a parameter

// it might be a class with a non default constructor, but

// then it might also be valid to pass in null as a value

try

{

ParameterInfo parameter = parameters[ i ];

p[ i ] = Activator.CreateInstance(parameter.ParameterType);

}

catch { }

}

// try to create the form

obj = Activator.CreateInstance(formType, p);

// if we come to this point, we got an instance -> break

break;

}

catch { }

}

}

return obj as Form;

}