Get value of user control in business layer code

N

NeilR

We have a business layer which is compiled as a dll and used across
several linked websites. Some of the website pages have search panels
with a number of controls for the user to enter search criteria. When
he clicks a search button, the panel is submitted to the business
layer, which goes through the controls, extrascts selected values and
sends them as parameters via the appropriate SQL stored procedures to
get lists of data.
This all works fine, but we are now trying to add some user controls
to give even more flexible searches. These contain several controls
feeding into a combo - eg start & end dates and project types to
filter the list of projects in the combo. The user controls have
public properties to get the selected value in these combos - eg:
intProjectID = ucProjectSelector.intIDvalue
This all works fine from the parent page - we can get the value from
the final combo in each ascx via its public property. However, when we
submit the panel to the business layer library file, it cannot access
these public properties - eg:
ElseIf TypeOf MyControl Is UserControl Then
MyUserCntrl = MyControl
'MyUserCntrl is dimmed as UserControl
intParameterValue = MyUserCntrl.intIDvalue
- - - gives the error: "intIDvalue is not a member of 'Control' "

Can anyone help us resolve this? Are we going to have no choice but to
go down the (lengthy) route of creating complied custom or composite
controls and registering a dll for these separately, or is there a
simpler way to get values from the public properties of our user
controls outside the scope of the current page? We could, of course,
add code to the pages to get the values from the user controls, and
store these in hidden controls in the panel before submitting the
panel to the library code, but this would rather negate the value of
using our business layer to extract all the values. Any brilliant
minds out there who can think of a better method?
Hopefully, Neil
 
P

Patrice

The UserControl class is just the base class. You have to use the actual
type for your user control to be able to access all its features :

If TypeOf c Is DateRangeControl Then
drc=CType(c,DataRangeControl)
Debug.WriteLine(drc.DataStart & "/" & drc.DateEnd)
End If

Also it seems that the bl gets its data directly from the ui which is not
the usual archictecture. You could have method that extracts criterias from
your user control that pass this list to the BL (allowing the BL to be used
not only in web apps but also in windows apps for example).
 
N

NeilR

The UserControl class is just the base class. You have to use the actual
type for yourusercontrolto be able to access all its features :

If TypeOf c Is DateRangeControl Then
    drc=CType(c,DataRangeControl)
    Debug.WriteLine(drc.DataStart & "/" & drc.DateEnd)
End If

Also it seems that the bl gets its data directly from the ui which is not
the usual archictecture. You could have method that extracts criterias from
yourusercontrolthat pass this list to the BL (allowing the BL to be used
not only in web apps but also in windows apps for example).

--
Patrice

"NeilR" <[email protected]> a écrit dans le message de




- Show quoted text -

Thank you for responding but can I ask for a little clarification? Our
user controls contain a mixture of web controls (eg datepickers, text
boxes, etc); they end up with a combo - which is the one we want to
extract the value from - but these might yield text or integer values.
How would we classify the user control as a more specific type? Does
this imply turning them into custome controls with more specific
types? If so, we have never attempted this and would not be sure how
to do it. Can you please provide a little more guidance?
Best regards, Neil
 
P

Patrice

How would we classify the user control as a more specific type?Does
this imply turning them into custome controls with more specific
types? If so, we have never attempted this and would not be sure how
to do it. Can you please provide a little more guidance?

This is already done. A user control is nothing else than a class (named
webusercontrol_ascx for example). Use the object browser for example or just
move the mouse over the member that represents this control. You should see
its actual type.

Or if you dump UserControlVariable.GetType.ToString in the layer you talked
about, you'll be able to see the actual type of the user control.

Now you could use typeof to test the actual type and depending on the type
you'll be able to access all the capabilites that could be exposed in your
code behing for this particular control.

There is more behind this (for example using interfaces rather than testing
the type of each and every control could be better) but unless you have a
bunch of controls it should be sufficient at first...
 
N

NeilR

This is already done. A user control is nothing else than a class (named
webusercontrol_ascx for example). Use the object browser for example or just
move the mouse over the member that represents this control. You should see
its actual type.

Or if you dump UserControlVariable.GetType.ToString in the layer you talked
about, you'll be able to see the actual type of the user control.

Now you could use typeof to test the actual type and depending on the type
you'll be able to access all the capabilites that could be exposed in your
code behing for this particular control.

There is more behind this (for example using interfaces rather than testing
the type of each and every control could be better) but unless you have a
bunch of controls it should be sufficient at first...

