Click to See Complete Forum and Search --> : Handling events of constituent controls loaded at runtime.
yosef
Dec 17th, 2000, 04:19 AM
Hi. If anyone could help me with that I'd be very happy.
I have a user-control that loads controls at runtime according to data from XML.
The problem: when I do this:
Controls.Add("vb.textbox", "washington_irving", frameMain)
(the parameters are examples. the type and the name could be anything)
Well, when I do this I can't handle events on the controls I load. How do I handle events (and don't tell me to use WithEvents because I don't know how many controls are loaded)?
I don't mind if your solution includes classes, other user-controls or anything. Just give me something that works....
Thanks!!
Iain17
Dec 20th, 2000, 11:55 AM
When will you people give up the idea of handling controls loaded at runtime. If i've said this once, i've said it a thousand times.
You say ah, but if i load it at runtime it isnt using up valuable memory. I say, you have to have the control declared already, so eth control is using up memory. So advantage number 1 just flew out the window.
And what other advantages do you think there are? You have to have the code written for them anyway, other wise, as you have found, nothing sodding well happens. And yes you do have to dim it with events.
Why not just hide the control, and show it if it is needed, much simpler, and more sensible.
yosef
Dec 21st, 2000, 01:36 AM
Because I don't know how many (and which) controls I'm going to use. The data is stored in an XML.
Besides - you can use a collection to store the controls and not declare them in advance. My only problem is handling their events.
agent
Jan 1st, 2001, 04:30 PM
i use a similar method for handling plugins in my programs. When a plugin needs to send info back to the app, there's no way to do it, because you CAN'T use events with controls loaded at runtime. I thought, maybe the host app could have a class in it that is refenced by the plugin. Unfortunatly, you can't have a pulic-creatable class in a standard exe (in vb5 anyway)
Next best thing, when you load the control, pass it an instance of the class. The class has a method in it that is called by the control (with parameters to match the index of the control that called the method). This only works if you wrote the conrols you're adding at runtime.
A better way to explain this:
1. Program starts
2. It reads the XML and determins the controls needed to load.
3. Program loads each control, assigning an index to each.
4. Each control is passed an instance of clsEvent which has a "Public Sub CTRLEvent(ControlIndex as Integer, EventIndex as Integer)" method
5. Each control is also passed it's own index number.
6. When the event is fired, the control calls "clsEvent.CTRLEvent iMyIndex, x" (x being a number that specifies the event being fired)
7. Using a Select Case in the clsEvent.CTRLEvent determines what action to be taken based on the ControlIndex and Event Index.
Note, you could also have one method for each event.
Sorry if you can't understand some of this, I just got up from bed when I wrote this.
yosef
Jan 2nd, 2001, 12:57 AM
hey, agent, I'm sorry but I didn't understand how you handle events like Click and DblClick etc. Just to be certain I was understood correctly - I load not only the UserControls at runtime. I actually load a number of Instances of ctlAnything - which In turn finds his matching XML (say - ctlAddress.xml) and XSL, and load constituet controls based on it.
Now the sollution (It's not going to be complete since it's confidential Information of Amdocs (Israel) Ltd.):
Ok, you make a UserControl to run with my program, right? So you build an XSL to describe his components, and an XML to describe which component is used (you could use other structure, that's what I did).
Now, the XSL of a control contains templates such as this:
</template match="txtName">
<CONTROL>
<NAME>txtName</NAME>
<TYPE>vb.TextBox</TYPE>
.
.
.
<ADDINFO> (that's where I put control information that is not bound to a property
</ADDINFO>
</template>
Now, suppose we want to handle the Click event on the 'txtName' textbox? we need the main program to declare a variable WithEvents, but we can only declare a limited number in des-time, and we want infinite at run-time. What do we do?
There is a way. I will continue on my next post, and meanwhile try to find the solution. You can ask me questions about this.
Happy new year, you Cristians out there!
agent
Jan 2nd, 2001, 03:20 PM
this will only work if you wrote all the controls that are expected to be described in the xml. this would not work for you, since vb.textbox is a vb constituant control, and you can't modify it to call a method in a class instead of firing an event.
Good luck on finding an answer.
BTW, you can also use a hidden control whose index is = 0 (instead of null). Each time a new control is needed, just use Load ctrlMyControl(ubound(ctrlMyControl)), and set the position, size, caption, etc...
The event if fired as usual, but and index number is passed to the event, so you know which control firedt the event.
tumblingdown
Jan 2nd, 2001, 04:11 PM
Why do you guys not use dynamic control arrays? They give you all your events handling.
td.
tumblingdown
Jan 2nd, 2001, 04:14 PM
Sorry agent, didn't read the end of your last post.
td.
yosef
Jan 3rd, 2001, 12:51 AM
Hey, I'm describing something that W O R K S. Be patient. The TextBox is not supposed to call anything or change anything.
The controls anyone writes of course must have a convention for creating them - what fields are in the XML, operation instructions etc. Since I work for a big company such as Amdocs this is no problem.
Now, for convenience: UC = UserControl, CC = Constituent Control
My next Post continuing the explanation will come this week, I hope. I think I need to explain the way I read the XML. Feel free to direct me. meanwhile - here's another clue: We need to attach every little CC with his own event-handling object. Think about it.
Agent: I still don't understand how can anyone write, say, a new Click method for a textbox he wants to add just after I die or something.
tumblingdown
Jan 3rd, 2001, 01:43 AM
Originally posted by yosef
Agent: I still don't understand how can anyone write, say, a new Click method for a textbox he wants to add just after I die or something.
What agent is talking about is when you place a control (textbox) on a form, and give it an index of 0, you have created a control array. If you have a look at the procedure definition for the Click (etc) event, you will see it has been modified , and now has passed into it the parameter of the Index of the control the was clicked, e.g.
Private TextBox1_Click(byref Index As Integer)
End Sub
Then at run time, do not use Controls.Add, simply use Load and increment the Index of the control, i.e.
'/ to load the second textbox
Load TextBox1(1)
'/ to load the third textbox
Load TextBox1(2)
If the user clicks the TextBox with Index = 0, zero will be passes to the Click handler, if the user clicks the TextBox with Index = 1, then 1 will be passed to the handler.
Does this help at all?
td.
yosef
Jan 3rd, 2001, 01:47 AM
Ok, I know this is what happens, but my goal is to allow people to program functionality to their CC's without touching the program I wrote (another clue...) so it doesn't help me to use control arrays. Hard Coded = Trouble, get what i mean?
That's why the solution is still not acceptable. But thanks for the help, anyway, I appreciate it.
tumblingdown
Jan 3rd, 2001, 02:05 AM
Which bit is Hard-Coded?
td.
yosef
Jan 14th, 2001, 01:31 AM
OK. There it is.
My Controls are described in an XML of two levels. The first level describes the User Controls (UC's if you dont mind), and the second describes the Constituent Controls (CCs) of each UC.
excerpt from the first level XSL file used to form the data(the XML file specifies which controls of those listed in the XSL will be created):
<xsl:template match="ctlCustTypeNB">
<CONTROL>
<xsl:attribute name="parent">
<xsl:value-of select="@parent" />
</xsl:attribute>
<CONTROLNAME><xsl:value-of /></CONTROLNAME>
<CONTROLTOP>20</CONTROLTOP>
<CONTROLLEFT>20</CONTROLLEFT>
<CONTROLBACKCOLOR>H8000000F</CONTROLBACKCOLOR>
<CONTROLTABINDEX>0</CONTROLTABINDEX>
<POSITION>1</POSITION>
<CONTROLTYPE>ctlCustType</CONTROLTYPE>
</CONTROL>
</xsl:template>
<xsl:template match="ctlNameGroupBusiNB">
<CONTROL>
<xsl:attribute name="parent">
<xsl:value-of select="@parent" />
</xsl:attribute>
<CONTROLNAME><xsl:value-of /></CONTROLNAME>
<CONTROLTOP>1000</CONTROLTOP>
<CONTROLLEFT>20</CONTROLLEFT>
<CONTROLBACKCOLOR>H8000000F</CONTROLBACKCOLOR>
<CONTROLTABINDEX>0</CONTROLTABINDEX>
<POSITION>1</POSITION>
<CONTROLTYPE>ctlNameGroupBusi</CONTROLTYPE>
</CONTROL>
</xsl:template>
the attribute 'parent' is used to distinguish between forms. It's a different story. For information about XML and XSL transformations, see Web Workshop under MSDN.
Notice the XML Tag <CONTROLTYPE>. My program lookas for a second level XML-XSL pair by the name under this tag.
Excerpt from ctlCustType.xsl:
<xsl:template match="cmbCustType">
<CONTROL>
<CONTROLNAME>cmb<xsl:value-of /></CONTROLNAME>
<CONTROLTOP>200</CONTROLTOP>
<CONTROLLEFT>1800</CONTROLLEFT>
<CONTROLHEIGHT>315</CONTROLHEIGHT>
<CONTROLWIDTH>3075</CONTROLWIDTH>
<CONTROLBACKCOLOR>H80000005</CONTROLBACKCOLOR>
<CONTROLTABINDEX>0</CONTROLTABINDEX>
<POSITION>1</POSITION>
<CONTROLTYPE>VB.ComboBox</CONTROLTYPE>
<CONTROLTEXT />
<ADDINFO>
<DLL>amdocsGeneral</DLL>
<OBJ>CustTypeEvents</OBJ>
</ADDINFO>
</CONTROL>
<CONTROL>
<CONTROLNAME>lbl<xsl:value-of /></CONTROLNAME>
<CONTROLTOP>200</CONTROLTOP>
<CONTROLLEFT>40</CONTROLLEFT>
<CONTROLHEIGHT>315</CONTROLHEIGHT>
<CONTROLWIDTH>3075</CONTROLWIDTH>
<CONTROLBACKCOLOR>H8000000F</CONTROLBACKCOLOR>
<CONTROLTABINDEX>0</CONTROLTABINDEX>
<POSITION>1</POSITION>
<CONTROLTYPE>VB.Label</CONTROLTYPE>
<CONTROLTEXT>Customer Type: </CONTROLTEXT>
</CONTROL>
</xsl:template>
notice ADDINFO on the combobox.
How does my program load this controls?
I have one UC object, called ctlAnything. the program reads the first-level XML, and instantiates a new ctlAnything for each UC lited in the main XML.
ctlAnything, in turn, reads the second-level XML and instantiates its own CCs accordingly.
Now, crasy things happen when ctlAnything encounters <ADDINFO>.
I promise a second part later. Right now duty calls. Send your answer her or to yossefm@amdocs.com
Bye.
Part two.
---------
now, when ctlAnything encounters the ADDINFO tag it searches for two tags: the DLL tag and the OBJ tag.
So, you can see that the event-handling functions are external to the program, you distribute a separate .dll with each
control or group of controls you release, just like you make a separate XML and XSL.
The DLL contains objects that look something like that:
Dim WithEvents myCombo As VB.ComboBox
Private Sub myCombo_Click()
msgbox myCombo.Text 'Or any functionality you want for a CC
End Sub
Public Sub listenTo(ctl As Object)
Set myCombobox = ctl
End Sub
This is an object for a comboBox CC that prints out the text selected when clicked.
Back to ctlAnything - If it finds the DLL and OBJ tags, it uses that data to create an object of that type, add it to a collection and
make it listen to the events of a certain control:
Handlers(i).listenTo(Controls(i)) for example.
I think this is pretty much it. If it isn't, please respond. I'm sorry it's not very specific, I'm terribly busy right now.
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.