VB Equivalent to Access Form BeforeUpdate Event?

  • Thread starter Thread starter Richard B. Lewis
  • Start date Start date
R

Richard B. Lewis

Hi,
We have two fields in just about every table for UpdatedBy and UpdatedOn
which we want to update if there are any changes to fields on the form. In
Access we typically use the Form_BeforeUpdate event to accomplish this.

How should we do this in vb.net? I've explored using the RowChangeEvent to
assign values to the dataset, but of course this triggers another RowChange
event!

Do I need to have events for each control on the form? A little help
needed!

Thanks.
 
You could use the "ColumnChanged" event of the DataTable. To add/remove an
event handler dynamically use the AddHandler/RemoveHandler keywords.

Private myDataTable As DataTable = Nothing

Private Sub SetupDataTable()
Me.myDataTable = CreateDataTable()
AddHandler Me.myDataTable.ColumnChanged, New
DataColumnChangeEventHandler(AddressOf DataTable_ColumnChanged)
End Sub

Private Function CreateDataTable() As DataTable
Dim dt As New DataTable("MyTable")
dt.Columns.Add("StringColumn", Type.GetType("System.String"))
dt.Columns.Add("IntegerColumn", Type.GetType("System.Int32"))
dt.Columns.Add("UpdatedBy", Type.GetType("System.String"))
dt.Columns.Add("UpdatedOn", Type.GetType("System.DateTime"))
Return dt
End Function

Private Sub DataTable_ColumnChanged(ByVal sender As Object, ByVal e As
DataColumnChangeEventArgs)
BeginDataTableUpdate()
e.Row.Item("UpdatedBy") = "Name"
e.Row.Item("UpdatedOn") = DateTime.Now
EndDataTableUpdate()
End Sub

Private Sub BeginDataTableUpdate()
RemoveHandler Me.myDataTable.ColumnChanged, New
DataColumnChangeEventHandler(AddressOf DataTable_ColumnChanged)
End Sub

Private Sub EndDataTableUpdate()
AddHandler Me.myDataTable.ColumnChanged, New
DataColumnChangeEventHandler(AddressOf DataTable_ColumnChanged)
End Sub
Do I need to have events for each control on the form?
Do you mean do you need to have separate event handlers for each similar
control on the form? If so then No. You can add the same event handler to
multiple controls/objects as long as these events require the same delegate
signature. So, for example, if you have multiple DataTable's that have the
"UpdatedBy" and "UpdatedOn" columns then these DataTable's can use the same
ColumnChanged event handler to perform all updating.
 
Tim said:
Private Sub DataTable_ColumnChanged(ByVal sender As Object, ByVal e As
DataColumnChangeEventArgs)
BeginDataTableUpdate()
e.Row.Item("UpdatedBy") = "Name"
e.Row.Item("UpdatedOn") = DateTime.Now
EndDataTableUpdate()
End Sub

Private Sub BeginDataTableUpdate()
RemoveHandler Me.myDataTable.ColumnChanged, New
DataColumnChangeEventHandler(AddressOf DataTable_ColumnChanged)
End Sub

Private Sub EndDataTableUpdate()
AddHandler Me.myDataTable.ColumnChanged, New
DataColumnChangeEventHandler(AddressOf DataTable_ColumnChanged)
End Sub

This seems to be a lot of overhead (adding and removing a delegate every
time a column is changed). Wouldn't it make more sense to do this:

Private Sub DataTable_ColumnChanged(ByVal sender As Object, ByVal e As
DataColumnChangeEventArgs)
Static Recursing as Boolean

If Recursing Then Exit Sub

Recursing = True
e.Row.Item("UpdatedBy") = "Name"
e.Row.Item("UpdatedOn") = DateTime.Now
Recursing = False
End Sub
 
You could use a boolean variable as an indication flag, sure. I was just
trying to show the basic understanding of hooking up/removing an event
handler dynamically as well as allowing the "UpdatedBy" and "UpdatedOn"
fields to be updated without the ColumnChanged method being called over and
over - even if it's only checking a boolen flag when it gets called.
Sometimes it's nice to remove delegates through the debug process as it can
get kind of hard to follow when you're trying to walk the debugger
step-by-step and it keeps jumping back into the same method, hitting a
boolean, and then jumping out again. By removing the delegates the method
only gets called once instead of three times as it would with the boolean
flag.
 
