I'm using a 2.0 Wizard control which I want my users to be able to jump into from another page using hyperlinks to determine which step to start at.
I've tried setting the ActiveStepIndex in Page.OnLoad but I'm getting some quite unexpected behaviour from the Wizard control in terms of the events that subsequently fire, and I find that the Wizard won't let me move any further back from the step I initially
set the ActiveStepIndex to.
Has anyone experienced this too, and do they have a workaround? It seems a little quirky, but it might be me misunderstanding how to use the ActiveStepIndex property properly.
The following simple example illustrates what I'm talking about. Try putting trace messages on the WizardStep.Activate/Deactivate events and you'll see some funky stuff going on. Note that if you use the sidebar to go back beyond the 'jumped-to' step, the wizard
seems to be freed up again...
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected override void OnInit(EventArgs e)
{
// only check on first time in
if (!IsPostBack)
// look in querystring for jump command
if (Request.QueryString["jumptostep"] != null)
// do the jump
TheWizard.ActiveStepIndex = Convert.ToInt32(Request.QueryString["jumptostep"]);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title /></head>
<body>
<form id="form1" runat="server">
imagine these links are on another page:<br />
jump in at: [<a href="?jumptostep=1">step 1</a>][<a href="?jumptostep=2">step 2</a>]
<hr />
<asp:Wizard ID="TheWizard" runat="server">
<WizardSteps>
<asp:WizardStep ID="Step0" runat="server">Step 0</asp:WizardStep>
<asp:WizardStep ID="Step1" runat="server">Step 1</asp:WizardStep>
<asp:WizardStep ID="Step2" runat="server">Step 2</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
</form>
</body>
</html>
Can anyone shed any light as to what's going on? This has been driving me barmy all of Friday and it's going to spoil my weekend at this rate!
Taking a break and coming back to this with a clear head, I think i have fixed it. The answer is actually ridiculously easy. The problems manifest themselves when you try to nagivate forwards and backwards after jumping in - strange things
happen with the e.NextStepIndex value if you watch the next/prev button events fired - so the solution is to just hook the NextButtonClick and PreviousButtonClick events on the Wizard, and override the screwy e.NextStepindex settings by deliberately setting
the ActiveStepIndex each time.
You get an ActiveStepChanged event firing when you make those changes to ActiveStepIndex, but that's expected and fine by me.
This seems to work for me, though I can't understand why this wouldn't be what's going on inside the control anyway. I guess either I'm misunderstanding how it's supposed to work, or this is a bug.
by the way, if anyone's interested, here's the test rig I used to figure this out, it's a modified version of the code I posted above:
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected override void OnLoad(EventArgs e)
{
TheWizard.ActiveStepChanged += new EventHandler(TheWizard_ActiveStepChanged);
TheWizard.NextButtonClick += new WizardNavigationEventHandler(TheWizard_NextButtonClick);
TheWizard.PreviousButtonClick += new WizardNavigationEventHandler(TheWizard_PreviousButtonClick);
TheWizard.Init += new EventHandler(TheWizard_Init);
TheWizard.Load += new EventHandler(TheWizard_Load);
TheWizard.PreRender += new EventHandler(TheWizard_PreRender);
TheWizard.Unload += new EventHandler(TheWizard_Unload);
// only check on first time in
if (!IsPostBack)
// look in querystring for jump command
if (Request.QueryString["jumptostep"] != null)
{
// do the jump
//TheWizard.ActiveStepIndex = Convert.ToInt32(Request.QueryString["jumptostep"]);
TheWizard.MoveTo(TheWizard.WizardSteps[
Convert.ToInt32(Request.QueryString["jumptostep"])
]);
}
}
Just thought I'd add some more detail to this thread after the weekend so it may get a little more attention. The solution was not quite a simple as I had first thought, and I've had to disable viewstate on the wizard to stop some dynamicly-generated
controls I use on one step from failing when the form posts-back after setting ActiveStepIndex.
My feeling is that the wizard is storing 'current step' state in two different ways (maybe using a hidden field), and the various parts of the control (e.g restoring viewstate) are not all consistently using the same value. If I had time I'd dig a bit deeper,
but deadlines call...
I'd love for someone with more experience of this control than mine to comment... anyone?
The wizard is designed to keep a history of steps and use this history for backward navigation [clicking 'Previous' means going to the last step in the
history not the 'Previous' step to the current step in the wizard. Thus if a user jumped to a particular step by setting ActiveStepIndex on the first browse
– there is no history and the “Previous” button will not do anything, the side bar has to be used in such a case for navigation.
Aha! Thanks Kashif, with that perspective on it things start to make a lot more sense. Any tips on where I can find out that level of information about these new controls? The MSDN documentation is pretty plain, and there's not much on
CodeProject etc. yet.
I was able to get the steps to work consistent by adding a handler and for each NEXT / PREVIOUS event either subtract or add to the active index. Some minor conditions were added and validation to also protect consistency.
Additionally I included a START step followed by regular steps and Fisihed step. I set the ALLOW PREVIOUS to True on all steps and only changed this setting to False when needed in backend code.
e.g.
' Handler for Nex/Previous buttoms must be first in LOAD section.
AddHandler myWizard.PreviousButtonClick, handler
AddHandler myWizard.NextButtonClick, handler
Protected
Sub myWizard_NextButtonClick(ByVal sender
As Object,
ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs)
Handles myWizard.NextButtonClick
End Sub
Protected
Sub myWizard_PreviousButtonClick(ByVal sender
As Object,
ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs)
Handles myWizard.PreviousButtonClick
Matt Wynne
Member
40 Points
8 Posts
Setting ActiveStepindex on a Wizard Control
Mar 18, 2006 04:34 PM|LINK
I've tried setting the ActiveStepIndex in Page.OnLoad but I'm getting some quite unexpected behaviour from the Wizard control in terms of the events that subsequently fire, and I find that the Wizard won't let me move any further back from the step I initially set the ActiveStepIndex to.
Has anyone experienced this too, and do they have a workaround? It seems a little quirky, but it might be me misunderstanding how to use the ActiveStepIndex property properly.
The following simple example illustrates what I'm talking about. Try putting trace messages on the WizardStep.Activate/Deactivate events and you'll see some funky stuff going on. Note that if you use the sidebar to go back beyond the 'jumped-to' step, the wizard seems to be freed up again...
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected override void OnInit(EventArgs e)
{
// only check on first time in
if (!IsPostBack)
// look in querystring for jump command
if (Request.QueryString["jumptostep"] != null)
// do the jump
TheWizard.ActiveStepIndex = Convert.ToInt32(Request.QueryString["jumptostep"]);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title /></head>
<body>
<form id="form1" runat="server">
imagine these links are on another page:<br />
jump in at: [<a href="?jumptostep=1">step 1</a>][<a href="?jumptostep=2">step 2</a>]
<hr />
<asp:Wizard ID="TheWizard" runat="server">
<WizardSteps>
<asp:WizardStep ID="Step0" runat="server">Step 0</asp:WizardStep>
<asp:WizardStep ID="Step1" runat="server">Step 1</asp:WizardStep>
<asp:WizardStep ID="Step2" runat="server">Step 2</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
</form>
</body>
</html>
Can anyone shed any light as to what's going on? This has been driving me barmy all of Friday and it's going to spoil my weekend at this rate!
cheers,
Matt
Matt Wynne
Member
40 Points
8 Posts
Re: Setting ActiveStepindex on a Wizard Control
Mar 18, 2006 06:58 PM|LINK
void TheWizard_PreviousButtonClick(object sender, WizardNavigationEventArgs e)
{
((Wizard)sender).ActiveStepIndex = ((Wizard)sender).ActiveStepIndex - 1;
}
void TheWizard_NextButtonClick(object sender, WizardNavigationEventArgs e)
{
((Wizard)sender).ActiveStepIndex = ((Wizard)sender).ActiveStepIndex + 1;
}
You get an ActiveStepChanged event firing when you make those changes to ActiveStepIndex, but that's expected and fine by me.
This seems to work for me, though I can't understand why this wouldn't be what's going on inside the control anyway. I guess either I'm misunderstanding how it's supposed to work, or this is a bug.
Hope this helps someone else.
cheers,
Matt
Matt Wynne
Member
40 Points
8 Posts
Test code
Mar 18, 2006 07:05 PM|LINK
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected override void OnLoad(EventArgs e)
{
TheWizard.ActiveStepChanged += new EventHandler(TheWizard_ActiveStepChanged);
TheWizard.NextButtonClick += new WizardNavigationEventHandler(TheWizard_NextButtonClick);
TheWizard.PreviousButtonClick += new WizardNavigationEventHandler(TheWizard_PreviousButtonClick);
TheWizard.Init += new EventHandler(TheWizard_Init);
TheWizard.Load += new EventHandler(TheWizard_Load);
TheWizard.PreRender += new EventHandler(TheWizard_PreRender);
TheWizard.Unload += new EventHandler(TheWizard_Unload);
// only check on first time in
if (!IsPostBack)
// look in querystring for jump command
if (Request.QueryString["jumptostep"] != null)
{
// do the jump
//TheWizard.ActiveStepIndex = Convert.ToInt32(Request.QueryString["jumptostep"]);
TheWizard.MoveTo(TheWizard.WizardSteps[
Convert.ToInt32(Request.QueryString["jumptostep"])
]);
}
}
void TheWizard_Unload(object sender, EventArgs e)
{
ReportState(sender, "Unload");
}
void TheWizard_PreRender(object sender, EventArgs e)
{
ReportState(sender, "PreRender");
}
void TheWizard_Load(object sender, EventArgs e)
{
ReportState(sender, "Load");
}
void TheWizard_Init(object sender, EventArgs e)
{
ReportState(sender, "Init");
}
void TheWizard_PreviousButtonClick(object sender, WizardNavigationEventArgs e)
{
ReportState(sender, "PreviousButtonClick", e.CurrentStepIndex, e.NextStepIndex);
((Wizard)sender).ActiveStepIndex = ((Wizard)sender).ActiveStepIndex - 1;
ReportState(sender, "PreviousButtonClick - Fix?", e.CurrentStepIndex, e.NextStepIndex);
}
void TheWizard_NextButtonClick(object sender, WizardNavigationEventArgs e)
{
ReportState(sender, "NextButtonClick", e.CurrentStepIndex, e.NextStepIndex);
((Wizard)sender).ActiveStepIndex = ((Wizard)sender).ActiveStepIndex + 1;
ReportState(sender, "NextButtonClick - Fix?", e.CurrentStepIndex, e.NextStepIndex);
}
void TheWizard_ActiveStepChanged(object sender, EventArgs e)
{
ReportState(sender, "ActiveStepChanged");
}
void ReportState(object sender, string eventName)
{
ReportState(sender, eventName, null, null);
}
void ReportState(object sender, string eventName, int? currentStepIdx, int? nextStepIdx)
{
Wizard wiz = (Wizard)sender;
WriteTrace("<b>" + eventName + "</b>" +
"ActiveStepIndex = " + wiz.ActiveStepIndex.ToString() +
((currentStepIdx.HasValue) ? "CurrentStepIndex = " + currentStepIdx.ToString() : "") +
((nextStepIdx.HasValue) ? "NextStepIndex = " + nextStepIdx.ToString() : "")
);
}
void WriteTrace(string msg)
{ this.TraceBox.Text += msg + "<br/>"; }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title /></head>
<body>
<form id="form1" runat="server">
imagine these links are on another page:<br />
jump in at: [<a href="?jumptostep=2">step 2</a>][<a href="?jumptostep=3">step 3</a>]
<hr />
<asp:Wizard ID="TheWizard" runat="server">
<WizardSteps>
<asp:WizardStep ID="Step0" runat="server">Step 0</asp:WizardStep>
<asp:WizardStep ID="Step1" runat="server">Step 1</asp:WizardStep>
<asp:WizardStep ID="Step2" runat="server">Step 2</asp:WizardStep>
<asp:WizardStep ID="Step3" runat="server">Step 3</asp:WizardStep>
<asp:WizardStep ID="Step4" runat="server">Step 4</asp:WizardStep>
<asp:WizardStep ID="Step5" runat="server">Step 5</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
<asp:Literal ID="TraceBox" runat="server" EnableViewState="false"></asp:Literal>
</form>
</body>
</html>
Matt Wynne
Member
40 Points
8 Posts
The Plot Thickens
Mar 21, 2006 05:07 PM|LINK
My feeling is that the wizard is storing 'current step' state in two different ways (maybe using a hidden field), and the various parts of the control (e.g restoring viewstate) are not all consistently using the same value. If I had time I'd dig a bit deeper, but deadlines call...
I'd love for someone with more experience of this control than mine to comment... anyone?
kashif
Contributor
2748 Points
547 Posts
Microsoft
Re: The Plot Thickens
Mar 23, 2006 08:42 PM|LINK
Matt
The wizard is designed to keep a history of steps and use this history for backward navigation [clicking 'Previous' means going to the last step in the history not the 'Previous' step to the current step in the wizard. Thus if a user jumped to a particular step by setting ActiveStepIndex on the first browse – there is no history and the “Previous” button will not do anything, the side bar has to be used in such a case for navigation.
Thanks,
Kashif
Matt Wynne
Member
40 Points
8 Posts
Re: The Plot Thickens
Mar 24, 2006 05:07 AM|LINK
thanks again,
Matt
lax4u
Participant
1592 Points
902 Posts
Re: The Plot Thickens
Feb 03, 2009 04:44 PM|LINK
then can we programatically add history to Wizard control?
gogginl
Member
79 Points
261 Posts
Re: The Plot Thickens
Feb 17, 2009 06:47 PM|LINK
I was able to get the steps to work consistent by adding a handler and for each NEXT / PREVIOUS event either subtract or add to the active index. Some minor conditions were added and validation to also protect consistency. Additionally I included a START step followed by regular steps and Fisihed step. I set the ALLOW PREVIOUS to True on all steps and only changed this setting to False when needed in backend code.e.g.
' Handler for Nex/Previous buttoms must be first in LOAD section.
AddHandler myWizard.PreviousButtonClick, handler AddHandler myWizard.NextButtonClick, handler Protected Sub myWizard_NextButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles myWizard.NextButtonClickmyWizard.ActiveStepIndex = myWizard.ActiveStepIndex + 1
End Sub Protected Sub myWizard_PreviousButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles myWizard.PreviousButtonClickmyWizard.ActiveStepIndex = myWizard.ActiveStepIndex - 1
End Sub