newyuppie
asked on
problem with binding object parse and format events
vb2005
hi, im having some problems handling the format and parse events of some textboxes.
this question i asked has the priors (https://www.experts-exchange.com/questions/21891973/One-Way-Data-Binding.html).
basically, i have a form with a bunch of textboxes. some of them are bound to the dataset, others aren't and are readonly and perform calculations based on the rest of the textboxes.
i now needed to send this computed readonly values back to the database (for sake of reporting), so the person whom i accepted the answer from in the linked question suggested i create a bindingobject for these readonly textboxes and handle its format and parse events.
so i did, created new columns for these values on the database, reconfigured the tableadapter, and created binding object which handle the format event, so that the value of the database gets replaced by the computed value when i fill the datatable (the end user never sees the database content, but a similar result computed by a defined function).
basically, the problem i am having now is that when i call tableadapter update command to send all the info back to the database, after its done all my readonly textboxes (the ones which i handled the format event) erase their values and place 0 instead (zero because their computed value are always arithmetic functions of the other textboxes).
why do you reckon this is happening? is it that after the update the format event of the bindings are not being called?
hi, im having some problems handling the format and parse events of some textboxes.
this question i asked has the priors (https://www.experts-exchange.com/questions/21891973/One-Way-Data-Binding.html).
basically, i have a form with a bunch of textboxes. some of them are bound to the dataset, others aren't and are readonly and perform calculations based on the rest of the textboxes.
i now needed to send this computed readonly values back to the database (for sake of reporting), so the person whom i accepted the answer from in the linked question suggested i create a bindingobject for these readonly textboxes and handle its format and parse events.
so i did, created new columns for these values on the database, reconfigured the tableadapter, and created binding object which handle the format event, so that the value of the database gets replaced by the computed value when i fill the datatable (the end user never sees the database content, but a similar result computed by a defined function).
basically, the problem i am having now is that when i call tableadapter update command to send all the info back to the database, after its done all my readonly textboxes (the ones which i handled the format event) erase their values and place 0 instead (zero because their computed value are always arithmetic functions of the other textboxes).
why do you reckon this is happening? is it that after the update the format event of the bindings are not being called?
ASKER
Hi Roger, thanks for the answer. I hope i can clarify a bit:
for the sake of simplicity (i have over 50 textboxes in the form) lets assume there are 2 textboxes which are bound in the usual way to a dataset. These textboxes are read/write enabled, and user is supposed to enter in them values. of course when i update the datatable these 2 values also get stored (they are bound). so when i load the form these 3 textboxes pull the values from the datatable, but are still subject to user input.
Assume the 3rd textbox calculates de SUM of the other 2 textboxes. this 3rd textbox is read/only and user cannot enter values. it's .text property is updated automatically handling the _textchanged event of the other 2 textboxes to perform the calculation and display the result.
this was my scenario and everything worked fine. now, i need to add one more column to the dataset, to store the sum of the first 2 textboxes. so i need to calculate it via my function, and then when i .endedit the bindingsource it has to pass this sum to the database for storage. one more thing is that when i open the form and load the dataset, i want to display as usual the first 2 textboxes (reading the values stored), but the 3rd textbox i dont want to read the stored sum, but calculate it again. in sum, this 3rd texbox must be readonly to the user, and "write-only" to the database.
so in the code i provided on the link to, anyoneis gave me an example of code to handle format event of a new binding of the textbox. i made some modifications and here's what i have so far. i show code for only one binding (i have over 10 now).
assume the calculation for the 3rd readonly textbox comes from this sub:
Private Sub CalculateCapEnd()
Dim TasaAnual As Double
Dim TasaMensual As Double
Dim Plazo As Integer
Dim SaldoNeto, IngresoNeto, GastoMicro, GastoFamiliar As Double
Double.TryParse(Me.TasaAnu alTextBox. Text, TasaAnual)
Integer.TryParse(Me.Plazo_ Solicitado __en_meses _TextBox.T ext, Plazo)
Double.TryParse(Me.Ingreso NetoTextBo x.Text, IngresoNeto)
Double.TryParse(Me.GastoMi croTotalTe xtBox.Text , GastoMicro)
Double.TryParse(Me.GastoTo talFamilia rTextBox.T ext, GastoFamiliar)
SaldoNeto = IngresoNeto - GastoMicro - GastoFamiliar
TasaMensual = TasaEfectivaMensual(TasaAn ual)
Me.CapEndTextBox.Text = CapEnd(TasaMensual, Plazo, SaldoNeto).ToString("F")
End Sub
the previous sub gets called whenever user makes changes to the text on the first 2 texboxes (called in the _textchanged event handler)
i also added this code to bind the 3rd textbox (readonly textbox):
Private Sub Bind3rdTextbox()
Dim _CapEnd As New Binding("Text", Me.SolicitantesBindingSour ce, "CapEnd", True)
Me.CapEndTextBox.DataBindi ngs.Add(_C apEnd)
AddHandler _CapEnd.Format, AddressOf WriteCapEnd
End Sub
Private Sub WriteCapEnd(ByVal sender As System.Object, ByVal e As ConvertEventArgs)
' We want to ignore the current value, and instead compute it
Try
e.Value = CE.ToString
Catch ex As Exception
e.Value = Nothing
End Try
End Sub
Private Function CE() As Double
CalculateCapEnd()
Dim CapEnd As Double
Double.TryParse(Me.CapEndT extBox.Tex t, CapEnd)
Return CapEnd
End Function
So, basically, the 3rd textbox has the _format event handled by the sub WriteCapEnd, which in turns uses the result of function CE which only purpose is to run sub CalculateCapEnd (which will in turn set the 3rd textbox .text property to the corresponding correct value) and return that value to the format event.
behaviour:
the real behaviour of all these subs is as following: i open the form and data gets loaded into textbox 1 and 2, and texbox 3 calculates its value (because i handle all of this in the Load event, i dont think its because of the _format event since this behaviour happened before i set to do this).
if i call bindingsource.endedit and tableadapter.update methods (save the data back to the form), what happens is that the value on the 3rd textbox is not saved in the database (1st and 2nd are). also, 3rd texbox .text resets to 0 no matter what value it was showing before the update was called.
if i close and reopen the form, i get all textboxes filled correctly again.
im sorry for the extension of all of this, i hope i could clarify the issue a bit.
for the sake of simplicity (i have over 50 textboxes in the form) lets assume there are 2 textboxes which are bound in the usual way to a dataset. These textboxes are read/write enabled, and user is supposed to enter in them values. of course when i update the datatable these 2 values also get stored (they are bound). so when i load the form these 3 textboxes pull the values from the datatable, but are still subject to user input.
Assume the 3rd textbox calculates de SUM of the other 2 textboxes. this 3rd textbox is read/only and user cannot enter values. it's .text property is updated automatically handling the _textchanged event of the other 2 textboxes to perform the calculation and display the result.
this was my scenario and everything worked fine. now, i need to add one more column to the dataset, to store the sum of the first 2 textboxes. so i need to calculate it via my function, and then when i .endedit the bindingsource it has to pass this sum to the database for storage. one more thing is that when i open the form and load the dataset, i want to display as usual the first 2 textboxes (reading the values stored), but the 3rd textbox i dont want to read the stored sum, but calculate it again. in sum, this 3rd texbox must be readonly to the user, and "write-only" to the database.
so in the code i provided on the link to, anyoneis gave me an example of code to handle format event of a new binding of the textbox. i made some modifications and here's what i have so far. i show code for only one binding (i have over 10 now).
assume the calculation for the 3rd readonly textbox comes from this sub:
Private Sub CalculateCapEnd()
Dim TasaAnual As Double
Dim TasaMensual As Double
Dim Plazo As Integer
Dim SaldoNeto, IngresoNeto, GastoMicro, GastoFamiliar As Double
Double.TryParse(Me.TasaAnu
Integer.TryParse(Me.Plazo_
Double.TryParse(Me.Ingreso
Double.TryParse(Me.GastoMi
Double.TryParse(Me.GastoTo
SaldoNeto = IngresoNeto - GastoMicro - GastoFamiliar
TasaMensual = TasaEfectivaMensual(TasaAn
Me.CapEndTextBox.Text = CapEnd(TasaMensual, Plazo, SaldoNeto).ToString("F")
End Sub
the previous sub gets called whenever user makes changes to the text on the first 2 texboxes (called in the _textchanged event handler)
i also added this code to bind the 3rd textbox (readonly textbox):
Private Sub Bind3rdTextbox()
Dim _CapEnd As New Binding("Text", Me.SolicitantesBindingSour
Me.CapEndTextBox.DataBindi
AddHandler _CapEnd.Format, AddressOf WriteCapEnd
End Sub
Private Sub WriteCapEnd(ByVal sender As System.Object, ByVal e As ConvertEventArgs)
' We want to ignore the current value, and instead compute it
Try
e.Value = CE.ToString
Catch ex As Exception
e.Value = Nothing
End Try
End Sub
Private Function CE() As Double
CalculateCapEnd()
Dim CapEnd As Double
Double.TryParse(Me.CapEndT
Return CapEnd
End Function
So, basically, the 3rd textbox has the _format event handled by the sub WriteCapEnd, which in turns uses the result of function CE which only purpose is to run sub CalculateCapEnd (which will in turn set the 3rd textbox .text property to the corresponding correct value) and return that value to the format event.
behaviour:
the real behaviour of all these subs is as following: i open the form and data gets loaded into textbox 1 and 2, and texbox 3 calculates its value (because i handle all of this in the Load event, i dont think its because of the _format event since this behaviour happened before i set to do this).
if i call bindingsource.endedit and tableadapter.update methods (save the data back to the form), what happens is that the value on the 3rd textbox is not saved in the database (1st and 2nd are). also, 3rd texbox .text resets to 0 no matter what value it was showing before the update was called.
if i close and reopen the form, i get all textboxes filled correctly again.
im sorry for the extension of all of this, i hope i could clarify the issue a bit.
I've not seen a Binding's .Format event used like this before. It is normally used, as it says, to FORMAT the datatable's data for display purposes rather than to CREATE data for it. That, however, is by the by. I can see nothing wrong in principle with this approach although it is new to me. Where it falls down in this case, however, is that it has no matching .Parse. Have a look at this
http://msdn2.microsoft.com/en-us/library/system.windows.forms.binding.format.aspx
The code provided by anyoneis did say that it was providing a one-way binding, and the Console output on button1 illustrated that the newly calculated value in textbox3 did not get back to the datatable. That being so, it would not get back to the database on an update.
With a matching .Parse on the lines explained in the link above such a calculated value would get back to the datatable. So, if anyoneis' code was amplified by
AddHandler sumBinding.Parse, AddressOf SaveSum
as well as
AddHandler sumBinding.Format, AddressOf FormatSum
and
Private Sub SaveSum(ByVal sender As System.Object, ByVal e As ConvertEventArgs)
e.Value = ComputeSum()
End Sub
it would, in theory, achieve what you want. Unfortunately for your scenario that .Parse event is (so far as I know) only triggered if the user has altered the data in the control. Here, as the textbox is readonly, that just can't happen.
So far, I've only addressed part of the problem - "the value on the 3rd textbox is not saved in the database" - but I think getting that right first is crucial. Until the data is right, display issues are peripheral.
Looking at it from a data angle, rather than a display angle, can I ask why you are calculating figures in your app to pass back to a database when, I think, all the elements necessary for that calculation are in your database anyway? What is your database? Does it not have the ability to do calculations of this sort itself?
If you want to continue looking at this as a display problem, we may be able to get round the difficulty you are currently facing. But my inclination would be to treat the calculation as something to be done at the database end and/or at the application end rather than trying to pass the result between the two. x + y + z = the same whichever end it is done at. And if you can do that, all these .Format and .Parse issues will just disappear.
Roger
http://msdn2.microsoft.com/en-us/library/system.windows.forms.binding.format.aspx
The code provided by anyoneis did say that it was providing a one-way binding, and the Console output on button1 illustrated that the newly calculated value in textbox3 did not get back to the datatable. That being so, it would not get back to the database on an update.
With a matching .Parse on the lines explained in the link above such a calculated value would get back to the datatable. So, if anyoneis' code was amplified by
AddHandler sumBinding.Parse, AddressOf SaveSum
as well as
AddHandler sumBinding.Format, AddressOf FormatSum
and
Private Sub SaveSum(ByVal sender As System.Object, ByVal e As ConvertEventArgs)
e.Value = ComputeSum()
End Sub
it would, in theory, achieve what you want. Unfortunately for your scenario that .Parse event is (so far as I know) only triggered if the user has altered the data in the control. Here, as the textbox is readonly, that just can't happen.
So far, I've only addressed part of the problem - "the value on the 3rd textbox is not saved in the database" - but I think getting that right first is crucial. Until the data is right, display issues are peripheral.
Looking at it from a data angle, rather than a display angle, can I ask why you are calculating figures in your app to pass back to a database when, I think, all the elements necessary for that calculation are in your database anyway? What is your database? Does it not have the ability to do calculations of this sort itself?
If you want to continue looking at this as a display problem, we may be able to get round the difficulty you are currently facing. But my inclination would be to treat the calculation as something to be done at the database end and/or at the application end rather than trying to pass the result between the two. x + y + z = the same whichever end it is done at. And if you can do that, all these .Format and .Parse issues will just disappear.
Roger
ASKER
thanks for your clarifications and comments. i can now see why you say that .Parse and .Format events are meant to manage the display of the value.
i see what you mean by saying that maybe i could do the math on the database side, but the calculation of this 3rd textbox (and of the other calculated textboxes i have on the form) are not that simple. i have oversimplified the example of calculation because i thought i wasnt relevant, but actually they have to do with calculating present values, exponentiated values, etc (financial calcs in general).
in that sense, what alternative method do you recommend to achieve what i want?
thanks
i see what you mean by saying that maybe i could do the math on the database side, but the calculation of this 3rd textbox (and of the other calculated textboxes i have on the form) are not that simple. i have oversimplified the example of calculation because i thought i wasnt relevant, but actually they have to do with calculating present values, exponentiated values, etc (financial calcs in general).
in that sense, what alternative method do you recommend to achieve what i want?
thanks
ASKER
one thing that i should mention now that i have told you that calculations are financial, the simplified situation is this:
say 1st textbox is a future value. say 2nd textbox is an interest rate, and say 3rd textbox is the present value of textbox 1, and calculation takes into account both textboxes values (future value and interest rate).
Now, 1st texbox is bound the usual way and stores the value on database field. 2nd texbox is the interes rate, and assume for a second that this rate is pulled from the bank's database and is subject to change daily.
first time i create the form, user will input future value on tb1, interest rate will be pulled on tb2, and i will give the calculation on tb3. now suppose i want to store this on my database, all 3 values because i will do an automated report later and all textboxes' values have to appear. now say a week later somebody opens that form to make a change on the future value, when they open it, the future value will be the one stored a week before pulled from the database. the interest rate will be pulled from the mainframe, and could be different than the one a week ago. so, the calculation on tb3 can't be the one that was stored on the main database, because interest rates have changed and i wouldnt be reflecting that. so, tb3 has to be calculated always on the spot, and when user ends editing, the final value of tb3 has to go into database for reporting issues.
is it a bit clearer this way? thanks
say 1st textbox is a future value. say 2nd textbox is an interest rate, and say 3rd textbox is the present value of textbox 1, and calculation takes into account both textboxes values (future value and interest rate).
Now, 1st texbox is bound the usual way and stores the value on database field. 2nd texbox is the interes rate, and assume for a second that this rate is pulled from the bank's database and is subject to change daily.
first time i create the form, user will input future value on tb1, interest rate will be pulled on tb2, and i will give the calculation on tb3. now suppose i want to store this on my database, all 3 values because i will do an automated report later and all textboxes' values have to appear. now say a week later somebody opens that form to make a change on the future value, when they open it, the future value will be the one stored a week before pulled from the database. the interest rate will be pulled from the mainframe, and could be different than the one a week ago. so, the calculation on tb3 can't be the one that was stored on the main database, because interest rates have changed and i wouldnt be reflecting that. so, tb3 has to be calculated always on the spot, and when user ends editing, the final value of tb3 has to go into database for reporting issues.
is it a bit clearer this way? thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ok i have adapter your comments and suggestions to my code, and removed the _Format and _Parse event handlers since they, like you said, are mainly for display issues.
i have removed the binding for tb3, and wrote code in the _PositionChanged event of the BindingSource, using the BindingSource.Current("Col umnName") to assign the proper values to the datatable column so they could be persisted on call of the .EndEdit.
thank you very much for your help its been a life saver! (this approach i took here is basically the same one i took on my other related question, which you have also assisted me! here's the link just in case https://www.experts-exchange.com/questions/21902555/Manually-editing-content-of-datatable-row.html)
thanks again
P
i have removed the binding for tb3, and wrote code in the _PositionChanged event of the BindingSource, using the BindingSource.Current("Col
thank you very much for your help its been a life saver! (this approach i took here is basically the same one i took on my other related question, which you have also assisted me! here's the link just in case https://www.experts-exchange.com/questions/21902555/Manually-editing-content-of-datatable-row.html)
thanks again
P
Roger