Thanks for the examples!

I see your point, but which is the best practice - using the boolean (and
consuming cycles) or adding and removing a delegate (adding and removing
resources - and more code)?

BTW, in our applications the event shouldn't fire when adding a record, so
the delegate needs to be removed during this process, then added back in
after the record has been added.

-R
 
Richard said:
I see your point, but which is the best practice - using the boolean (and
consuming cycles) or adding and removing a delegate (adding and removing
resources - and more code)?

Adding/removing the delegate actually involves running code inside the
type providing the event, so that will certainly take more time than
setting/clearing a boolean.
BTW, in our applications the event shouldn't fire when adding a record, so
the delegate needs to be removed during this process, then added back in
after the record has been added.

Then I would suggest another approach; if you are using DataAdapters to
update/insert the changes from the DataTable back to your original
source, the use the events exposed by the DataAdapter instead of the
DataTable. That way you'll only get one event for an added row, one
event for a changed row, etc. You also don't have to worry about
updating the timestamp columns for changes the user made but then later
cancelled.
 
Adding/removing the delegate actually involves running code inside the
type providing the event, so that will certainly take more time than
setting/clearing a boolean.
Keep in mind that if the method gets called multiple times, unnecessarily,
then not only do you have overhead in the method actually being executed
(code being run) but the reference to the "sender" must be passed as a
parameter and a reference to the DataColumnChangeEventArgs object will need
to be passed too as well as a memory allocation required to make room on the
heap for the DataColumnChangeEventArgs object data itself. So depending on
the situation adding/removing a delegate could very well be faster, and more
resource friendly, then the method of a supposed simple boolean check. Now I
haven't actually run a test to see how these two methods compare right down
to the tick count but you have to consider that there is more going on here
then just "setting/clearing a boolean value". But the truth is that in the
application that I'm currently working on I'm using both methods. If I know
that the amount of times that the method will be getting called is minimal,
then I will use a boolean. But if the possibility exists that the method may
get called many times then I will unhook from the event and then hook in
again after the work is done. This is something that has to be seen by
someone who is looking at the entire scope of what, at least, a certain
section of the application is doing. It's not something that you can say
just by answering a simple newsgroup question. So the decision has to be
made as to how many times this method would get called and will unhooking
and rehooking be a better or worse solution in this situation. For every
item that needs to be updated in the ColumnChanged event you need to push
parameters onto the stack and also allocate memory that is not even going to
be accessed since the method will get called again only to outright fail
when the boolean is checked. Also a well known way of adding a new row is to
use the NewRow method of the DataTable and then proceed to fill in the
columns one at a time with information. This will call the ColumnChanged
event for every column of data that is set during this process. Then the
event handler will be called 3 times when in this situation, since you are
just setting up new row data, this event does not need to be called at all.
At 3 times the number of unneccessary memory allocations per column of data
changed that can add up to a whole lot more time taken then just unhooking
from the event and then hooking back up when done.

Dim newRow As DataRow = Me.myDataTable.NewRow
newRow.Item("StringColumn") = "String" ' *
newRow.Item("IntegerColumn") = 0 ' *
Me.myDataTable.Rows.Add(newRow)

* ColumnChanged event called 3 x times (once for the change here and then
once for each "Update" change in the ColumnChanged event).

Now wrap it with the "BeginDataTableUpdate()" and "EndDataTableUpdate()"
calls and you have the overhead of removing and then adding the delegate but
you do not call the event handler 6 times for just two columns. And this
just gets worse the more columns you have. So in a situation where you are
reentering and executing code in a method just to check a boolean can in
fact allocate more memory and take more time depending on how many times the
method is getting called. I did it this way not only for the reasons I
mentioned previously but for the fact that this is a way to essentially
ensure that the event handler is not getting called at all. But the original
poster will need to look at this situation and decide which solution best
fits the given problem. But, as I mentioned earlier, using both methods
might be the way to go.
 
Thanks guys,

You've taken my level of understanding on this subject "up a notch". I have
decided to use both solutions, depending on the situation.

-Rick Lewis
 
Back
Top