Click here to Skip to main content
15,893,161 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am creating a program that will monitor the output of an external process. I have a timer setup that requests data from the external process every tick and the results are stored in my class. If any of the variables have changed from their previous state, I want to update the results in a database. I have setup a test program that simulates this but on a much smaller scale. For now, I am only checking 3 variables. I have setup a class that holds the results of the 3 variables and I have created properties for each variable. In each property, I call an event that gets triggered when the variable changes value.

I have then created an event handler that handles all 3 events. If one of the events is triggered, it updates my database. This all works fine except for one thing. If a single variable has changed, then it updates the variable in the database just fine. If 2 variables change at the same time, then the event fires twice which will update the database 2 times. If all 3 variables change at the same time, then it will update the database 3 times. I want to avoid overtaxing the database so I don’t want to update it more than once every timer tick no matter if one variable or all variables change. How can this best be handled? The only thing that I can think of is to create one variable and one property that contains all 3 results in either an array, list or something similar. Is this my best option or is there something else I am missing?

What I have tried:

Public Class ClassTimerVars

    Private _Feedrate As Integer
    Public Event FeedrateChanged()
    Private _Spindle As Integer
    Public Event SpindleChanged()
    Private _Rapid As Integer
    Public Event RapidChanged()
   


    Public Property Feedrate() As Integer
        Get
            Feedrate = _Feedrate
        End Get
        Set(ByVal value As Integer)
            If _Feedrate <> value Then
                _Feedrate = value
                RaiseEvent FeedrateChanged()
            End If
        End Set
    End Property

    Public Property Spindle() As Integer
        Get
            Spindle = _Spindle
        End Get
        Set(ByVal value As Integer)
            If _Spindle <> value Then
                _Spindle = value
                RaiseEvent SpindleChanged()
            End If
        End Set
    End Property

    Public Property Rapid() As Integer
        Get
            Rapid = _Rapid
        End Get
        Set(ByVal value As Integer)
            If _Rapid <> value Then
                _Rapid = value
                RaiseEvent RapidChanged()
            End If
        End Set
    End Property

End Class


Public Class Form1

    Private TimerTick As Long = 0
    Private WithEvents test As New ClassTimerVars
    Private EventsFired As Long = 0


    Private Sub OverrideChanged() Handles test.FeedrateChanged, test.SpindleChanged, test.RapidChanged

        Me.TxtFeedrate.Text = test.Feedrate
        Me.TxtSpindle.Text = test.Spindle
        Me.TxtRapid.Text = test.Rapid

        EventsFired += 1
        Me.LblEventsFired.Text = "Events Fired = " & EventsFired

        'Update the Database here

    End Sub

    Private Sub BtnStartTimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStartTimer.Click
        Timer1.Start()
    End Sub

    Private Sub BtnStopTimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStopTimer.Click
        Timer1.Stop()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        'Simulate Extracting data from an external process
        'Update the 3 variables on different intervals to see how many times the event is triggered

        TimerTick += 1

        'Update Feedrate in the class
        If TimerTick Mod 2 = 0 Then
            test.Feedrate = TimerTick
        End If

        If TimerTick Mod 4 = 0 Then
            test.Spindle = TimerTick
        End If

        If TimerTick Mod 8 = 0 Then
            test.Rapid = TimerTick
        End If


    End Sub
End Class
Posted
Updated 19-Feb-17 12:36pm
Comments
[no name] 17-Feb-17 14:30pm    
I think I would created an event args class that contained all three values.
Peter Leow 18-Feb-17 0:06am    
Create a class with the 3 variables as properties and implement Property Change Notification https://msdn.microsoft.com/en-us/library/ms743695(v=vs.110).aspx
theskiguy 20-Feb-17 13:23pm    
Peter:

I have never used Property Change Notification before. Can you tell me what is the advantage of using it versus the way I raise the events in my class?

As NotPolitcallyCorrect[^] mentioned in the comment to the question, you have to use EventArgs Class (System)[^]. At the bottom of related page you'll find an example.

[EDIT]
Here is a code sample which uses your class:
VB.NET
'methods and classes

Public Sub ctv_DataHasBeenAdded(sender As Object, e As ClassTimerVarsEventArgs)
	Console.WriteLine("New data has been added! Feedrate: {0}, Spindle: {1}, Rapid: {2}.", e.Feedrate, e.Spindle, e.Rapid)
	Dim c As ClassTimerVars = DirectCast(sender, ClassTimerVars)
	Console.WriteLine(c.ToString())
End Sub

