Validate single validation groups step by step in code behind - c#

I have three sections of a form that are contained in jquery tabs. I want to have each tab have it's own validator on it so that if there are validation errors on that form, it is easy to see which forms the user needs to re-do. The problem I am running into is that when I try something like this:
private void ValidateTabOne()
{
Page.Validate("t1");
if (!Page.IsValid)
cvt1.IsValid = false;
}
private void ValidateTabTwo()
{
Page.Validate("t2");
if (!Page.IsValid)
cvt2.IsValid = false;
}
protected void btnSave_Click(object sender, EventArgs e)
{
ValidateTabOne();
ValidateTabTwo();
if (Page.IsValid)
{
//do the save
}
}
cvt2 will always be invalid if anything in the t1 group is invalid (regardless of if t2 group is valid or not) because I Validate("t1") first.
I'd still like a way to do this in the code behind. How can I validate a single group at a time, or "reset" the validation to exclude the previous groups in the Page.IsValid check?
I know that worst case I can write a huge statement to check each validator for IsValid but would much rather use the validation groups.

The best way I have found to do this for now is to use Page.GetValidators as such:
foreach (IValidator v in Page.GetValidators("t1"))
{
if (!v.IsValid)
{
cvt1.IsValid = false;
return;
}
}
cvt1.IsValid = true;
Beforehand I do my custom validation, this just checks to make sure all the required validation is already accounted for.

Related

checking items in a list and take a decision

I want to build a program in Windows forms where the user can create a pizza by pressing buttons.
My problem is that when the user presses an ingredient more than once, the list will just increment. I tried various methods but they don't seem to work.
I have seen a solution using a for loop checking individual items in the list however I will have to implement that 19 times which is not really efficient (once for every button)
string check = "Thin Base";
if (My_Pizza.Contains(check))
{
My_Pizza.Items.Remove("ThinBase");
My_Pizza.Items.Add("Thin Base");
}
You have "ThinBase" and "Thin Base". Not the same thing.
Also, if an item is already in the list, you don't need to do anything. Simply invert your check
string check = "Thin Base";
if (!My_Pizza.Items.Contains(check))
{
My_Pizza.Items.Add(check);
}
General idea is not to hardcode string values, but create reusable method that will do what you need: check if certain value is already in the list and if it not, add this item to list. This will help you to avoid duplicate code.
In the button event handler you simply call this method and provide string value as parameter. I'm not sure how exactly you handle button clicks, but I would suggest creating single reusable method once again and acquire string value from button.Text property.
Here is code sample for you to demonstrate the idea.
private void OnButtonClick(object sender, EventArgs e)
{
Button clickedButton = (Button) sender;
if (clickedButton != null)
{
string buttonContent = clickedButton.Text;
CheckAndAdd(buttonContent);
}
}
private void CheckAndAdd(string valueToCheck)
{
if (!My_Pizza.Items.Contains(valueToCheck))
{
My_Pizza.Items.Add(valueToCheck);
}
}

C# - Enable/Disable MenuStrip Item Based On TextBox Value

I am trying to disable some menu strip items while a textbox is displaying "Calculating...". Once that value goes away, I wish to re-enable the menu items. Its purpose is not to interrupt MD5/CRC32 calculations. So far, I've tried various method of code, and have had no luck so far. What's listed below should work, but for some reason it does not. Any help would be appreciated.
// THIS PART WORKS
if (boxMD5.Text.Contains("Calculating") == true)
{
openROMToolStripMenuItem.Enabled = false;
saveROMDataToolStripMenuItem.Enabled = false;
asTXTToolStripMenuItem.Enabled = false;
asHTMLToolStripMenuItem.Enabled = false;
}
// THIS PART DOES NOT WORK
else if (boxMD5.Text.Contains("Calculating") == false)
{
openROMToolStripMenuItem.Enabled = true;
saveROMDataToolStripMenuItem.Enabled = true;
asTXTToolStripMenuItem.Enabled = true;
asHTMLToolStripMenuItem.Enabled = true;
}
I can't quite tell you why the code isn't doing what you expect, but I can make a suggestion that will change your approach and may help achieve your goal at the same time. What you are trying to do shouldn't be to disable the menu when the textbox contains "Calculating" but instead you should disable the menu while the calculations are being performed. From a user/UI perspective, these are the same thing, but the inner-workings of your program know better.
Based on you PasteBin code, try this:
private void openROMToolStripMenuItem_Click(object sender, EventArgs e)
{
//Other code omitted for brevity
if (File.Exists(OpenFileDialog1.FileName))
{
UpdateUI("Calculating...");
backgroundWorker1.RunWorkerAsync(OpenFileDialog1.FileName);
}
//Other code omitted for brevity
}
and
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
UpdateUI(e.Result.ToString());
}
where the new method UpdateUI() looks like this:
void UpdateUI(string hash)
{
var calculating = hash == "Calculating...";
if (!calculating)
{
progressBar1.Value = 0;
}
openROMToolStripMenuItem.Enabled = !calculating;
saveROMDataToolStripMenuItem.Enabled = !calculating;
asTXTToolStripMenuItem.Enabled = !calculating;
asHTMLToolStripMenuItem.Enabled = !calculating;
boxMD5.Text = hash;
}
Also, notice how you are able to just put !calculating in the if statement rather than calculating == false. This is because the value is already true or false so you don't have to compare it to anything to figure that out. The same thing applies to your original code but you don't need it anymore with this approach.

