davearia Posted May 21, 2005 Posted May 21, 2005 Hi All, I have an application that queries a table to return the name of user controls that I have in my application. I want to use this to create the controls dynamically at runtime. So I have my results stored in ds.Tables("myTable") and it returns a resulting VarChar ctlMyControl. Normally you would create and add it to the form like this: Private ctl As New ctlMyControl Me.pnl.Controls.Add(ctl) How do I create this control in my code using the results returned from the query? Thanks, Dave. :D :D :D Quote
Leaders snarfblam Posted May 21, 2005 Leaders Posted May 21, 2005 I haven't tried this, but can it be done using reflection? (Imports System.Reflection) Dim Assm As [Assembly] = _ [Assembly].GetExecutingAssembly Dim Control As Object = Assm.CreateInstance("Namespace.TypeName") 'TypeName must be fully qualified Quote [sIGPIC]e[/sIGPIC]
APaule Posted May 21, 2005 Posted May 21, 2005 Sorry marble eater, I think this won't work either (in fact I tried it, because I wanted to know). ;) I know another way (which doesn't work in this case either :D ) where you don't even have to import the Reflection namespace. Dim vType As Type = Type.GetType("System.Windows.Forms.Button") Dim vInstance As Object = Activator.CreateInstance(vType) The problem is that the CreateInstance method of the Assembly class as well as the GetType method of the Type class, expects a System.Type.Fullname. And as you can try with "System.Windows.Forms.Button" which is the fullname of a button's type you get an objectreference of nothing. So it seems that these methods only work with classes of your own assemblies ("Projectnamespace.Classname"). That's strange. :confused: Any idea? Quote
IngisKahn Posted May 21, 2005 Posted May 21, 2005 That's because there's no System.Window.Forms.Button in your executing assembly. You need to use CreateInstance on the WindowsForms assembly. Quote "Who is John Galt?"
davearia Posted May 22, 2005 Author Posted May 22, 2005 Has anyone got anymore ideas? Thanks for the help so far. :D Has anyone got anymore ideas? Thanks, Dave. :D :D Quote
Himo Posted May 22, 2005 Posted May 22, 2005 I don't think it would be possible. You could never deceive the compiler in using a field for a class constructor. I would put my hope into a Switch statement and just call the constructors with the parameters from the database. Quote For questions about VS .net extensibility, please fire at me! :) For readability, please use the [ CS][/CS ] tags
APaule Posted May 22, 2005 Posted May 22, 2005 You need to use CreateInstance on the WindowsForms assembly. Can you be more specific. What do you gain by that and what are the next steps after that? Well to be honest, I think we all try to find a perfect and elegant solution to devearia's problem. So we look for a solution with the highest degree of freedom. But as long as we can't provide a "perfect" solution we should give any solution that resolves the problem for the moment. I would say there is a "quick and dirty" one on that. Supposing that a record of the table contains the fields, that describe the properties of a control, there is one field that contains the type of it. Then devearia could do the following:For Each r as DataRow in ControlTable.Rows Select Case r("CtrlType").ToString Case "Button" Dim B as New Button 'assign all properties and handlers Me.Controls.Add(B) B = Nothing Case "TextBox" 'and so on End Select Next Not really elegant and very, very stiff, but for the moment it will do. Meanwhile we are looking for a better solution. :-\ Quote
*Experts* mutant Posted May 22, 2005 *Experts* Posted May 22, 2005 I don't get what everyone is having problems with :), but simple reflection work solves this problem (let's take a look at the button for example): //First we get the required assembly. Assembly btnassembly = Assembly.GetAssembly(typeof(System.Windows.Forms.Button)); //And then simply create the button. Button btn = (Button)btnassembly.CreateInstance("System.Windows.Forms.Button", false); Unless I'm missing something from your problem (and other posts), this should work on any assembly. Quote
APaule Posted May 22, 2005 Posted May 22, 2005 //First we get the required assembly. Assembly btnassembly = Assembly.GetAssembly(typeof(System.Windows.Forms.Button)); //And then simply create the button. Button btn = (Button)btnassembly.CreateInstance("System.Windows.Forms.Button", false);But there you can see it again; as far as we came until now, there seems to be no way to have a functionality without particularly coding all eventualities that might occur during runtime. "typeof(System.Windows.Forms.Button)" can't be represented by a string variable (as well as the following type casting). And that seems to be the point to me, but maybe I am missing it too. :) But maybe davearia could light the darkness, if he tells us what he exactly wants to do in his program. :D Quote
davearia Posted May 22, 2005 Author Posted May 22, 2005 Apololgies if I wasn't clear in the first case. I have a call to a database something like this: SELECT ctlName FROM ctlTable_T WHERE ctlID = @usersChoice There could be hundreds of user control's names stored in this table (which is why I am avoiding a "case statement fudge" like the plague), all of these user controls are in my solution. At runtime the results of this query are stored in a dataset ds. So we could have ds.Tables("ctlControls"). In the dataset we only one result, a VarChar which could be say ctlMyControl, there is a user control with this name which exists in the solution. We could say for example assign this result from the dataset to a string: Dim str As String = ds.Tables("ctlControls").Rows(0).Item(0).ToString How do I at runtime use the results in the dataset assigned to str to dynamically create the instance of this control. I hope I have been clearer this time, thanks again for your help. Thanks, Dave. :D :D :D Quote
*Experts* mutant Posted May 22, 2005 *Experts* Posted May 22, 2005 As I see it this will work excatly the way you want, as suggested previously by marble_eater (assuming your controls are in the same assembly as your program): //Replace the hardcoded string with your string you get from db. string ctrlname = "WindowsApplication2.MyControl"; Assembly asmb = Assembly.GetExecutingAssembly(); MyControl myctrl = (MyControl)asmb.CreateInstance(ctrlname, false); Quote
APaule Posted May 22, 2005 Posted May 22, 2005 MyControl myctrl = (MyControl)asmb.CreateInstance(ctrlname' date=' false);[/code']This assumes that davearia only has one type of controls in his assembly. But if he has more than one, it seems to be impossible to avoid "case statement fudging". Quote
*Experts* mutant Posted May 22, 2005 *Experts* Posted May 22, 2005 MyControl can simply be a base type for all other usercontrols he creates (or even cast it to a UserControl, it doesn't matter). Either way it works for what he seems to be requiring. Can't forget some level of abstraction :). Quote
APaule Posted May 22, 2005 Posted May 22, 2005 Can't forget some level of abstraction :). :eek: :o :D Quote
*Experts* mutant Posted May 22, 2005 *Experts* Posted May 22, 2005 :eek: :o :D Is that a sign of approval, or disagreement? :) ;) Quote
APaule Posted May 22, 2005 Posted May 22, 2005 Is that a sign of approval, or disagreement? :) ;)Approval of course! :) Quote
Himo Posted May 22, 2005 Posted May 22, 2005 But problem no. 1 here: From my point of view davearia uses VB .net, that doesn't allow typecasting. Away solution... Quote For questions about VS .net extensibility, please fire at me! :) For readability, please use the [ CS][/CS ] tags
Leaders Iceplug Posted May 22, 2005 Leaders Posted May 22, 2005 Sure you can do typecasting in VB by way of DirectCast. Why would you think that VB can't do this? myctrl = DirectCast(asmb.CreateInstance(ctrlname, false), myControl) :) Quote Iceplug, USN One of my coworkers thinks that I believe that drawing bullets is the most efficient way of drawing bullets. Whatever!!! :-(
Himo Posted May 22, 2005 Posted May 22, 2005 :o Because my VB proficiency is way lower than my C# proficiency Quote For questions about VS .net extensibility, please fire at me! :) For readability, please use the [ CS][/CS ] tags
davearia Posted May 22, 2005 Author Posted May 22, 2005 IcePlug can you please elaborate just a bit more with your code. I have a resulting String str which holds the name of the control we are going to create. How exactly am I going to use this to create an instance of this control. Many thanks in anticipation. :D Quote
APaule Posted May 22, 2005 Posted May 22, 2005 But problem no. 1 here: From my point of view davearia uses VB .net, that doesn't allow typecasting. Away solution...Oh you disbelievers..... are there still people out there who don't believe that VB has grown up long time ago!? :p There is even a second way of type casting. It's the method CType. :cool: Quote
Leaders Iceplug Posted May 23, 2005 Leaders Posted May 23, 2005 IcePlug can you please elaborate just a bit more with your code. I have a resulting String str which holds the name of the control we are going to create. How exactly am I going to use this to create an instance of this control. Many thanks in anticipation. :D I merely converted mutant's C# code to VB.NET. From the looks of it, it creates something from within the assembly that you have to convert to a control, but I won't profess to knowing exactly what it is. :) Quote Iceplug, USN One of my coworkers thinks that I believe that drawing bullets is the most efficient way of drawing bullets. Whatever!!! :-(
*Experts* mutant Posted May 23, 2005 *Experts* Posted May 23, 2005 Here is an equivalent for you: The DirectCast call will convert the created object into a control for you. Dim ctrlname As String = "WindowsApplication1.myctrl" Dim asmb As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly() Dim ctrl As UserControl = DirectCast(asmb.CreateInstance(ctrlname, False), UserControl) Quote
IngisKahn Posted May 23, 2005 Posted May 23, 2005 This is all a question of how to use basic reflection, which .NET supports wonderfully. Just a meander thru the System.Reflection namespace should yield answers. The many Assembly.Load* functions should give you an idea of how to access system assemblies. Quote "Who is John Galt?"
davearia Posted May 23, 2005 Author Posted May 23, 2005 Many thanks for your help. Here is what I used: Dim ctrlname As String = "ctlMyControl" Dim asmb As System.Reflection.Assembly = System.Reflection.Assembly.LoadFrom("C:\MyDLL.dll") Dim ctrl As UserControl = DirectCast(asmb.CreateInstance(ctrlname, False), UserControl) Me.pnl.Controls.Add(ctrl) The only thing I needed to change from the code provided was the assembly reference as the reference is a dll outside the current assembly. Thanks to everyone again you are brilliant. Thanks, Dave. :D :D :D Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.