Sorry - I still don't follow. Your suggestion above was to CType the
ascx as a specific type of control (eg DateRangeControl) but we have
controls of various types in the ascx. The value we are trying to get
is from a combo box but if we CType the whole ascx as a combo I don't
see how we would get the selected value of the combo inside it. In the
original code I posted you can see we are testing for the control type
and this bit of code is only running if the type is UserControl. If I
interupt the code at that point, and point the mouse at "MyUserCntrl "
to get all its properties, I can see intIDvalue in there with the
correct value. However, if I use the next line shown above
( intParameterValue = MyUserCntrl.intIDvalue) I get the error:
""intIDvalue is not a member of 'Control' " - - so how do I get this
value from the control? Also, we have added a public property in the
user control called IDvalue (which gets the value from one of the
controls in the ascx) but this is not showing up at all when I halt
the code at this same point. Can you give me any further guidance?
Many thanks, Neil
 
P

Patrice

So, let's try to go back to your code...

ElseIf TypeOf MyControl Is UserControl Then
MyUserCntrl = MyControl
'MyUserCntrl is dimmed as UserControl
intParameterValue = MyUserCntrl.intIDvalue
- - - gives the error: "intIDvalue is not a member of 'Control' "

Waht is the type of the MyControl variable ? If UserControl what is the
purpose of doing a MyUserCntrl = MyControl as MyUserCntrl is also of the
UserControl type ?

If seems to me you are trying to assign MyControl (which is of type
UserControl) to MyUserCntrl (which should be declared using the actual type
of the user control) so that you can then access to the specific
capabilities of this class (such as the intlDvalue member that gives perhaps
access to the value selected inside a dropdown ?)

Also don't confuse the control and its content. I don't suggest to cast a
usercontrol to a combo but to the type of the user control itself... A user
control is not of the type of the control that is included in it (it could
anyway have multiple controls).

For example the type of myusercontrol.ascx should be myusercontrol_ascx (use
the boject browser to see this type).

If it still doesn't work the last resort could be to create a simplistic
project from scratch to play with this... Do you use a web application or a
web site project ?
 
N

NeilR

So, let's try to go back to your code...

 ElseIf TypeOf MyControl Is UserControl Then
        MyUserCntrl = MyControl
'MyUserCntrl is dimmed as UserControl
        intParameterValue = MyUserCntrl.intIDvalue
- - - gives the error: "intIDvalue is not a member of 'Control' "

Waht is the type of the MyControl variable ? If UserControl what is the
purpose of doing a MyUserCntrl = MyControl as MyUserCntrl is also of the
UserControl type ?

If seems to me you are trying to assign MyControl (which is of type
UserControl) to MyUserCntrl (which should be declared using the actual type
of the user control) so that you can then access to the specific
capabilities of this class (such as the intlDvalue member that gives perhaps
access to the value selected inside a dropdown ?)

Also don't confuse the control and its content. I don't suggest to cast a
usercontrol to a combo but to the type of the user control itself... A user
control is not of the type of the control that is included in it (it could
anyway have multiple controls).

For example the type of myusercontrol.ascx should be myusercontrol_ascx (use
the boject browser to see this type).

If it still doesn't work the last resort could be to create a simplistic
project from scratch to play with this... Do you use a web application ora
web site project ?

Dear Patrice
This snippet is from a vb function into which we feed a control
collection (from a search criteria panel). It start with
For Each MyControl In collControls
If Not MyControl.ID Is Nothing Then
- - then it tests for the type of control. We have dimmed each type at
the top so we then assign a variable dimmed as that type - eg for a
text box:
If TypeOf MyControl Is WebControls.TextBox Then
MyTextBox = MyControl
Now, for each type we can look for the appropriate property:
strParameterValue = MyTextBox.Text

So, if it finds a user control in the collection, we assign it to the
variable we have dimmed as a usercontrol, as I showed originally:
MyUserCntrl = MyControl

Now we want to get its IDvalue property (which is the selected item in
the combo within it) - - as I said earlier, if I put a brealpoint just
below this and point at MyUserCntrl in visual studio, it shows
{ASP.accesscontrolled_commonfiles_usercontrols_companyselector_ascx}
with all its members (from application to visible). If I click on the
+ beside this name in the top line, it shows a list of controls and
properties - - in there, I can see the IDvalue property AND its value:
IDValue = "100011718"
However, if I try to get it in the command window by typing
MyUserCntrl.IDvalue I get the error: "intIDvalue is not a member of
'Control' "

So our code is fine up to this point - it gets the values of all the
other criteria from the other controls, but I simply cannot work out
how to retrieve this property, even though I can see that it is in
there! Can you help?

Neil
 
P

Patrice

