Custom Control problem.

Discussion in 'ASP .Net Building Controls' started by David, Oct 29, 2006.

  1. David

    David Guest

    Hi all,

    I am not quite sure how to phrase the subject, so apologies.

    I am writing a custom control. It is using a textbox. I create the text box,
    but cannot read the contents of it later.

    Here is my code...

    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.ComponentModel;
    using System.Drawing;

    namespace MyProjectControls
    {
    /// <summary>
    /// Summary description for WebCustomControl1.
    /// </summary>
    [DefaultProperty("Text"),
    ToolboxData("<{0}:WebCustomControl1
    runat=server></{0}:WebCustomControl1>")]
    public class HTMLPlaceHolder : System.Web.UI.WebControls.WebControl
    {

    private System.Web.UI.WebControls.TextBox tb = new TextBox();


    private string text;
    private string _CurrentViewMode = "display";

    [Bindable(true),
    Category("Appearance"),
    DefaultValue("")]
    public string Text
    {
    get
    {
    return text;
    }

    set
    {
    text = value;
    }
    }

    public string CurrentViewMode
    {
    get
    {
    return _CurrentViewMode.ToLower();
    }

    set
    {
    _CurrentViewMode = value.ToLower();
    }
    }

    /// <summary>
    /// Render this control to the output parameter specified.
    /// </summary>
    /// <param name="output"> The HTML writer to write out to </param>
    protected override void Render(HtmlTextWriter output)
    {

    RenderContents(output);

    }


    protected override void OnPreRender(EventArgs e)
    {
    System.Web.UI.Page MyPage = this.Page as System.Web.UI.Page;

    CurrentViewMode = MyPage.PageState;

    Text = "This is purely test text"

    if (MyPage.AllowSave)
    {
    SavePlaceholder();
    }

    switch (CurrentViewMode)
    {
    case "edit" :
    AuthoringPlaceholder();
    break;
    case "display" :
    DisplayPlaceholder();
    break;
    case "design" :
    DesignPlaceholder();
    break;
    default:
    DisplayPlaceholder();
    break;
    }


    base.OnPreRender (e);
    }

    protected void DesignPlaceholder()
    {
    }

    protected void AuthoringPlaceholder()
    {
    //TextBox tb = new TextBox();

    //this.tb = new TextBox();
    this.tb.ID = this.ID;
    this.tb.TextMode = TextBoxMode.MultiLine;
    this.tb.Text = Text;
    this.tb.Columns = 40;
    this.tb.Rows = 15;

    Controls.Add(this.tb);

    }

    protected void DisplayPlaceholder()
    {
    LiteralControl lit = new LiteralControl("<div>" + Text + "</div>");
    Controls.Add(lit);
    }

    protected void SavePlaceholder()
    {
    System.Web.HttpContext.Current.Response.Write(this.tb.Text);
    }

    }
    }


    In the SavePlaceHolder, I want to be able to display what is written in the
    text box. (Actually, I want to save it, but to display it will show that
    something is happening).

    However, this.tb.Text has nothing in it in the SavePlaceholder.

    How can I ensure that what is coming back when the page is submitted is
    actually there?

    Thanks.

    Best regards,
    Dave Colliver.
    http://www.AshfieldFOCUS.com
    ~~
    http://www.FOCUSPortals.com - Local franchises available
     
    David, Oct 29, 2006
    #1
    1. Advertisements

  2. David

    tdotnet Guest

    It's been a while since I've done one of these, but glancing through
    the code, I could be just missing it, but I could not find where your
    Text property sets the .Text property of the TextBox. And where or how
    do you restore the value to your text field string on a postback?

    -Tyler
    http://www.netbrick.net - The .NET Developer Search Engine
     
    tdotnet, Oct 29, 2006
    #2
    1. Advertisements

  3. I think the problem you have is that you're not loading the contents of
    the control tree properly. I don't think .NET can find the Textbox
    control when a Postback happens so it can't properly set the textbox
    text property. This is because you're only adding the textbox in the
    PreRender event if the user is in edit mode.

    You want to sure ensure that all controls sent to the client are loaded
    again in the init event during a postback. THis allow .NET to properly
    map form objects to .NET controls. You can try either 1) Always
    loading the textbox but setting the visible property to true or false,
    2) Add a marker that will tell the control to load the Textbox in the
    Init event if it was sent out during the Init event. 3) Explicitly
    setting the text property of the Textbox by implementing the
    IPostBackDataHandler interface.
     
    Michael Hamrah, Oct 29, 2006
    #3
  4. David

    David Guest

    Hi,

    Thank you both (tdotnet and Michael), however I am still having problems...
    It may be a combination of both answers.

    I have written an OnInit

    protected override void OnInit(EventArgs e)
    {
    //tb.ID = this.ID;
    tb.TextMode = TextBoxMode.MultiLine;
    //this.tb.Text = Text;
    tb.Columns = 40;
    tb.Rows = 15;

    Controls.Add(tb);
    base.OnInit (e);
    }

    (Note, the Text property has been remarked, as that can only really be
    loaded in the OnPreRender).

    This seems to prepare the textbox but on the postback, when I am trying to
    read it, there is nothing. How do I ensure that there is text in the
    postback?

    (I pre-load the text box in pre-render, I wish to be able to change the
    contents and I want to see what is in the text boxes when it comes back)

    I have never used the IPostBackDataHandler. Given what I have written above,
    does it look like this is what I need? If so, can you show me an example?

    Thanks.

    Best regards,
    Dave Colliver.
    http://www.AshfieldFOCUS.com
    ~~
    http://www.FOCUSPortals.com - Local franchises available
     
    David, Oct 29, 2006
    #4
  5. David

    David Guest

    Hi,

    Sorted it. A combination of OnInit and IPostBackDataHandler (which gave me a
    few headaches to make work...).

    It seems that IPostBackDataHandler needs to return a boolean value. What is
    this for?

    Best regards,
    Dave Colliver.
    http://www.SheffieldFOCUS.com
    ~~
    http://www.FOCUSPortals.com - Local franchises available
     
    David, Oct 29, 2006
    #5
  6. The IPostBackDataHandler returns a boolean value if the data has
    changed in the control. THis is so it can raise a data changed event.

    I wrote the following code below which doesn't use the
    IPostBackDataHandler (it relies on the textbox data handler, but it may
    not fit your needs in the long run.

    Anyway, the trick is to leverage the CreateChildControls function.
    This function gets called anytime .NET needs the control to be in a
    valid state- essentially during a postback after the init event and
    before it gets rendered.

    public class HTMLPlaceholder : CompositeControl
    {
    private TextBox tb = new TextBox();

    private string _text;
    private string _viewMode;

    public string ViewMode
    {
    get { return (ViewState["ViewMode"] == null) ? "default" :
    ViewState["ViewMode"].ToString(); }
    set { ViewState["ViewMode"] = value; }
    }
    public string Text
    {
    get { return _text; }
    set { _text = value; }
    }
    protected override void OnInit(EventArgs e)
    {
    base.OnInit(e);
    }
    protected override void OnLoad(EventArgs e)
    {
    this.Text = tb.Text;
    base.OnLoad(e);
    }
    protected override void OnPreRender(EventArgs e)
    {

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

    switch (ViewMode)
    {
    case "Edit":
    AuthoringPlaceholder();
    break;
    case "default":
    TextPlaceHolder();
    break;
    }
    base.CreateChildControls();
    }
    protected void AuthoringPlaceholder()
    {
    tb = new TextBox();
    this.tb.ID = this.ID;
    this.tb.TextMode = TextBoxMode.MultiLine;
    //this.tb.Text = Text; Don't need to set this
    this.tb.Columns = 40;
    this.tb.Rows = 15;

    Controls.Add(this.tb);
    }
    protected void TextPlaceHolder()
    {
    this.Controls.Add(new LiteralControl(this.Text));
    }
    }

    In your page class you can switch modes like this:

    protected void Page_Load(object sender, EventArgs e)
    {
    if (this.IsPostBack)
    {
    test.ViewMode = "default";
    }
    }

    And place it in the page like this:

    <cc1:HTMLPlaceholder runat=server ViewMode="Edit" id="test" />
    <asp:Button runat="server" ID="submit" Text="submit" />
     
    Michael Hamrah, Oct 30, 2006
    #6
    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.