Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Variables in Composite Controls

Status
Not open for further replies.

blueark

Technical User
Apr 16, 2002
1,212
IE
I'm new to creating custom controls, so forgive me if I'm missing something incredibly obvious!

I'm having trouble keeping variables up to date in a composite control I'm writing. It's a simple version of the "Wizard" control, but for v1.1. One control is a simple navigation control with previous/next buttons, and another is a list that updates with each button press. The trouble is, the list always seems to be one step behind.

The navigation control is as follows
Code:
public class Navigation : System.Web.UI.WebControls.WebControl, INamingContainer
{
  public Button btnPrev;
  public Button btnNext;

  public int CurrentStep
  {
   get { return (int) ViewState["CurrentStep"]; }
   set { ViewState["CurrentStep"] = value; }
  }

  public int StepCount
  {
   get { return (int) ViewState["StepCount"]; }
   set { ViewState["StepCount"] = value; }
  }

  public Navigation() : base(HtmlTextWriterTag.Div)
  {
   if (ViewState["CurrentStep"] == null)
    ViewState["CurrentStep"] = 0;
   if (ViewState["StepCount"] == null)
    ViewState["StepCount"] = 0;
  }

  protected override void CreateChildControls()
  {
   Controls.Clear();
   btnPrev = new Button();
   btnPrev.ID = "Previous";
   btnPrev.Click += new EventHandler(this.PrevBtn_Click);
   btnPrev.Text = "Prev";
   if (CurrentStep <= 0) { CurrentStep=0; btnPrev.Enabled = false; } else btnPrev.Enabled = true;

   btnNext = new Button();
   btnPrev.ID = "Next";
   btnNext.Click += new EventHandler(this.NextBtn_Click);
   btnNext.Text = "Next";
   if (CurrentStep >= StepCount) { CurrentStep=StepCount; btnNext.Enabled = false; } else btnNext.Enabled = true;

   Controls.Add(btnPrev);
   Controls.Add(btnNext);

   // For debugging only
   Controls.Add(new LiteralControl(" CurrentStep: " + CurrentStep.ToString()));
  }

  // Button Click events
  public void PrevBtn_Click(Object sender, EventArgs e)
  {
   if (CurrentStep > 0)
    CurrentStep--;
   CreateChildControls();
  }

  public void NextBtn_Click(Object sender, EventArgs e)
  {
   if (CurrentStep < StepCount)
    CurrentStep++;
   CreateChildControls();
  }
}

The list control is very basic:
Code:
public class Sidebar : System.Web.UI.WebControls.WebControl, INamingContainer
{
  public WizardSidebar() : base(HtmlTextWriterTag.Ol)
 {
 }
}

Finally, the main component is as follows (simplified):
Code:
[ControlBuilderAttribute(typeof(StepBuilder)),ParseChildren(false)]
public class Wizard : System.Web.UI.WebControls.WebControl, INamingContainer
{
 private Navigation myNavigation;
 private Sidebar mySidebar;
 private Step CurrentStep;
 private int StepCount;

 // Constructor	
 public Wizard() : base(HtmlTextWriterTag.Div)
 {
 }

 protected override void CreateChildControls()
 {
  StepCount = Controls.Count;
  string StepTitle = "";

  // Create placeholders
  PlaceHolder phSidebar = new PlaceHolder(); Controls.Add(phSidebar);
  PlaceHolder phNavigation = new PlaceHolder(); Controls.Add(phNavigation);

  mySidebar = new Sidebar();
  myNavigation=new Navigation();

  // Set up Navigation controls
  myNavigation.ID="Navigation";
  myNavigation.StepCount = StepCount-1;
  phNavigation.Controls.Add(myNavigation);

  [red]// Set up Sidebar
  for (int i=0; i<StepCount; i++)
  {
   CurrentStep = (Step) Controls[i];
   CurrentStep.Visible = false;
   mySidebar.Controls.Add (new LiteralControl("<li>"));
   if (myNavigation.CurrentStep == i)
    mySidebar.Controls.Add (new LiteralControl("<strong>" + CurrentStep.Title + "</strong>"));
   else
    mySidebar.Controls.Add (new LiteralControl(CurrentStep.Title));
   mySidebar.Controls.Add (new LiteralControl("</li>"));
  }
  phSidebar.Controls.Add(mySidebar);
 }[/red]

}

internal class StepBuilder : ControlBuilder
{
 public override Type GetChildControlType(string tagName, IDictionary attributes)
 {
  if (tagName == "Step")
    return typeof(Step);
  else
    return null;
 }

 public override void AppendLiteralString(string s)
 {
 }
}
I left out the "Step" class; it's probably not relevant for now.

The actual usage would be something like this:
Code:
<BA:Wizard id="ctlWizard" runat="server">
 <BA:Step Title="Step 1" runat="server" />
 <BA:Step Title="Step 2" runat="server" />
 <BA:Step Title="Step 3" runat="server" />
</BA:Wizard>

I put a text message in the navigation control to see what value the variable "Navigation.CurrentStep" is. It seems to work correctly. However, when I try to use this variable in the section marked in red, it's always one step behind. For example, when the page opens first, the first item in the list is bold, as it should be. Pressing "Next" should move onto the next item on the list, but it doesn't. Pressing it again moves the list onto the second item, but the navigation control has moved onto the third.

I hope that's clear. Thanks in advance...
 
I've made a little progress with this, but it's still not right. In the Navigation class, I took out the CreateChildControls() line in the click event handlers, and inserted the following:

Code:
protected void Page_Init(object src, EventArgs e)
{
  EnsureChildControls();
}

So, to summarize, there is a Navigation control with a public property, CurrentStep. The main container control, Wizard, tries to access this property.

Before making these changes, the Navigation control worked correctly, but the Wizard class was always one step behind, meaning the list (red section in previous post) was always out of sync. For example, CurrentStep defaulted to 0, and pressing "Next" increased it to 1. The Navigation control did this correctly, but if you try to access CurrentStep from Wizard class, it returned 0. Pressing "Next" again increased the value to 2 within the Navigation control, but only returns 1 from the Wizard class.

After making the changes, both controls are now in sync (i.e. they both get the same value for CurrentStep), but they are both one step behind. The sequence is as follows:

1. Both default to CurrentStep = 0
2. Press "Next" and both remain at 0
3. Press "Next" again and both increase to 1.
4. Press "Previous" and both increase to 2.
5. Press "Previous" again and both decrease to 1.

It seems to honor each button press, but just one step behind, so I suspect I'm doing something in the wrong order. Any ideas?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top