- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Datagrid field validation
Joined: 25-Oct-2006
Can anybody help with this? I have a winforms datagrid bound to an entity collection. I have added an OnValidateFieldValue override function to the entity class. This function validates the entity fields and if invalid I use SetEntityFieldError and return false from the function. This seems to work very well and the datagrid ends up with a nice red error indicator in the appropriate cell. I have 2 problems: 1. because I return false from the validate function the value that the user typed in is lost - this means they see the old value (which was valid) and an error saying the value is invalid if I change the function to return true then the new invalid value is shown in the grid but the error indicator is not shown 2. how do I clear the error - it seems that the user would have to enter a new valid value in the cell - but what if the user wants to leave the old valid value
Just one other thing - I do not have an error provider defined on the form - does anyone know why the datagrid does not need an error provider to display errors?
Thanks John
LLBL v2.0 / selfservicing / vb / .net 1.1
Joined: 25-Oct-2006
Thanks for your comments Walaa but the type of applications I write really do require field validation at the time of input. A typical example being an order entry screen where the user enters a product code which has to be validated as the result impacts the rest of the screen immediately (eg. displays a price). I agree with your 2 cents in that validation on save is easier my customers won't go for it. Do you have any insight to the problem I described? Thanks
Joined: 17-Aug-2003
carmines wrote:
Can anybody help with this? I have a winforms datagrid bound to an entity collection. I have added an OnValidateFieldValue override function to the entity class. This function validates the entity fields and if invalid I use SetEntityFieldError and return false from the function. This seems to work very well and the datagrid ends up with a nice red error indicator in the appropriate cell. I have 2 problems: 1. because I return false from the validate function the value that the user typed in is lost - this means they see the old value (which was valid) and an error saying the value is invalid if I change the function to return true then the new invalid value is shown in the grid but the error indicator is not shown
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
- how do I clear the error - it seems that the user would have to enter a new valid value in the cell - but what if the user wants to leave the old valid value
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
Just one other thing - I do not have an error provider defined on the form - does anyone know why the datagrid does not need an error provider to display errors?
I've no idea, winforms works in mysterious ways unfortunately.
Joined: 28-Jul-2005
Otis wrote:
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
i.e. for let the user fixing a typo? When the user enters productcode '3281097' which is not valid, but s/he meaned '3281094', it is sometimes easier to correct than to retype. But ok, most times it's enough to display the wrong value in the errormessage (but then show the errors in a label outside the grid or so, and not only in the tooltip of the errorprovider).
Otis wrote:
- how do I clear the error - it seems that the user would have to enter a new valid value in the cell - but what if the user wants to leave the old valid value
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
That conflicts with no.1. But you can reset to the old value when the users presses ESC, which cancels 'the attempt to change/update'
Joined: 17-Aug-2003
BertS wrote:
Otis wrote:
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
i.e. for let the user fixing a typo? When the user enters productcode '3281097' which is not valid, but s/he meaned '3281094', it is sometimes easier to correct than to retype. But ok, most times it's enough to display the wrong value in the errormessage (but then show the errors in a label outside the grid or so, and not only in the tooltip of the errorprovider).
There's unfortunately no other way: the entity either can accept the value or reject it. What happens in a control displaying the value is up to the control displaying the value, the entity itself can't nor should take care of that.
Otis wrote:
- how do I clear the error - it seems that the user would have to enter a new valid value in the cell - but what if the user wants to leave the old valid value
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
That conflicts with no.1. But you can reset to the old value when the users presses ESC, which cancels 'the attempt to change/update'
What exactly does conflict with no.1 ?
Joined: 28-Jul-2005
Otis wrote:
BertS wrote:
Otis wrote:
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
i.e. for let the user fixing a typo? When the user enters productcode '3281097' which is not valid, but s/he meaned '3281094', it is sometimes easier to correct than to retype. But ok, most times it's enough to display the wrong value in the errormessage (but then show the errors in a label outside the grid or so, and not only in the tooltip of the errorprovider).
There's unfortunately no other way: the entity either can accept the value or reject it. What happens in a control displaying the value is up to the control displaying the value, the entity itself can't nor should take care of that.
Right, but you asked for a reason to keep the wrong value
Otis wrote:
Otis wrote:
- how do I clear the error - it seems that the user would have to enter a new valid value in the cell - but what if the user wants to leave the old valid value
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
That conflicts with no.1. But you can reset to the old value when the users presses ESC, which cancels 'the attempt to change/update'
What exactly does conflict with no.1 ?
If you keep the wrong value visible, the user should (imo) not be able to leave the field which resets the old value. That's very confusing. And besides that, most-time validation is done when leaving the field (because that's the moment the control updates its datasource). (or do I talk nonsense now?)
Joined: 25-Oct-2006
Otis wrote:
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
I would want the following behaviour - user enters value and leaves cell - field is validated - if value is false then show red error icon with tooltip containing description of the problem and the cell to contain the invalid value that the error description relates to. The way it works now is that the cell shows an error but the value in the cell is valid. In my validation routine I use SetEntityFieldError to assign the error description to the entity field but the grid only shows an error if I also return False. Could you explain why this happens - what causes the grid to show the error? Returning false from the validation must be doing something else internally to cause the grid to not show the error.
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
This sounds like a reasonable work around which I will try out. But could you tell me when focus moves to another cell how can I tell which entity the cell is related to?
I've no idea, winforms works in mysterious ways unfortunately.
I can't believe you have no idea about this as you seem to know lots about everything
Joined: 17-Aug-2003
carmines wrote:
Otis wrote:
Returning true also makes the code accept the value as a value for the field and signals the grid the value is accepted, which isn't correct. I'm not really sure why you want to have the invalid value in the field, as that value is invalid, so why keep it around?
I would want the following behaviour - user enters value and leaves cell - field is validated - if value is false then show red error icon with tooltip containing description of the problem and the cell to contain the invalid value that the error description relates to. The way it works now is that the cell shows an error but the value in the cell is valid. In my validation routine I use SetEntityFieldError to assign the error description to the entity field but the grid only shows an error if I also return False. Could you explain why this happens - what causes the grid to show the error? Returning false from the validation must be doing something else internally to cause the grid to not show the error.
the reason I think the grid rejects the error is that the set doesn't succeed, i.e.: the value isn't accepted as the value in the entity, plus the change notification event isn't raised, as the value isn't accepted.
Good point. You might want to clear all errors when the focus moves to another cell? (so bind some handler to the event raised when focus is moving away from a cell. ). Clearing an error is done by setting the error to an empty string.
This sounds like a reasonable work around which I will try out. But could you tell me when focus moves to another cell how can I tell which entity the cell is related to?
currentrow in the grid and hten the data element, cast it to the entity type.
I've no idea, winforms works in mysterious ways unfortunately.
I can't believe you have no idea about this as you seem to know lots about everything
heh well, with winforms, it's logical to some point and then it's simply random: sometimes this happens, in other situations something else happens. It's not predictable simple software and I really wonder why as on java for example people don't have this complexity as they use completely different patterns with layout managers and proper event delegation, deriving of controls from base controls and by adding your control using code to THAT class, instead of to the form the control is on.
Joined: 25-Oct-2006
Thanks for all the help so far but I am starting to get lost with this whole topic. My projects before LLBL used data adapters, datasets and databinding. I would bind a grid to a dataset/table and would use a data adapter to fill and save the dataset. The data adapter had a nice event called RowUpdated which received an event argument that contained any errors raised during the row update. If the row could not be saved back to the database because of a duplicate PK the RowUpdated event still fired and you could test for any errors and use e.Row.RowError to set an error string on the row. The datagrid back on the form would then show the error. I have to say this seemed like sensible behaviour and I am attempting to duplicate using LLBL - but I am failing miserably.
It looks like I am going to have to do the following: 1. catch the ORMQueryExecutionException raised by the SaveMulti 2. check if the inner exception is a SqlException 3. decode the SqlException.Number 4. now determine which entity caused the exception by decoding ORMQueryExecutionException.Parameters collection 5. now somehow I would need to SetEntityError on the problem entity - I guess I would need to loop through the collection looking for the problem entity and then set the error
This all seems very long winded and makes me think I am going about it the wrong way.
Am I missing an equivalent to the data adapters RowUpdated event - eg. an entitycollection EntityUpdated event? (not the AfterSave event because that only fires if the save was successful)
Would anyone like to comment on the above and perhaps make some alternative suggestions.
Thanks
Joined: 17-Aug-2003
carmines wrote:
Thanks for all the help so far but I am starting to get lost with this whole topic.
I'll try to clear things up a bit below.
My projects before LLBL used data adapters, datasets and databinding. I would bind a grid to a dataset/table and would use a data adapter to fill and save the dataset.
that's the same route you'll follow with LLBLGen Pro: you fetch an entity collection, you bind it to a grid, you save the entity collection.
The data adapter had a nice event called RowUpdated which received an event argument that contained any errors raised during the row update. If the row could not be saved back to the database because of a duplicate PK the RowUpdated event still fired and you could test for any errors and use e.Row.RowError to set an error string on the row. The datagrid back on the form would then show the error. I have to say this seemed like sensible behaviour and I am attempting to duplicate using LLBL - but I am failing miserably.
The problem is that having a collection of entities in memory can give all kinds of issues when you persist the changes. These changes have to be addressed in a handler for the exception.
It looks like I am going to have to do the following: 1. catch the ORMQueryExecutionException raised by the SaveMulti 2. check if the inner exception is a SqlException 3. decode the SqlException.Number 4. now determine which entity caused the exception by decoding ORMQueryExecutionException.Parameters collection 5. now somehow I would need to SetEntityError on the problem entity - I guess I would need to loop through the collection looking for the problem entity and then set the error This all seems very long winded and makes me think I am going about it the wrong way.
That's because you combine two things into one. As soon as the gui is over and the save process starts, the gui is nowhere in sight and shouldn't be in your mind when writing the code. When you save the collection and you run into an exception, you can use a FindMatches call to find the entity matching the parameters.
The core problem is that there's no unified way to determine if a UC voilation took place on all databases, or an FK violation for example: every db uses its own exception object and its own error number or numbers.
So the code which handles the exception and which you've to write is very db specific which is a bit of a pain, but unavoidable. I'd suggest to write a generic routine which accepts the entity collection, the ORMQueryExecutionException and returns teh entity at stake. In the routine you do the sqlexception examination.
What's to do after an exception happens is very application dependend. You want an error displayed in the gui, but perhaps your save code is in a service on another server, so the error should be serialized to you (remoting) or should be handled on the server by tossing out the entity which failed and the whole transaction should be re-tried.
Now, as the exception doesn't provide you with enough tools/info, I'll see if I can update the exception in v2.1, so more info is available to you, if applicable, like entityname, PK fields and pk field values. Including the entity object is an option but that could make the exception bigger than expected when the exception is serialized over a remoting wire because serialization is recursive.
Am I missing an equivalent to the data adapters RowUpdated event - eg. an entitycollection EntityUpdated event? (not the AfterSave event because that only fires if the save was successful)
Would anyone like to comment on the above and perhaps make some alternative suggestions.
A selfservicing entity has two methods; OnSave and OnSaveComplete which are called before and after the save action. So when a save of an entity was successful, the OnSaveComplete method is called, otherwise it's not. As you're using selfservicing, the entities do their own saving.
Joined: 25-Oct-2006
Thanks for the great response - again You have clarified things for me - I did have a little problem with FindMatches which I could not find on my collections. I found another thread in the forum which said this was only available to .NET 2.0 so I took the advice there and used an entityview to extract the offending entity.
Things are coming along nicely now - in no small part to the great support in the forum from Frans and also the rest of the members.
Totally off topic - but this is the only forum I have ever participated in where everyone seems to be 'of the same mind' - professional software developers with real life problems and intelligent questions - it is very refreshing
Joined: 17-Aug-2003
Thanks for the great feedback!
FindMatches was declared protected in older builds of the runtime library. It was made public on november 1st so all builds after that date have the method public.