Public Class ClassTimerVars
    Private _Feedrate As Integer
    Private _Spindle As Integer
    Private _Rapid As Integer

  	Public Sub New()
		'default constructor	
	End Sub
	
	Public Sub New(iFeedrate As Integer, iSpindle As Integer, iRapid As Integer)
    	_Feedrate = iFeedrate
    	_Spindle = iSpindle
    	_Rapid = iRapid
    End Sub

    Public Property Feedrate() As Integer
        Get
            Feedrate = _Feedrate
        End Get
        Set(ByVal value As Integer)
            _Feedrate = value
        End Set
    End Property

    Public Property Spindle() As Integer
        Get
            Spindle = _Spindle
        End Get
        Set(ByVal value As Integer)
            _Spindle = value
        End Set
    End Property

    Public Property Rapid() As Integer
        Get
            Rapid = _Rapid
        End Get
        Set(ByVal value As Integer)
            _Rapid = value
        End Set
    End Property

	Public Overrides Function ToString() As String
		Return String.Format("ClassTimerVars totals - Feedrate: {0}, Spindle: {1}, Rapid: {2}.", _Feedrate, _Spindle, _Rapid)
	End Function

    Public Sub AddData(ByVal iFeedrate As Integer, ByVal iSpindle As Integer, ByVal iRapid As Integer)
            _Feedrate += iFeedrate
            _Spindle += iSpindle
			_Rapid += iRapid
			Dim args As ClassTimerVarsEventArgs = New ClassTimerVarsEventArgs() _
				With {.Feedrate = iFeedrate, .Spindle = iSpindle, .Rapid = iRapid}
            OnDataAdded(args)
    End Sub

    Protected Overridable Sub OnDataAdded(e As ClassTimerVarsEventArgs)
        RaiseEvent DataHasBeenAdded(Me, e)
    End Sub

    Public Event DataHasBeenAdded As EventHandler(Of ClassTimerVarsEventArgs)

End Class

Public Class ClassTimerVarsEventArgs
	Inherits EventArgs

    Public Property Feedrate As Integer
    Public Property Spindle As Integer
    Public Property Rapid As Integer

End Class

Usage:
VB.NET
Sub Main
	'create new instance of ClassTimerVars with initial values
	Dim ctv As ClassTimerVars = New ClassTimerVars(1,5,10)
	AddHandler ctv.DataHasBeenAdded, AddressOf ctv_DataHasBeenAdded
	
	'dispplay initial value
	Console.WriteLine(ctv.ToString())
	'add data #1
	ctv.AddData(2,8,11)	
	'add data #2
	ctv.AddData(Nothing,3,21)
	'add data #3
	ctv.AddData(12,4,Nothing)
	
End Sub


Output:
ClassTimerVars totals - Feedrate: 1, Spindle: 5, Rapid: 10.
New data has been added! Feedrate: 2, Spindle: 8, Rapid: 11.
ClassTimerVars totals - Feedrate: 3, Spindle: 13, Rapid: 21.
New data has been added! Feedrate: 0, Spindle: 3, Rapid: 21.
ClassTimerVars totals - Feedrate: 3, Spindle: 16, Rapid: 42.
New data has been added! Feedrate: 12, Spindle: 4, Rapid: 0.
ClassTimerVars totals - Feedrate: 15, Spindle: 20, Rapid: 42.


Try!
 
Share this answer
 
v3
Comments
theskiguy 20-Feb-17 16:13pm    
Ok, please bear with me, I have never done this before so I need a little guidance. I copied the example you provided in the link and it works but I am having trouble figuring out how this example can be applied to my situation. There are 2 classes in the example, the counter class and the event args class. I assume I would need to change sub new in the counter class to accept the 3 vars I am tracking? Is this where I should also keep track of whether the variables change to work similar to my example above? Then what is the purpose of the event args class?
Maciej Los 20-Feb-17 16:54pm    
Check updated answer ;)
Graeme_Grant 20-Feb-17 16:56pm    
A generous answer. +5 :)
Maciej Los 20-Feb-17 16:57pm    
Thank you, Graeme.
Graeme_Grant 20-Feb-17 16:55pm    
Set a break point and step through his code. You will see how it works.
Polling variables with a Timer will miss events. This requires the classic Observer Pattern[^].
 
Share this answer
 
Comments
Maciej Los 20-Feb-17 16:58pm    
Good idea!
I would do something like described in the Comments :
you make one Event for your class which is fired every time a property changes.

If you want to build your own List (of ClassTimerVars) you override the Add-Method and redirect here the Event from your class the an own Event from your List (AddHandler).
If you remove an Item from those List (or dispose it) you should remove the Handler from the Class-Item to the List-Method.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900