Connecting webcontrols and components

C

cpnet

I have been struggling with this for a long time now, and am beginning to
think that what I'm attempting isn't the correct approach. The short
version is that I want to be able to add a webcontrol to a page, and have
that webcontrol have properties that reference other webcontrols and/or
components. These properties that reference other webcontrols or components
should be of the type of the other webcontrols or components, and their
values should be persisted. These properties should be available at design
time and run time.

The longer story is that I'm trying to develop some webcontrols/components
to implement some questionnaires. There are a few different questionnaires
(each with different questions) and they have many questions. The questions
are organized heirarchically, and the user should only be presented with a
subset of the questions from a questionnaire at any given time. My current
design has a WebControl that will be based on a TreeView
(MyNavigatorWebControl). This will act as a navigator to allow the user to
quickly jump to a particular part of the questionnaire. I'll have a
second control (MyQuestionsWebControl). This second control will display a
subset of questions with corresponding DropDownLists and validators for a
particular subset of questions from a questionnaire. Finally, I'll have a
component (MyManagerComponent). This component will be the brains behind
everything. Typically a user will place an instance each of
MyNavigatorWebControl, MyQuestionsWebControl, and MyManagerComponent on a
WebForm. The instances of MyNavigatorWebControl and, MyQuestionsWebControl
will each reference the same MyManagerComponent. MyManagerComponent will be
aware of the currently 'active' part of the questionnaire.
MyNavigatorWebControl and, MyQuestionsWebControl will use this info to know
what to display in the navigation tree, and what subset of questions to
display to the user respectively at any given time. On post backs,
MyNavigatorWebControl will inform MyManagerComponent if the user has decided
they want to view a different section of the questionnaire.
MyQuestionsWebControl will notify MyManagerComponent about answers the user
has given for the questions it was displaying. MyManagerComponent will use
the Session cache and a number of other classes to keep the whole
questionnaire's answers, associated calculations, and methods to help a
developer load and save the answers to a complete questionnaire. Basically,
MyManagerComponent holds the whole questionnaire, while my WebControls work
with MyManagerComponent to only display a small portion of the questionnaire
with each page request to keep traffic minimal.

The only way I can (sort of) getting this working is if I use DataBinding to
bind MyManagerComponent to MyNavigatorWebControl, and MyQuestionsWebControl.
However, I don't think this is really that appropriate. MyManagerComponent
is not a typical datasource that implements IEnumerable. It has a number of
complex methods that MyNavigatorWebControl, and MyQuestionsWebControl will
need to call in order to function properly. It doesn't provide a basic list
of things to display. Databinding seems to require that at design time I
deal with strings rather than actual property types when assigning my
properties. Also, if I change the MyNavigatorWebControl1.MyManagerComponent
property value at runtime, I want this change to take effect immediately,
not wait until I call DataBind.

I think part of my problem is property persistence info for WebControls is
serialized to the HTML tags in the WebForm HTML page. Component property
persistence is handled in the codebehind file for the WebForm. I need a
safe way for a WebControl property to reference an instance of a component -
at design and runtime. I suppose this may get tricky since I'm not sure
when WebControls are created in relation to components (design or run time).

The only example I've seen in MS WebControls of relating a WebControl to a
Component, is attaching a DataSource to a DataBound Control of somesort
(i.e. assigning a DataSet to a DataGrid). But again, I don't think this is
really what I need. I just want my WebControls to reference (but not 'own')
Components, so that a given Component can be shared by several WebControls,
and so that the WebControls can take advantage of not only the data, but the
functionality of the Component. Is DataBinding my only option? Is my
design flawed?

Thanks,
cpnet
 
C

cpnet

I found this page http://www.dotnet247.com/247reference/msgs/16/80518.aspx
that says DataBinding is my only solution. (Apparently this post was from
this newsgroup, but I can't find it archived on google). Of course I found
this right after my rather long post here. ;) I guess I need to read a bit
further into Databinding. Will this stuff be improved in ASP.NET 2? Using
Databinding for WebControls that need to reference Components seems to be a
bit of a kludge to me... it works, but it Databinding really seems to be
aimed at attaching enumerations of some sort with a property. I would have
expected a more straightforward way to allow you to assign (and persist the
assignment of) components to webcontrols at runtime and designtime.
 
