Dynamic menus

T

tonFrere

Hello all,
I did a lot of research on the subject and came to the
conclusion that what I want to do might not be "good practice". I
created a set of table to manage user rights to forms in my solution
and hope I might be able to auto-generate the menu at solution startup.

I successfully created the menu structure but am stuck trying to add
code to the click event of my menuitems.

The database sends me the string name of the form to open. Now, how can
I instantiate a form by it's string name? Did I mention that I'm new to
OOP... I realise that I might be completely wrong trying to do such
thing. Is there a better approach to creating dynamic menus?

Hope this is clear enough...

Herre is how I generate the click event for each menuitem:
tsCont.Click += new System.EventHandler(this.toolStrip_Click);

Here is my test code for the click event:
private void toolStrip_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Test");

}

I need to open the form refered by the "project" string property of the
sender object (class is tsmiWithProject)?

Thanks!
Justin
 
N

Nicholas Paldino [.NET/C# MVP]

Justin,

See inline:
The database sends me the string name of the form to open. Now, how can
I instantiate a form by it's string name? Did I mention that I'm new to
OOP... I realise that I might be completely wrong trying to do such
thing. Is there a better approach to creating dynamic menus?

In order to create the form, or any other object dynamically, you will
have to call the static CreateInstance method on the Activator class. It
will take a Type instance which it will create an instance of. You will
probably also need to call the static GetType method on the Type class to
get the Type instance that you are referring to.

Make sure that you are storing the assembly-qualified full name of the
type, unless you are loading the form from one single library (and will only
ever load it from that library).
Hope this is clear enough...

Herre is how I generate the click event for each menuitem:
tsCont.Click += new System.EventHandler(this.toolStrip_Click);

Here is my test code for the click event:
private void toolStrip_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Test");

}

Well, when you create the forms, I would suggest putting them in a
Dictionary that is keyed by this string, and then in your Click event
handler, perform a lookup for the form.

Hope this helps.
 
T

tonFrere

Thanks for the very fast reply. I think all I need to do is to read on
Dictionaries. MSDN, here I come! ;)

Thanks again,
Justin
 
T

tonFrere

Nicholas,
I spent the day working with dictionaries and learn a lot on how it
will help me. Thanks a lot. I just have a some questions though just to
be sure I understand everything right. I hope you have a few minutes to
answer since I still have difficulties finding answer to my questions
on MSDN.

Is it possible to "save" my dictionary (let say in a dll or something)
or is it just a runtime object?
In that case, must I fill my dictionary each time the application
launches?
Is it ok to create my dictionary as <string, form>? I tried working
with types but I'm a little confuse with them.

Thanks a lot!
Justin

tonFrere a écrit :
 
J

Jianwei Sun

tonFrere said:
Nicholas,
I spent the day working with dictionaries and learn a lot on how it
will help me. Thanks a lot. I just have a some questions though just to
be sure I understand everything right. I hope you have a few minutes to
answer since I still have difficulties finding answer to my questions
on MSDN.

Is it possible to "save" my dictionary (let say in a dll or something)
or is it just a runtime object?
In that case, must I fill my dictionary each time the application
launches?
Is it ok to create my dictionary as <string, form>? I tried working
with types but I'm a little confuse with them.

Thanks a lot!
Justin

tonFrere a écrit :

I am not an expert as Nicholas, but here is my answer to your question.
1> You can serialize the dictionary into xml file, and load it from xml
file too. You can serialize it into other format like binary stream too.

2> You should be able to create the dictionary as <string, form>.
 
B

Bruce Wood

tonFrere said:
Nicholas,
I spent the day working with dictionaries and learn a lot on how it
will help me. Thanks a lot. I just have a some questions though just to
be sure I understand everything right. I hope you have a few minutes to
answer since I still have difficulties finding answer to my questions
on MSDN.

Is it possible to "save" my dictionary (let say in a dll or something)
or is it just a runtime object?

You can serialize a dictionary, but I believe that the point here is to
avoid storing class names in your database. In other words, store a
code in the database to indicate which form you want, and then provide
a mapping in your program that says, "This code means this form."

If you then serialize that dictionary (mapping) into the database, it
defeats the whole purpose of having it, which is to decouple your
database information from your program design.
In that case, must I fill my dictionary each time the application
launches?

Yes. Just make a little method that fills in your dictionary and call
it on start-up. Or, if you like, put the mapping into your App.config
file. It's probably simplest to just put it directly in code rather
than a config file, since you would have to change the code to add a
new form, etc. anyway.
Is it ok to create my dictionary as <string, form>? I tried working
with types but I'm a little confuse with them.

Yes, that's fine. It implies that you'll be using string codes in your
database to represent your different forms, which is fine.
 
T

tonFrere

Hello again,
I think I'm doing well so far, thanks to you guys.

Could you just validate this code. Maybe there's a better way to do
things, I'm just not 100% sure about that code. The results are there
but I would rather do things right.

This is from my forms dictionary class constructor. It's how I add each
form to the dictionary:
Form2 f2 = new Form2();
add(f2.Text, f2);
REM: The "code" I'm using is the form header. I just have to make sure
it's the same name in the database.

Then, on my click event, I open the correct form using that code in a
try/catch block:
dictProjet.TryGetValue("Form2", out nouvForm);
nouvForm.Show();

Works well, just wonder if it's "swell" ;)

Justin
 
B

Bruce Wood

tonFrere said:
Hello again,
I think I'm doing well so far, thanks to you guys.

Could you just validate this code. Maybe there's a better way to do
things, I'm just not 100% sure about that code. The results are there
but I would rather do things right.

This is from my forms dictionary class constructor. It's how I add each
form to the dictionary:
Form2 f2 = new Form2();
add(f2.Text, f2);
REM: The "code" I'm using is the form header. I just have to make sure
it's the same name in the database.

Then, on my click event, I open the correct form using that code in a
try/catch block:
dictProjet.TryGetValue("Form2", out nouvForm);
nouvForm.Show();

Works well, just wonder if it's "swell" ;)

This code does something different from what I originally understood.

I thought that you would fetch from the database an indication of
_which type_ of form to create, and then instantiate that form.

The code you just posted instantiates all of the forms and then shows
them based on a value read from the database.

I was thinking of something more along these lines (please note that
this is written for .NET 1.1; someone else can no doubt provide a
superior implementation using generics):

Hashtable formTypes = new Hashtable();
formTypes["DBCODEFORFORM1"] = typeof(Form1);
formTypes["DBCODEFORFORM2"] = typeof(Form2);
....

The important thing to notice here is that the codes used to look up
the form types don't correspond to any property of the form. That way,
you can change the form title, or even the form name, and you don't
have to fix your database tables.

Once you have the table set up, when you retrieve a code from the
database you can create the form using System.Reflection:

using System.Reflection;

Type typeOfFormToCreate = (Type)formTypes[codeFromDatabase];
if (typeOfFormToCreate == null)
{
... error: bad code in database ...
}
else
{
ConstructorInfo ci =
typeOfFormToCreate.GetConstructor(Type.EmptyTypes);
if (ci == null)
{
... error: Form has no public no-argument constructor ...
}
else
{
Form newForm = (Form)ci.Invoke(null);
... do something with the newly created form ...
}
}

One important difference between this code and yours is that you can
create multiple instances of the same form this way, if you want to.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top