Ok, so the core problem is that you are using the UserControl type. As
MyUserCntrl is typed as UserControl it doesn't know anything about the user
control you created that *inherits* from UserControl but adds *new*
features. So you won't never be able to access to those additional features.
You would have to cast to the actual type of the user control to get access
to those additional features...

The problem is that you'll have perhaps to test for numerous user controls.
Here is a quick summary of a basic architecture that could perhaps help :
- create a website
- add a file (will go in App_Code) that contains this code :
Public Interface IFilters
Function GetFilters() As Generic.Dictionary(Of String, Object)
End Interface
- add a new webusercontrol containing the following code markup :
<asp:TextBox runat="server" ID="Like" Text="Some text"/>
<asp:CheckBox runat="server" ID="chkFinished" />
and the following code behind :
Partial Class WebUserControl
Inherits System.Web.UI.UserControl
Implements IFilters

Public Function GetFilters() As Generic.Dictionary(Of String, Object)
Implements IFilters.GetFilters
Dim dic As New Generic.Dictionary(Of String, Object)
dic.Add("Like", [Like].Text)
dic.Add("Finished", chkFinished.Checked)
Return dic
End Function
End Class

Now add this control to your default page. In the page code behind the
following code :

Sub ProcessControl(ByVal c As Control)
If TypeOf c Is IFilters Then
For Each v In CType(c, IFilters).GetFilters
Dim str As String = v.Key
Dim value As Object = v.Value
Stop
Next
End If
If c.HasControls Then
For Each subControl As Control In c.Controls
ProcessControl(subControl)
Next
End If
End Sub

Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
ProcessControl(Me)
End Sub

Now when you run this code, it stops at the Stop statement. If you place the
mouse over the str/value variable you'll see the values for the filtering
controls.

What we have done is :
- we created an interface (a kind of "contract") telling that IFilters is
able to provide a name/value list of criteria
- the usercontrol we created fullfills this contract by providing this list
for the appropriate controls it contains (possibly not all)

Then we just test for this "contract" and if this contract is fullfilled
then we can get those values.

If you want to create other filtering controls, if you used the same pattern
you'll be able to get their own list with the same code. You could even
extract all those values in a single dictionary and pass this to another
layer.
 
N

NeilR

Ok, so the core problem is that you are using the UserControl type. As
MyUserCntrl  is typed as UserControl it doesn't know anything about theuser
control you created that *inherits* from UserControl but adds *new*
features. So you won't never be able to access to those additional features.
You would have to cast to the actual type of the user control to get access
to those additional features...

The problem is that you'll have perhaps to test for numerous user controls.
Here is a quick summary of a basic architecture that could perhaps help :
- create a website
- add a file (will go in App_Code) that contains this code :
Public Interface IFilters
    Function GetFilters() As Generic.Dictionary(Of String, Object)
End Interface
- add a new webusercontrol containing the following code markup :
<asp:TextBox runat="server" ID="Like" Text="Some text"/>
<asp:CheckBox runat="server" ID="chkFinished" />
and the following code behind :
Partial Class WebUserControl
    Inherits System.Web.UI.UserControl
    Implements IFilters

    Public Function GetFilters() As Generic.Dictionary(Of String, Object)
Implements IFilters.GetFilters
        Dim dic As New Generic.Dictionary(Of String, Object)
        dic.Add("Like", [Like].Text)
        dic.Add("Finished", chkFinished.Checked)
        Return dic
    End Function
End Class

Now add this control to your default page. In the page code behind the
following code :

    Sub ProcessControl(ByVal c As Control)
        If TypeOf c Is IFilters Then
            For Each v In CType(c, IFilters).GetFilters
                Dim str As String = v.Key
                Dim value As Object = v.Value
                Stop
            Next
        End If
        If c.HasControls Then
            For Each subControl As Control In c.Controls
                ProcessControl(subControl)
            Next
        End If
    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
        ProcessControl(Me)
    End Sub

Now when you run this code, it stops at the Stop statement. If you place the
mouse over the str/value variable you'll see the values for the filtering
controls.

What we have done is :
- we created an interface (a kind of "contract") telling that IFilters is
able to provide a name/value list of criteria
- the usercontrol we created fullfills this contract by providing this list
for the appropriate controls it contains (possibly not all)

Then we just test for this "contract" and if this contract is fullfilled
then we can get those values.

If you want to create other filtering controls, if you used the same pattern
you'll be able to get their own list with the same code. You could even
extract all those values in a single dictionary and pass this to another
layer.

Dear Patrice
Many thanks for your effort. This will take a bit of digesting but I
will give it a try and see if it also works in our library code (I
notice your is tested on a page within the current project so not sure
if it will work equally well from our library code)
Best regards, Neil
 

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