J

Jeffrey Tan[MSFT]

Hi cpnet,

Based on my understanding, you made a custom web control, you want your
control has a property to refer certain component.

I think we have worked with issue before. The solution I provided you for
this issue is shadow the property at design, and use HtmlControlDesigner's
DataBindingCollection to store the binding expression.

Does this solution work for you? Actually, this is the standard implement
for this issue.

As you stated "MyManagerComponent is not a typical datasource that
implements IEnumerable", we need not the component to implment IEnumerable
interface. Because this interface is only needed for DataSourceConverter.
We should implement a new TypeConverter, which will loop all the
components(implement IComponent interface) on the designer, then display
them in the propertygrid at design-time.

For your another conern: "Also, if I change the
MyNavigatorWebControl1.MyManagerComponent property value at runtime, I want
this change to take effect immediately, not wait until I call DataBind.".
Actually, our solution persists the binding expression at the html view
file, not the code behind, Page.DataBind method will force asp.net to
resolve all data-binding expressions in the server control and in any of
its child controls. Once DataBind method is called, the property is
correctly referred to the component. Then, every change to the component
will immediately reflect on this property, we need NOT call DataBind method
again.

This proves my statement:
private void Page_Load(object sender, System.EventArgs e)
{
this.DataBind();
this.Response.Write(this.SimpleControl1.testComponent.ToString()+"<br>");

TestProject.MyComponent obj=this.SimpleControl1.testComponent as
TestProject.MyComponent;

this.Response.Write(obj.testprop+"<br>");
myComponent1.testprop="set property";
this.Response.Write(obj.testprop+"<br>");
}

In the code, "SimpleControl1" is the solution webcontrol I provided you in
original issue. I created a new MyComponent class like this:

public class MyComponent: Component
{
private string m_testprop=String.Empty;
public string testprop
{
get
{
return m_testprop;
}
set
{
m_testprop=value;
}
}
}

The output is:
TestProject.MyComponent
abc //I set testprop value to "abc" in the designer
set property

So as you can see, it also works well at runtime.

Actually, Component is also an object, at run-time, once your property has
refered a component, it just behaves like refer other objects.

If you still have other concern about this solution, please feel free to
feedback.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
C

cpnet

Hi Jeffrey,

Your solution (that we discussed previously) does work. However, it just
seemed to me that using DataBinding was a less than ideal way to implement
properties of type 'Component' for a WebControl. I wanted to confirm that
in fact this is the only way to do this. And then when I found more
information that it was, I was wondering if this would be improved in
ASP.NET 2.0, or if there was something more generally wrong in my approach
that was forcing me to use this?

To me it seems more logical for there to be a single property of type
Component (i.e. no shawdowing with a string property at design time). In
the designer, you could implement a lookup who's display values were strings
(names of instances of Components), but who's key value was of type
component (the type of the property). In the HTML, you'd persist the
selected display value (i.e. the name of the selected component for the
property), and the framework would take care of resolving this name to the
appropriate component instance for the property. The framework would also
keep everything synchronized. This way if I changed MyComponent.Name, the
name persisted in the HTML would also automatically be updated.

At the very least, I wish Microsoft would have some examples/discussion of
this. Assigning Components to WebControls does seem to be something many
people would need to do, and I think there should be an article describing
it somewhere. Don't get me wrong - I appreciate your help very much, but
this seems like a topic that deserves 'official' MS coverage in it's
documentation. I bought, "ASP.NET Server Controls and Components"
(MSPress), and this stuff isn't discussed anywhere in that book that I can
find.

Thanks,
cpnet

PS: I overrode the "OnLoad" event of MyWebControl so that it calls
"DataBind()". I didn't initially call DataBind() anywhere when using the
control and couldn't figure out why MyControl.MyComponent == null at
runtime. By putting "DataBind()" in MyWebControl.OnLoad, users of my
component won't have to remember to do this. But, is this a safe thing to
do? (This is one reason why I don't like the Databinding solution - if I've
assigned a MyComponent to MyControl, then to my mind, MyComponent should be
automaticially, immediately, always available without calling other
methods). I know that for performance reasons, it should be up to the page
developer to call DataBind(), but I can see this causing frustration for
users of my controls. Since none of my controls are like standard
Datasources I doubt they'll expect to have to call DataBind().
 
