View previous topic :: View next topic |
Author |
Message |
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Tue Feb 10, 2015 4:35 pm Post subject: textbox validation |
|
|
I have read many posts on this, and it seems there are three elements involved in handling values a user typed in a textbox for an edit.
1) GetControlValue - used to do any custom value conversions before validation starts
2) Validating event hooked up through editor InitializeControl. This is used to cancel if the value is invalid.
3) Validated event hooked same way, and generally used to do something with the value, such as save to the bound object prop.
Correct me if wrong on above items pls, I will be using this a ton so need validation, so to speak ok....
In GetControlValue, its easy to get row and column object using e and then have access to the object bound.
The textbox events have no reference to the row or column though.
I need to know those as the value gets handled differently depending on them (and the value itself too).
The value is easy, but the row and column are confusing me.
Also, if I do handle the validated event, does that override the normal mechanism that would update the bound object?
The fact that I don't know that tells you I am not clear on the binding.
I use programmatic binding for all my vtrees as I need control along the way for most things. This is the first time I am using editors though.
I use validated event on textboxes normally, so must be close. _________________ James M |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Tue Feb 10, 2015 5:42 pm Post subject: |
|
|
I decided to try the txtEditor_GetControlValue method and it seems to let me do what I want, but I read its not intended for validation.
Why not though? I can cancel an edit by telling it to do nothing right?
I guess the edit is done by then, so no chance to let the user correct things maybe.
I did see posts saying the row can be recalled from the textbox by setting the e.control.tag to the row in the initialize event.
I also need to know the column, so am thinking I just make a couple props for the tree called curEditorRow and CurEditorCol, and set those in initialize.
I also found posts talking about using cellwidget to do things like handle the editchanged and other events.
I do use custom cellwidgets in other trees, and actually do need to control the width of the textbox so likely need to use one.
The cellwidget has a lot of power, I could sure use more examples of cool things people have done with it. _________________ James M |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Tue Feb 10, 2015 7:12 pm Post subject: |
|
|
I did some tests showing the GetControlValue is definately not the place to take the value from the textbox and "take over" assigning it to the bound object.
It is only a chance to modify the e.value that then continues on to the binding process no matter what.
So I could change the value there, but not prevent the bound object from being updated.
I guess preventing the update should be done in the validating event.
The validated event I normally use with textboxes is replaced by the binding in the VT case.
I guess I need to use the validating event to do any value changing or cancelling. That means using vars to know row and column.
I need to try the cellwidget events to see if they can interrupt the binding update process more. _________________ James M |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Tue Feb 10, 2015 10:18 pm Post subject: |
|
|
You can set the tag on the text box to the CellWidget - this gives you both the Row and the Column. For instance:
Code: | private void textEditor_InitializeControl(object sender, CellEditorInitializeEventArgs e)
{
e.Control.Tag = e.CellWidget;
if (e.NewControl)
{
e.Control.Validating += new CancelEventHandler(Control_Validating);
}
}
void Control_Validating(object sender, CancelEventArgs e)
{
TextBox textBox = sender as TextBox;
CellWidget cellWidget = textBox.Tag as CellWidget;
if (cellWidget.Column == this.colContactName &&
cellWidget.Row.ChildIndex == 2)
{
if (textBox.Text == "Foo")
{
e.Cancel = true;
}
}
}
|
This only applies the specific validation (that the text is not "Foo") to a given column and row. _________________ Infralution Support |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Wed Feb 11, 2015 12:21 am Post subject: |
|
|
that works, but that e.cancel leaves you in the edit mode still.
I tried using the curWidget.AbandonEdit() method in the validating method, but that does not prevent the value from being sent to the bound object property.
I tried doing both e.cancel and AbandonEdit() but the focus gets left on the edit control and the tree is locked up. I read someone else solved this but did not explain how it was solved.
So if I catch a nonvalid value during validating, how do I get out of the edit and stop the update?
Thanks for your replies so far, the tree is so key to the progs I am doing. _________________ James M |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Wed Feb 11, 2015 3:50 am Post subject: |
|
|
Quote: | but that e.cancel leaves you in the edit mode still. |
That's the normal use of validation - it just prevents focus leaving the control until the user types a valid entry. Normally you would beep and/or display some form of message to indicate what the problem was. Then the user has the chance to fix their mistake - or they can hit Escape and return the previous value (which should pass the validation rule).
If for some reason you just want to revert to the previous value if there was an error and stop editing then you could just call the AbandonEdit() function from within the Validating event like:
Code: | void Control_Validating(object sender, CancelEventArgs e)
{
TextBox textBox = sender as TextBox;
CellWidget cellWidget = textBox.Tag as CellWidget;
if (cellWidget.Column == this.colContactName &&
cellWidget.Row.ChildIndex == 2)
{
if (textBox.Text == "Foo")
{
//e.Cancel = true;
cellWidget.AbandonEdit();
}
}
} |
I've tested what happens in this case and the SetCellValue event is not called in this case so the bound object never gets updated if "Foo" is entered and the cell just reverts to its previous value. _________________ Infralution Support |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Wed Feb 11, 2015 4:46 pm Post subject: |
|
|
ok, that is exactly what I was doing in the validating code.
I set a breakpoint to see what else was happening and realized the SetControlValue code I have was firing immidiately after the abandonedit.
In that SetControlValue code, I am setting the value of the editor textbox to some value, as I thought that is the whole point of using it.
What I am doing is showing abbreviated vals in the tree normally, then getting full values for the textbox at time of edit.
But it fires after abandonedit?
It seems that the code setting the textbox.text value is causing that control to continue its events, likely the valuechanged or lostfocus or whatever event the binding uses (I'd like to know which one).
Wait, I wonder if this is the issue where the update is firing twice, so the SetControlValue is not going after, but trying to start again for second run.
I'll look at that some more. _________________ James M |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Wed Feb 11, 2015 5:39 pm Post subject: |
|
|
I thought it was firing twice due to EditorValueChanged so I overrode in cellwidget:
Code: |
protected override void OnEditorValueChanged(object sender, EventArgs e) {
//do nothing
}
|
but that did not help.
I am not understanding something about the events here obviously. _________________ James M |
|
Back to top |
|
|
jmaeding
Joined: 11 Apr 2008 Posts: 67
|
Posted: Wed Feb 11, 2015 6:34 pm Post subject: |
|
|
I emailed in test project showing the behavior.
Its like the editor gets left in limbo after an abandonedit. _________________ James M |
|
Back to top |
|
|
|