Hello,
I am currently experimenting with databinding.
Now there is one problem I cannot seem to fix.
I have a DataSet with a DataTable. In this DataTable I have a Column which does not allow null values.
Now I have a BindingSource which has the DataSet as its DataSource and the DataTable as its DataMember and a BindingNavigator which has the BindingSource as its BindingSource property. All goes well until I leave the non-null column empty and try to navigate to another row in the DataTable or add a new row. It makes the application crash altogether... If I just call the DataSource.EndEdit method I only get a NoNullAllowedException.
The fields of my DataTable are shown in TextBoxes, not DataGrids.
I have checked all the DataSource events, properties, subs and functions, but I cannot find any method that allows me to check if all values are OK before I update/add new row/ navigate to another row or call the DataSource.EndEdit method.
Any suggestions on overcoming this? Thanks. Amongst all the tags you applied to your question you forgot to include one for the type of Database (SQL Server, Access, MySQL, ????).
Still, one suggestion. If your database allows default values for columns setting that to 0 or any sensible number for your scenario might resolve the problem. If not, then having that TextBox initialized to a value of 0 (or whatever) might achieve the same result.
If neither of those suggestions suit, or as an alternative, consider handling the Validating [ ^ ] event.
I'm no fan of 'default values'. Either you enter a value or you don't. And if you don't, you just can't continue. The problem isn't in SQL. My DataTable is trying to add rows, which it can't do because of no-null contraints. Only if one or more rows are added to my DataTable the SQL Server comes into play, but by that time I hope to have valid DataRows :)
What I do now is the following:

<pre>
Private Function ValidateValues() As Boolean
Dim view As DataRowView
Dim row As DataRow
Dim hasEmptyValues As Boolean

Me.Validate()

view = CType(bindingSource.Current, DataRowView)

row = view.Row

If row("Name").ToString = String.Empty Then
errorProvider.SetError(txtName, "Please specify a name.")
hasEmptyValues = True
Else
errorProvider.SetError(txtName, String.Empty)
End If

If row("Type").ToString = String.Empty Then
errorProvider.SetError(cbxType, "Please specify a valid type.")
hasEmptyValues = True
Else
errorProvider.SetError(cbxType, String.Empty)
End If

Return Not hasEmptyValues
End Function
</pre>

It works, but I have to check every column in my current DataSource row. I could also use the Validating event for each control or datagrid cell or whatever.
But is there no way to check every value in my current DataSource row directly? It knows which columns cannot be null and it knows all the values, so it should know if the current row is valid or not. I tried the row.HasErrors, but it returned no errors and crashed my application after that because of NULL values. I tried handling the DataSource events (it doesn't have a validating event), but it all comes down to the same thing, which is checking every value one by one. I don't specifically have a problem with that as long as I know there really is no other way...
Well, there is a DataGridView.RowValidating (http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.rowvalidating.aspx) event that you might use. The example on that page shows using it together with the Cell.ErrorText property. If that would work any better, or how it would affect performance I have no idea as I have never used it.
But I'm not using a datagridview. I am using a dataset with datatables and a bindingsource. Now, as I understand it, a bindingsource holds one datatable row, being the current one that is being edited (if your binding is correct of course). Now I want to insert some (non-default) values in a row when the row is created (these fields are not even on the user interface) and I want to validate other values as soon as they are entered by the user.
My biggest problem is that I do not know how to directly get the current bindingsource row (other than CTypeing it) and I do not know how to get or set the values of the items within the row. I have looked at various events, but no event seems to give me anything useful, for both bindingsource and datatable events...
I cannot remember if I have given you a link to this article before so have a look at http://www.codeproject.com/KB/database/databinding_tutorial.aspx. In particular look at the part about the CurrentItemChanged event as I think that it will help in this situation.

Internally BindingSource maintains an IBindingList of DataRowView objects so you should be able to use Dim drv As DataRowView = CType(myBindingSource.Item(2), DataRowView) or CType(myBindingSource.Current, DataRowView). You can then access the columns from the DataRowView.
I read the article at work today! This actually cost me my day off because now I '...am the only one who knows about binding and I have to finish my work before the deadline on tuesday.' That's an actual quote from my boss... I recommended the article to all my colleague's too though, so maybe I won't be the only one anymore soon :)
That said, this article gave me new insights which helped me to fix my problem ;)
Many thanks! :D
  • Read the question carefully.
  • Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  • If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  • Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question. Let's work to help developers, not make them feel stupid.
  •