J

Jeffrey Tan[MSFT]

Hi cpnet,

Thanks for your feedback.

Oh, I see your concern. Actually, in current version of Asp.net, this is
the only way of doing this.

I see it is strange for the page developer to call DataBind method to parse
the html persist statement. The solution for this is you as a control
developer to call DataBind method in OnInit or OnLoad method.

For Asp.net component design-time support, I will consult internally for
conformation, please wait for some time.

Thanks for your understanding.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi cpnet,

Sorry for letting you wait for so long time.

After internally consulting, I get some feedback from our product group for
Whidbey.

In Whidbey, the design surface for web forms does not support Components
located in the document since InitializeComponent is no longer used. We do
however have some alternatives. At design time we have a new host service
called ITypeDiscoveryService that allows your control's designer to
discover types available to the project - these can be located in the bin
and code directories, as well as in the GAC via the project references.

So I think ITypeDiscoveryService may meet the design-time need.

I hope this help you. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
C

cpnet

Ok thanks. Although, it does sound like if I want my code to easily migrate
to ASP.NET 2.0, I need to rethink my design a little. There's no much point
in building controls that can reference components on the design surface, if
components won't be allowed on the design suface in ASP.NET 2.0.

But then again... I was having the same issue with controls referencing
controls, as I was with controls referencing components. So, some of this
will still be applicable if I have Controls on the design surface that need
to reference each other.

Thanks,
cpnet
 
J

Jeffrey Tan[MSFT]

Hi cpnet,

Thanks for your feedback.

Yes, I see your concern, I will still spend some time communicating with
our product team for your concern.

Thanks for your understanding.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jørn Esbensen

Hi cpnet

I am trying to do the same thing as you, but I can't make it work.
Do you have any sample code you want to share?
As you mentioned there doesn't seem to be anyone else adressing this
problem.

Regards
Jørn.
 
C

cpnet

If you look at the thread, "Persisting control properties at design time" in
this group, started on Apr 19, 2004, there's a reply from Jeffrey Tan (Apr
29) with some code that worked for me. Try out the code he posted and it
should work for you.

The only addition I made to the code was to call the DataBind() method in
the OnLoad event of my control. This ensures that at runtime the component
name referenced in the HTML gets resolved to an actual component property in
my control.

cpnet
 
Y

Yan-Hong Huang[MSFT]

Hello Cpnet,

We have worked with product group on it for some time. In VS.NET 2003, I think you have known the correct way passed from
product group.

For VS Whidbey, we are testing it and working with product group now. It may need some more time. I will get back with more
information here as soon as possible.

I agree with you that there is no much material in this area yet. We also pass your feedback to our internal team and they took
it as a request in the future.

Thanks very much for your feedback and understanding.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Y

Yan-Hong Huang[MSFT]

Hello Cpnet,

We are still researching it and will be back here as soon as possible.

Thanks very much for your patience.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
C

cpnet

From the most recent issue of MSDN Magazine (June 2004),
http://msdn.microsoft.com/msdnmag/issues/04/06/ASPNET20Data/default.aspx, it
looks like there is a move to Controls only on forms for ASP.NET 2.0.
However, the article also mentions that ASP.NET 2.0 should be backwards
compatible with ASP.NET 1.1. code.

I can (without too much trouble) implement my components as controls that
produce no runtime HTML. But hopefully there will be a better way than
databinding for my HTML controls to reference on another. (The article I'm
mentioning focuses on DataSource controls so it only talks about Databinding
to associate controls).
 
Y

Yan-Hong Huang[MSFT]

Hello Cpnet,

We have worked with product group and support team for some time on it. It seems that the behavior in VS Whidbey is somewhat different
than what is in ASP.NET 1.1. We are still investigating it.

For VS.NET, I agree with you that there is no easy solution yet. For Whidbey, we may need to author the reference property just like the
DataSource property on our data-bound controls, i.e. with the right type converter, and designer functionality to persist it as a data-binding.

Thanks.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

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

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top