Why isn't this causing an infinite loop of events?

I have a simple application that reverses any text typed to it in another textbox. The catch is, you can modify either textbox and the changes will be (literally) reflected in the other.
I wrote this code, believing for it to cause problems.
private void realText_TextChanged(object sender, EventArgs e)
{
mirrorText.Text = mirror(realText.Text);
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
realText.Text = mirror(mirrorText.Text);
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
I then tried it out, believing that it would cause an infinite loop (realText changes mirrorText, another event happens, mirrorText changes realText, etc). However, nothing except the intended behavior happened.
I'm of course happy about this, I could just leave it here. Or could I?
I'm quite sure the TextChanged event is supposed to be fired whenever Text is changed. Is this intended behavior of some error protection in the events, or was I just lucky? Can this code misbehave on another computer, with other build settings, etc? It can be easily fixed:
private void realText_TextChanged(object sender, EventArgs e)
{
if (realText.Focused)
{
mirrorText.Text = Mirror(realText.Text);
}
}
I'll probably do it anyway to be safe, but is it required to check this? (I'm not even going to ask if it's recommended.)
Per the comments, and as already answered, the TextChanged event is not getting raised when you set the Text property to the value it already has.
It's not clear whether this is something you can safely rely upon. It is a sensible optimisation, and I would be very surprised if future versions of .NET Framework drop it, but I cannot speak for older versions, nor for third-party implementations (Mono).
To be absolutely safe, I would not use the Focused check you put in your question. I would do exactly what the Text setter does now.
private void realText_TextChanged(object sender, EventArgs e)
{
var newMirrorText = Mirror(realText.Text);
if (mirrorText.Text != newMirrorText)
mirrorText.Text = newMirrorText;
}
This has the same advantage of preventing infinite recursion, but plays more nicely with other code you may put in your form that changes the text as a result of some other event.
The reason it doesn't cause a loop is that it checks whether the Text property actually changed, i.e. if the new value does not equal the old value. In your case the mirror function happens to reverse itself, which leads to the same text after two passes.
It's pretty easy to check.
First, replace both textbox controls with
class T : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}
Second, set the breakpoint on setter. Add these expressions to the Watch window:
Name
Text
value
Third, launch the app, copy '123' from somewhere and paste it to the first textbox. Here it goes:
1st break:
Name: "mirrorText"
Text: ""
value: "321"
2nd break:
Name: "realText"
Text: "123"
value: "123"
3rd... whoops, it does not breaks anymore. To detect why we had to go deeper. Look at referencesource: text box setter does nothing unusual, but TextBoxBase's one looks interesting:
set {
if (value != base.Text) { // Gotcha!
base.Text = value;
if (IsHandleCreated) {
// clear the modified flag
SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
}
}
}
So, as hvd already answered, the reason is the textbox does not raise TextChanged if old and new values are the same. I don't think the behavior will change, at least for winforms. But if you want more robust solution, here it is:
private void RunOnce(ref bool flag, Action callback)
{
if (!flag)
{
try
{
flag = true;
callback();
}
finally
{
flag = false;
}
}
}
private bool inMirror;
private void realText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
mirrorText.Text = mirror(realText.Text);
});
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
realText.Text = mirror(mirrorText.Text);
});
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
P.S. mirror() will fail on surrogate pairs. Here're some solutions.
If textbox has a Text, and we try to change it with the same Text, the TextChange event is not raising because new text is same as the previous.
In your code, the realText_TextChanged event reverses the text and changes the mirrorText with it.
The mirrorText_TextChanged event reverses the text and try to change the realText.
The realText has already this text and does not raises the realText_TextChanged event.

Datatype for submit to database

