|
This behaviour is because you are trying to use a variable instead of a type. This goes against the nature of generics which identifies information about an object at compile time.
Now, to get around this you would use:
GetForm<Form>("myformid");
|
|
|
|
|
I know how to get around it. The thing is, I want to provide the type at runtime using reflection. The reason for this is that somewhere in the GetForm method there's a line saying:
formType ret = Activator.CreateInstance<formType>();
I need to call the specific constructor for the type that's provided. This is why simply passing type Form will not do. Since I can ensure the compiler that the type passed will be a descendant of Form, I figured there's enough information for it to work with.
Standards are great! Everybody should have one!
|
|
|
|
|
I don't understand why you would want to do this in this way. As I stated before, generics are really handled at compile time. I knocked up the following quick routine to get a form.
namespace GenericForms
{
public static class TestForms
{
public static Form ShowForm(string formName)
{
return (Form)Activator.CreateInstance(Type.GetType(formName));
}
}
} Calling this becomes as simple as GenericForms.TestForms.ShowForm("Form1").ShowDialog(); .
|
|
|
|
|
The thing is, I'm working in a MDI application and want to store and retrieve all of the forms that were open when the application last closed. Here's my code, maybe not so pretty, but I think you'll get it...
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Drawing;
using System.Diagnostics;
namespace Tools
{
[Serializable]
public class FormsPool
{
/// <summary>
/// This dictionary will store the form's properties that we want to save to file.
/// </summary>
private Dictionary<string, FormData> dataPool = new Dictionary<string, FormData>();
/// <summary>
/// And this one is used to store forms at runtime.
/// </summary>
[field: NonSerialized]
private Dictionary<string, Form> formPool = new Dictionary<string, Form>();
/// <summary>
/// Get the form with the specified id.
/// </summary>
/// <param name="form_id">Unique string identifying the form to get.</param>
/// <returns></returns>
public Form GetForm(string form_id)
{
return GetForm<Form>(form_id);
}
/// <summary>
/// Returns the form with the given id from the pool. If it's not there, it'll be constructed.
/// </summary>
/// <typeparam name="formType">The form class you want to be returned.</typeparam>
/// <param name="form_id">The id for the form to return.</param>
/// <returns></returns>
public formType GetForm<formType>(string form_id) where formType : Form
{
if (formPool == null) // make sure our dictionaries are there
formPool = new Dictionary<string, Form>(); // (deserialization can set them to be null)
if (dataPool == null)
dataPool = new Dictionary<string, FormData>();
if (this.formPool.ContainsKey(form_id)) // check out if we have a reference to the form
{
if (formPool[form_id] != null)
return formPool[form_id] as formType; // if so, return it
else formPool.Remove(form_id);
}
formType ret = Activator.CreateInstance<formType>(); // not there, so create it
if (dataPool.ContainsKey(form_id)) // check for past references to this form
{ // and get the data used in that case
ret.StartPosition = FormStartPosition.Manual;
ret.Size = dataPool[form_id].size;
ret.Location = dataPool[form_id].location;
this.formPool.Add(form_id, ret);
}
else // otherwise, reset all parameters
{
FormData data = new FormData();
data.type = typeof(formType);
this.dataPool.Add(form_id, data);
this.formPool.Add(form_id, ret);
}
// the form that was asked for has been newly instantiated, so we'll need to track movement and sizechanges
ret.LocationChanged += delegate(object sender, EventArgs e)
{
foreach (string key in formPool.Keys)
{
if (formPool[key].Equals(sender))
{
if (dataPool.ContainsKey(key))
{
Form form = sender as Form;
FormData data = dataPool[key];
data.location = form.Location;
dataPool[key] = data;
}
}
}
};
ret.SizeChanged += delegate(object sender, EventArgs e)
{
foreach (string key in formPool.Keys)
{
if (formPool[key].Equals(sender))
{
if (dataPool.ContainsKey(key))
{
Form form = sender as Form;
FormData data = dataPool[key];
data.size = form.Size;
dataPool[key] = data;
}
}
}
};
return ret;
}
/// <summary>
/// Save all formdata to a file. Look out, no errorhandling.
/// </summary>
/// <param name="filename">The filename to store our data in.</param>
public void Save(string filename)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Close();
}
/// <summary>
/// Return a formspool from file that was saved using the Save method.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public static FormsPool FromFile(string filename)
{
Stream stream;
try
{
stream = File.Open(filename, FileMode.Open);
}
catch (FileNotFoundException)
{
return new FormsPool();
}
BinaryFormatter formatter = new BinaryFormatter();
FormsPool pool = null;
try
{
pool = formatter.Deserialize(stream) as FormsPool;
}
catch { }
finally
{
if (pool == null) pool = new FormsPool();
stream.Close();
}
return pool;
}
}
[Serializable]
public struct FormData
{
public Type type;
public string form_id;
public Point location;
public Size size;
}
}
Standards are great! Everybody should have one!
|
|
|
|
|
Biggest mistake :
this code :
Type classToGet = typeof(Form);
here Form is the base class of all the forms, so u cant use base class to get the type of form.
Instead if u use as argument in typeof() any derived class of base class(Form)then it will return that derived Class and base on it this code :
Type classToGet = typeof(DerivedClassOfForm);//Return Form "derived Class"
which you can during debug time it will view as GetForm<derivedclass>("myformId")
GetForm<classtoget>("myformid");
This is difficult to explain as well as to understand .For more details learn Factory Pattern from http://www.c-sharpcorner.com.
Regards
Chintan
www.visharadsoft.com
(Nothing is so purify as KNOWLEDGE)
|
|
|
|
|
Actually it doesn't work with Form-derived classes either: The Form class was really just an example: At runtime it can be any class implementing Form. Thank you anyway, I'll try and see what I can find at c sharp corner too.
Standards are great! Everybody should have one!
|
|
|
|
|
Generics are for compile-time type resolution. For run-time types, use abstract classes or interfaces.
-----
If atheism is a religion, then not collecting stamps is a hobby. -- Unknown
|
|
|
|
|
Dictionary<string, form=""> pool = new Dictionary<string, form="">(10);
pool.Add("myformid", new LoginForm());
pool.Add("myAboutformid", new AboutForm());
public class LoginForm : Form
{
}
public class AboutForm : Form
{
}
Type typLoginForm = typeof(LoginForm);
LoginForm lf = GetForm<typloginform>("myformid");
lf.ShowDialog();
public T GetForm<t>(string form_id) where T: Form
{
return pool[form_id] as T;
}
You can change the Dictionary<string,form> to Dictionary<string, collection<form="">> to add more than 1 item under the same key. Or Dictionary<type, collection<form="">> to get a pool item with its type instead of form_id value which is string.
Fire and Water, Love and Death, Sex and the City?
|
|
|
|
|
Thanks. But this way I'll be creating a new Form eacht time the GetForm function is called, while all I really want is a reference to an existing instance of the form if it exists, or a reference to a new instance if it doesn't. This works. The real problem for me is that the pool is serializable: Some basic data (location, position) can be stored and retrieved from a file. I save the info when the application is exited. When I start it up I want it to reconstruct each instance using its respective constructor...
Standards are great! Everybody should have one!
|
|
|
|
|
No, you won't be creating a new Form each time. It was just an example,
you can replace:
pool.Add("myformid", new LoginForm());
pool.Add("myAboutformid", new AboutForm());
as
pool.Add("myformid", myAlreadyCreatedLoginForm);
pool.Add("myAboutformid", myAlreadyCreatedAboutForm());
also:
GetForm(...) code I sent you does not create anything. Do you see any "new" keyword in the code/or am I blind?
Result:
- You have an assembly created in you bin\debug folder in which your Forms are also embedded. This is your store to create the Forms at run-time. You want to store some configuration related to your forms, so what you need is to store this configuration like size and location somewhere like an xml file. If you've done it(you've written Some basic data(location, position) can be retrieved from a file), then you want to get a Form from the pool. Then your pool is the one which is responsible of returning an instance of the Form type if there is already one, created in pre-call to GetForm(...) or you want to create a new instance with the configuration parameters stored using reflection. If this is what you want:
// The configurtation of the Form you serialize/deserialize
public class FormConfig : ConfigurationProperty /*or string, or xml file, or whatever you want */
{
}
public T GetForm<t>(string form_id) where T: Form
{
if(pool.ContainsKey(form_id))
{
return pool[form_id] as T;
}
else
{
// you may have a look at other overloaded method(s) of Activator.CreateInstance
return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T;
}
}
public FormConfig GetConfig(string key)
{
return ..... // return the deserialized config
}
public FormConfig GetConfig(Type key)
{
return ..... // return the deserialized config
}
"Peace at home, peace in the world"
Mustafa Kemal Atatürk(the founder of the Republic of Turkey and its first President.))
|
|
|
|
|
Hmm, I think I might have been having a bit of an off day in explaining what I was aiming for, but you guessed about right the second time. This line of code was close enough to what I was looking for:
return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T;
I've just been staring at the same CreateInstance method without ever realizing there's a bunch of overloads to choose from. Thanks very much for the help .
Standards are great! Everybody should have one!
|
|
|
|
|
If I could help you then I'm glad to win a coder's heart
|
|
|
|
|
Hi all,
I need help regarding how to communicate with OPCServer. i am developing application in C#. In project Reference i added OPCAutomation 2.0(COM) . I am adding the code which i done .
OPCServer MyServer = null;
OPCGroups MyOPCGroups = null;
OPCGroup MYOPCGroup = null;
MyServer = new OPCServer();
MyServer.Connect(ProgID,NODE);
// till here ok
MyOPCGroups =(OPCGroups) MyServer.OPCGroups;
// but when i tried to create the OPCGroups i am getting casting error //saying that " OPCAutmation.OPCServerClass to type OPCAutomation.IOPCGroup"
MYOPCGroup = (OPCGroup)MyOPCGroups.Add("MyGroup");
any help is appreciated
Regards,
Kotha.
|
|
|
|
|
Hi!
I have the same problem
Were you able to solve it?
Would be glad for any help...
Regards,
Alessandro
|
|
|
|
|
Hi.
I want to develope an application that this application will be installed on computers of a LAN.
Now I want the DataBase(Access , SQL Server) of these applications be one and on one of the computers(Server).
i.e. I want the DB be shared between these applications.
Best wishes
|
|
|
|
|
So make the connection string of the app point to the one DB, on the LAN.
Christian Graus - Microsoft MVP - C++
"I am working on a project that will convert a FORTRAN code to corresponding C++ code.I am not aware of FORTRAN syntax" ( spotted in the C++/CLI forum )
|
|
|
|
|
And if in same time 2 want to update one table what happens?
Best wishes
|
|
|
|
|
mehrdadc48 wrote: if in same time 2 want to update one table what happens?
SQL Server is a highly scalable multi user database system. You get versions from Express upto Enterprise which can handle thousands of users simultaneously. The database engine deals with it - that's what its good at.
Upcoming events:
* Glasgow: Mock Objects, SQL Server CLR Integration, Reporting Services, db4o, Dependency Injection with Spring ...
"I wouldn't say boo to a goose. I'm not a coward, I just realise that it would be largely pointless."
Ready to Give up - Your help will be much appreciated.
My website
|
|
|
|
|
You have a few choices, you can have it as last one to update wins, you could put in a check to see if the record has been updated since the last read (sql server provides the TIMESTAMP column type for this).
You could create some sort of checkout/checkin/lock system.
It all depends on what the app is for and how it will be used. This issue is called concurrency if you want to do some searching on the subject. I personally tend towards optimistic concurrency, but that is what normally suits my apps.
|
|
|
|
|
How do I make a window application run on a network
|
|
|
|
|
What do you mean by 'run on a network' ? It will access files on the network, just pass network paths to it. You can run it over a network, point to the exe over the network. How else do you mean ?
Christian Graus - Microsoft MVP - C++
"I am working on a project that will convert a FORTRAN code to corresponding C++ code.I am not aware of FORTRAN syntax" ( spotted in the C++/CLI forum )
|
|
|
|
|
I have a various tables which gets activated as a user selects an option.I want to poulate the results in a datatable and check they are not duplicate data from each table.My datatable should contain a dataonly once no duplicates.
How do i go about that?
Is there a function that checks the data before writing it to datatable so that it cant duplicate?
Please advice
Thanks and regards
|
|
|
|
|
Not really, your database should have keys set so that it won't accept duplicates. The other way is to write a select to see if the data exists. Finally, you can insert with a stored proc that first checks if the data exists, and only inserts if it doesn't.
Christian Graus - Microsoft MVP - C++
"I am working on a project that will convert a FORTRAN code to corresponding C++ code.I am not aware of FORTRAN syntax" ( spotted in the C++/CLI forum )
|
|
|
|
|
Every table must have primary key and the Domain of each column must matches with one another to get the correct type of data in a column of the datatable.Load 1st row from i(Option selected) table to common datatable, check whether that rows is exists in common datatble,if it is then dont add the row else add them and proceed further with next row in i table.
Regards
Chintan
www.visharadsoft.com
(Nothing is so purify as KNOWLEDGE)
|
|
|
|
|
THANK YOU ALL YOUR HELP IS VERY GREAT.
|
|
|
|