Just like covering up the wall sockets in a home with small children, Merlin lets you disable certain elements and validate others, so as to prevent your users from doing unsavory things.
Let's go back to the example in the previous post. There, we have a step whose UI consists of a single text box. Let's now make sure that the user cannot advance to the next step without having typed something in the box. We rewrite the main method as follows:
var t = new TextBox();
var myStep = new TemplateStep(t, 10, "Name Entry");
myStep.NextHandler = () => {
if (string.IsNullOrEmpty(t.Text))
{
MessageBox.Show("You gotta enter your name before I let you continue");
return false;
}
else return true;
};
steps.Add(myStep);
var result = new WizardController(steps).StartWizard("My SuperCoolWizard");
if (result == WizardController.WizardResult.Finish)
MessageBox.Show("Hello, " + t.Text);
That's a bit more code than we had before. Let's look at the new stuff:
if (string.IsNullOrEmpty(t.Text))
{
MessageBox.Show("You gotta enter your name before I let you continue");
return false;
}
else return true;
};
The TemplateStep class offers the NextHandler, PreviousHandler, and CancelHandler properties to handle the "Next/Finish", "Previous", and "Cancel" buttons, respectively. The first two are boolean delegates. If they return false, the controller will not leave the current step. Since the purpose of a cancel button is to drop everything and abort, it does not have a return value, and a cancellation will occur no matter what.
But why wait for the user to hit the "Next/Finish" button? Why not just gray it out altogether? I'm glad I asked!
var t = new TextBox();
var myStep = new TemplateStep(t, 10, "Name Entry");
myStep.AllowNextStrategy = () => {
return !string.IsNullOrEmpty(t.Text);
};
t.KeyUp += (object sender, KeyEventArgs keyArgs) => {
myStep.StateUpdated();
};
steps.Add(myStep);
var result = new WizardController(steps).StartWizard("My Wizard");
if (result == WizardController.WizardResult.Finish)
MessageBox.Show("Hello, " + t.Text);
This time, in lieu of a handler for the next button, we provided a strategy (in the form of a boolean delegate) to determine if the Next button should be enabled. But we needed one more piece:
myStep.StateUpdated();
};
We need to know when to recheck the strategy so that the buttons accurately reflect the validity of the user's input. To do this, we fire TemplateStep's StateUpdated method whenever something in our UI has changed.
That does it for this lesson. Please leave any questions or feedback in the comments, we'll do our best to answer.
Yev - these posts are great and I truly hope you keep them up.
ReplyDeleteA truly minor quibble, just in case this makes it into someone's production code. Wouldn't you want to subscribe to t.TextChanged rather than t.KeyUp, for circumstances such as pasting via right-click, etc?
Otherwise, this is well written and just the kind of information I was looking for. You seem to know your audience well.
-Scott
Yes, I would. I seem to remember having issues with TextChanged not firing under some circumstances, but after some experimentation, I think the former might have been user error on my part. In any case, no one ever died from subscribing to both. :-)
ReplyDelete