I'm sending the contents of text boxes and checkboxes to my database via a WCF service.
So far, I have
fNameTxtBox.Text, - string
(DateTime) BirthDate.Value, - System.DateTime
toggle1.IsChecked, - bool
But what happens if the datatype is int?
Unfortunately the autocomplete does not help me as such, and of course it doesn't accept .Text as an ending.
Anybody able to lend a hand and let me know what this would be?
EDIT:
Here is my complete statement that I am trying to complete. I am looking for the ending for ownerTextBox which for which the method required it to be an int, when the source is a text box on a WP7 app:
private void addAccountBtn_Click(object sender, RoutedEventArgs e)
{
_ServiceClient.AddDriverAsync(fnameTxtBox.Text, snameTxtBox.Text, (DateTime)BirthDate.Value, phonemobNumBox.Text, toggle1.IsChecked, toggle2.IsChecked, toggle3.IsChecked, toggle4.IsChecked, toggle5.IsChecked, toggle6.IsChecked, toggle7.IsChecked, toggle8.IsChecked, toggle9.IsChecked, toggle10.IsChecked, toggle11.IsChecked, toggle12.IsChecked, toggle13.IsChecked, toggle14.IsChecked, toggle15.IsChecked, ownerTextBox.????);
}
ie replace the ???? with the correct ending, or reformat that part as such so that it works.
You need to perform validation on the client to ensure that an invalid value never gets sent to your service. You can do this by checking if the value is a integer, and display a message if its not. Only send the data to your service if it meets the validation criteria.
public void OnButtonClick(object sender, EventArgs e) {
int value;
bool isValid = int.TryParse(textBox.Text, out value);
if (isValid) {
// send to WCF
}
else {
// display a message
}
}
You will need to parse the value using the int class, e.g.
int.Parse(myTextBox.Text)
Note that int.Parse will throw an exception if the value cannot be represented as an integer, so you may want to perform appropriate validation or exception handling. Look into the TryParse family of methods.
You may find it useful to read up on Casting, Type Conversion, and Parsing.
Using the source-code you posted, you would change it to:
private void addAccountBtn_Click(object sender, RoutedEventArgs e)
{
_ServiceClient.AddDriverAsync(
fnameTxtBox.Text, <snip_lots_of_arguments>,
toggle15.IsChecked,
int.Parse(ownerTextBox.Text)); //I've only changed the very last bit here
}

Server-side RequiredFieldValidators not working

I have a form representing a survey that is dynamically generated based on some database configuration. I have a custom server control for rendering the survey (SurveyRenderer) which contains custom server controls for rendering questions (QuestionRenderers). I dynamically add RequiredFieldValidators for questions if they are flagged as being required. I add these validators to the SurveyRenderer's control collection.
The gist of the code...
// In SurveyRenderer.CreateChildControls()...
foreach (QuestionRenderer questionRenderer in questionRenderers)
{
if (questionRenderer.Question.IsRequired)
{
Controls.Add(CreateRequiredValidator(questionRenderer));
}
}
The client-side validation works fine -- if someone has omitted a required question, the validators catch it and the form doesn't validate. However if I turn off JavaScript and submit an invalid form, the validators do not seem to work.
On the server-side I am calling Page.Validate() and checking Page.IsValid in the submit button click event handler. Despite submitting a form where required questions have been left blank - something that would be caught client-side - on the server-side Page.IsValid remains True.
// In SurveyPage.aspx...
public void btnSubmit_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
// Always get here, even though the form is not valid and would
// have been caught client-side...
}
}
Should I be adding the validators to the Page's Control collection, rather than the SurveyRenderer? How come it works on the client-side but not server-side?
UPDATE: My QuestionRenderer is annotated with:
[ValidationProperty("IsValid")]
And the IsValid get method is like so:
// QuestionRenderer.IsValid
public bool IsValid
{
get
{
EnsureChildControls();
if (Question.IsRequired && QuestionIsNotAnswered())
{
return false;
}
return true;
}
}
If I set a breakpoint and step through, I can see that QuestionRenderer.IsValid is being fired OK. It is returning false when it should do. If I go fine-grained and call in btn_submitClick:
// In SurveyPage.aspx...
public void btnSubmit_Click(object sender, EventArgs e)
{
foreach (IValidator validator in Page.Validators)
{
validator.Validate(); // this calls through to QuestionRenderer.IsValid, which returns false...
bool valIsValid = validator.IsValid; // yet this is set to True
}
}
So validator.IsValid is true, even though the call to QuestionRenderer.IsValid returns false. So maybe I haven't wired something up correctly? Is using [ValidationProperty("IsValid")] not enough?
actually, validation uses Page.Validators where all the validators are stored (the actual routine is quity tricky) - so it does not matter, where you add them.
source of BaseValidator
protected internal override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Page.Validators.Add(this);
}
i would leave them in th view, as you could use object sender-parameter (which represents the validator) to get the associated control ...
i believe, your CreateChildControls - which does the attaching of the validators - is called to late, so it misses the validation phase ...
could you maybe try to call EnsureChildControls in OnLoad-event, to see if it changes something?
another chance might be, that your validators are not visible or disabled...
EDIT
according to your edits, i would encourage you to use a CustomValidator - a RequiredFieldValidator will return true on each case (property is true or false), because it is not empty :)

Categories

Resources