views:

162

answers:

3

hi there!

currently i've built a collapseControl which behaves similar to a label (associatedControlID) to control the collapse-state of a control.

following control i'd like to build:

collapsableArea

i thought of something like:
put my already build collapsableControl and some other control (eg. panel) together to get a collapsableArea.

first try:
i tried to extend a panel and did the following:

this.Parent.Controls.Add(collapsableControl);

but this gave me: "not correct life cycle step", "can't modify", "nullReference", ... exceptions

so i gave it another try (which i believe the better choice, due to getting no tagKey):
i extended a placeholder and did the following:

this.Controls.Add(collapsableControl);
this.Controls.Add(collapsablePanel);

this caused other problems, like: i only want to set the text of the panel, the style of the panel, ...

wired!

do you have any solutions for this scenario?

edit:
i came up with another solution:
another solution

"CollapsableArea" is of type "Control", containing 2 extra private properties:

  1. "CollapsableControl"
  2. "Panel"

i thought it would be enough, to redirect the getter of the CollapsableArea.Controls to CollapsableArea.Panel.Controls. in CollapsableArea.CreateChildControls() i instanciate and add the CollapsableControl and Panel to base.Controls and in CollapsableArea.RenderChildren() render those 2

my problems now: the CollapsableControl will get a clientID (without setting an ID) - the panel won't render CollapsableControl will fail (or passed out), if panel contains <% %>-tags

any suggestions?

edit: i fixed the behaviour of the missing ID - just set CollapsableControl.AssociatedControlID to Panel.ClientID... but - when putting <% %> in the panel, it won't get rendered??!!

A: 

If you are after a simple panel, rather then re-inventing the wheel you could use the Collapsible Panel Control:

http://www.asp.net/AJAX/AjaxControlToolkit/Samples/CollapsiblePanel/CollapsiblePanel.aspx

Might be the easiest way to get the functionality you are after?

Chris
i know that there's this control, but: we don't want to use neither to atlas-framework nor its controls... sry! plus: we do not need such a all-singing-all-dancing control... we focus on the integration of jQuery!
Andreas Niedermair
you may see the question "what's your solution" in a more common way - i think teaming up 2 controls is a wide-used scenario! and since now i do not know the (best) solution for this scenario :)
Andreas Niedermair
A: 

Your control should get a Template control property to define collapsable content. And as you said a AssociatedControlID property which gets the Label control id.

public class CollapsableArea : WebControl, INamingContainer
{
    public string AssociatedControlID { get; set; }
    public ITemplate ContentTemplate { get; set; }
}

You have to register a jquery to the startup scripts of the page.

$("#The AssociatedControlID client control id").click(function(e) {
    $("#The CollapsableArea client control id").toggle();
}
Mehdi Golchin
nope... as i want a control which consists of 2 controls (collapsableControl, panel) i know @ CreateChildControls the id of the control for the associatedControlID of the collapsableControl. your solution is already captured by my implemented collapsableControl - but for shorting-reasons i want to create a collapsableArea...
Andreas Niedermair
What's your reason?
Mehdi Golchin
"shorting-reason": 80% usage of the collapsableControl would be in combination with a plain old panel. why should every programmer declare 2 controls, if there could only be one?
Andreas Niedermair
What I realized you have a CollapsableControl which expands and collapses an associated panel. What is the role of CollapsableArea here?
Mehdi Golchin
the "collapsableArea" is the wanted control, containing a collapsableControl (which is the header with the icon) and eg. a panel (for the content) - see edit for more info!
Andreas Niedermair
basically I disagree with your model. this control is much easier than you wrote.
Mehdi Golchin
your supposted "answer" is the basic implementation of the whole collapseControl. Basically it can collapse everything (from image, to table, to div, ... name it, it does it). Therefore it already does, what you wanted to achieve with your answer - just in a more comely way.but: 80% we use: collapsableControl with a panel - why not team 'em up in a control?! --> this is what i want to achieve!
Andreas Niedermair
I don't have any problem with using panel. it's not a bad idea. my problem is with your control design. you want to create 2 controls, a collapsableControl and a collapsableArea, here is the problem. you can create a simple control (not mine) which takes 2 panels' ids.one for header and another for content. and handles the first panel client click and turns second panel display to on and off.furthermore,using ITemplate for layout,header,content and even footer is very useful.cause you can create a skin file and assign it to all of collapsablecontrols.
Mehdi Golchin
i don't want enforce you to use Itemplate. this is my idea and that is your code. here we can talk about our idea without any challenge.
Mehdi Golchin
i do not want to create 2 controls. i've created 1 control (collapsableControl) and now i want to reuse this control in combination with a panel. this reusage will be called collapseArea.the problem is, why i left out ITemplate: i will not need the ability to skin, as i want to create a standard-control for our website. and there is no plan to distribute this to any other project! so ... sry!
Andreas Niedermair
A: 

oh, how comes - i've solved this problem:

public sealed class CollapsableArea : Control
{
    private const string ViewStateKeyCollapsableContentClientID = "collapsableContentClientID";

    private string CollapsableContentClientID
    {
     get
     {
      var obj = this.ViewState[ViewStateKeyCollapsableContentClientID];
      if (obj == null)
      {
       var collapsableContentClientID = Guid.NewGuid().ToString();
       this.ViewState[ViewStateKeyCollapsableContentClientID] = collapsableContentClientID;
       return collapsableContentClientID;
      }
      return (string)obj;
     }
    }

    /// <summary>
    /// Gets or sets the header text.
    /// </summary>
    /// <value>The header text.</value>
    public string HeaderText
    {
     get
     {
      this.EnsureChildControls();
      return this._collapseControl.Text;
     }
     set
     {
      this.EnsureChildControls();
      this._collapseControl.Text = value;
     }
    }

    public override ControlCollection Controls
    {
     get
     {
      // redirect controls
      return this._collapsableContent.Controls;
     }
    }

    #region child controls

    private readonly Panel _collapsableContent = new Panel();
    private readonly CollapsableControl _collapseControl = new CollapsableControl();

    #endregion

    public override Control FindControl(string id)
    {
     // need to redirect
     if (string.Equals(id, this._collapsableContent.ID))
     {
      return this._collapsableContent;
     }
     return this._collapsableContent.FindControl(id);
    }

    protected override void CreateChildControls()
    {
     base.Controls.Clear();

     var collapsableContentClientID = this.CollapsableContentClientID;
     this._collapsableContent.ID = collapsableContentClientID;
     this._collapseControl.AssociatedControlID = collapsableContentClientID;
     base.Controls.Add(this._collapseControl);
     base.Controls.Add(this._collapsableContent);
    }

    protected override void RenderChildren(HtmlTextWriter writer)
    {
     this._collapseControl.RenderControl(writer);
     // hack for code blocks
     if (!this.Controls.IsReadOnly)
     {
      this._collapsableContent.RenderControl(writer);
     }
     else
     {
      this._collapsableContent.RenderBeginTag(writer);
      base.RenderChildren(writer);
      this._collapsableContent.RenderEndTag(writer);
     }
    }
}
Andreas Niedermair