Connecting webcontrols and components

Discussion in 'ASP .Net Building Controls' started by cpnet, May 12, 2004.

  1. cpnet

    cpnet Guest

    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
     
    cpnet, May 12, 2004
    #1
    1. Advertisements

  2. cpnet

    cpnet Guest

    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.
     
    cpnet, May 13, 2004
    #2
    1. Advertisements

  3. 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.
     
    Jeffrey Tan[MSFT], May 13, 2004
    #3
  4. cpnet

    cpnet Guest

    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().
     
    cpnet, May 13, 2004
    #4
  5. 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.
     
    Jeffrey Tan[MSFT], May 14, 2004
    #5
  6. 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.
     
    Jeffrey Tan[MSFT], May 17, 2004
    #6
  7. cpnet

    cpnet Guest

    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
     
    cpnet, May 17, 2004
    #7
  8. 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.
     
    Jeffrey Tan[MSFT], May 18, 2004
    #8
  9. 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.
     
    Jørn Esbensen, May 18, 2004
    #9
  10. cpnet

    cpnet Guest

    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
     
    cpnet, May 18, 2004
    #10
  11. 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.
     
    Yan-Hong Huang[MSFT], May 20, 2004
    #11
  12. 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.
     
    Yan-Hong Huang[MSFT], May 26, 2004
    #12
  13. cpnet

    cpnet Guest

    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).
     
    cpnet, May 26, 2004
    #13
  14. 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.
     
    Yan-Hong Huang[MSFT], May 27, 2004
    #14
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.