CallBacks, or what do I really need?
Public ClassxxForm
Public zPanel as New xxPanel
End Class
Public ClassxxPanel
Public zLabel as New xxLabel(Me)
Public Property Ticker() As Long
End Class
Public ClassxxLabel
Private zParentPanel as xxPanel(<constructed in New(xxPanel) sub)
Me.Text = zParentPanel.Ticker.toString
End Class
Above pseudo-code: the xxForm creates an xxPanel, and the xxPanel creates an xxLabel.
How can I bind an xxLabel.Text output to its parent xxPanel's Ticker returnvalue so that the label continuously reflects the changing returnvalue, in a threadsafe manner?
After looking into databinding, events and multithreading, I now think I need to set a delegate in xxPanel that points to a function in xxPanel which returns the [TickerValue] from the Ticker property, and then the xxLabel needs to invoke the xxPanel's delegate to fetch the TickerValue.
I think this is what a 'callback' is, but I've never used it, so if someone could show me the way with my xxPanel/xxLabel example, I would very much appreciate it.
I've gotten as far as the following but I'm obviously not 'getting it' yet as I'm still seeing IllegalCrossThread errors, so what am I doing wrong?
Public ClassxxForm
Public zPanel as New xxPanel
End Class
Public ClassxxPanel
Delegate Function fName() As [Long]
Public zDelegate as fName(<constructed toNew fName(AddressOf delFunction))
Public zLabel as New xxLabel(Me)
Public Function delFunction() As [Long](<returns Me.Ticker)
Public Property Ticker() As Long
End Class
Public ClassxxLabel
Public zParentPanel as xxPanel(<constructed in New(xxPanel) sub)
Me.Text =zParentPanel.Invoke(zParentPanel.zDelegate).toString
End Class
[4929 byte] By [
nogChoco] at [2007-12-28]
Hello!
About your request
Public Class xxForm
Public zPanel as New xxPanel
End Class
Public Class xxPanel
Public zLabel as New xxLabel(Me)
Public Property Ticker() As Long
End Class
Public Class xxLabel
Private zParentPanel as xxPanel (<constructed in New(xxPanel) sub)
Me.Text = zParentPanel.Ticker.toString
End Class
you can easily use the idea of events for example
if i have a user control that uses n-Label
the question is how can i handle the event click for example
the answer is by using The AddHandler
and here in ur clase xxPanel , u can use this
Public Class xxPanel
Public zLabel As xxLabel
Public Sub New()
zLabel=New xxLabel(...)
AddHandler zLabel.TextChanged, AddressOf zLabel_TextChanged
End Sub
Private Sub zLabel_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles zLabel.TextChanged
' here goes your code to control the changes in ur zLabel control
End Sub
End Class
Hi
Is it possible that you can refactor your design a little as follows.
If the panel creates the label in its constructor, then I fail to see why it makes sense to encapsulate the binding to the parent Ticker method within the label class.
Perhaps it would be simpler to have the parent update the labels text each time it changes its property value?
If you cannot take this approach, please leave a little more information as to why you must bind from the label to the panel, and I'll put together a data binding example for you
Richard
Public Class xxPanel
Inherits ContainerControl
Private ReadOnly mLabel As xxLabel
Private mTimer As Timer
Public Sub New()
MyBase.New()
Me.mLabel = New xxLabel : MyBase.Controls.Add(Me.mLabel)
Me.mTimer = New Windows.Forms.Timer()
Me.mTimer.Interval = 1000 : Me.mTimer.Start()
AddHandler Me.mTimer.Tick, New EventHandler(AddressOf Me.TimerTick)
End Sub
Private Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs)Static tickCount As LongtickCount += 1
Me.mLabel.Text = tickCount.ToStringEnd SubEnd
Class
Thanks for your replies so far - it's really appreciated!

I'm using VB.NET to create a little app that shows the current networkspeeds (or whatever network statistic I point it at) and displays it as a nice looking historycurve (=customized panel that does the calculations) with extra labels that show the maximum/average/speeds as they change. The picture in link below has a running example of my app.
The reason I made the xxLabels seperate objects as opposed to incorporating them in the xxPanel's paintcode, is because this allows me to easily resize/reposition them manually within their parent xxPanel on runtime. (and I'd also like to make my app available as opensource on SourceForge afterwards,
which is why I'd like it to have as much 'proper' object coding as possible).
http://img77.imageshack.us/my.php?image=netspeedexampleqi8.jpg
The xxPanel with the speedhistorycurve is filling the form, and the xxLabel is in the upper-left corner (orange). The form's text is showing the maxspeed which is a property of xxPanel, and the xxLabel should be showing that too (currently using databindings but it doesn't update).
@ Monah84:The eventhandlers aren't really a problem, I think,it's the setting of xxLabel.Text = xxParentPanel.Ticker within the eventhandling subs that is causing
the illegalcrossthread errors.
@ Dick Donny:
I tried your code, and the thing that makes it work, is the fact that you're using a Windows.Forms.Timer -- I'm using a System.Timers.Timer -- so I'm assuming that the Forms.TimerTicks are synchronizing both objects somehow, but I don't know whether this may still lead to crossthreading errors in certain situations. I'll try switching to a Forms.Timer in both xxPanel and xxLabel and see what happens.
I tried databindings ( xxLabel.Text = xxLabel.databindings.add("Text", xxParentPanel, "Ticker") ) with INotifyPropertyChanged implemented in the xxPanel, but the xxLabel only updates once when the xxLabel is created - which I frankly don't understand why it wouldn't persist. Extra examples are always welcome ;)@ Geert Verhoeven: ( toffe blog ;) )
I'm assuming a backgroundworker in my app (as it is coded now) would be created by the xxPanel simply to host the calculated netspeed/TickerValue and then use its completion event to signal to the xxLabel that a new speedtickervalue is ready to be shown. And better would probably be, to offload the whole speedcalculation onto the Backgroundworker and have that signal both xxPanel and xxLabel? Do I need seperate backgroundworkers for each object's property that I want to access from another object?
The control.invoke method had also lead me to BackgroundWorker as it's
supposed to be the newer way of doing asynchronous stuff, but I'm gonna
have to look into it a little longer to get the multithreading stuff. The
control.invoke + Delegate stuff is supposed to be threadsafe too, so if
anyone could clarify that with a working xxPanel/xxLabel example, I'd
sure appreciate it.
Yes! Dick Donny's use of the Windows.Forms.Timer made me think about the hidden object-synchronizations done by it, and that made me realize that the System.Timers.Timer I was using in xxLabel, has a .SynchronizingObject method that I was pointing at 'Me' rather than the parent xxPanel object. So now there's several options that all work:(1) Simply use Windows.Forms.Timer which automatically syncs the controls (during the Timer's Tick event).
(2) When using a System.Timers.Timer object, you can set its .SynchronizingObject to point at the parent object and that makes sure that access to the parent's properties from a child is possible during the Timer.Elapsed event.
(3) In the Elapsed event of the Timers.Timer, only update the object if its Parent.InvokeRequired = false (this avoids invoking a property on the parent when the parent isn't available/sync'd with the childobject that is calling the property). This solution will still work if the childobject's timer.SynchronizingObject is not pointing at the parent, so this is basically the preferred solution (for my problem at least).
Notethat control.InvokeRequired also returns False if the control doesn't
have a handle yet, so the extra IsHandleCreated check in the example below, is necessary.
A working example pseudo-code with System.Timers (using solution (2)+(3) together):
Public Class xxForm
Public zPanel as New xxPanel
End Class
Public Class xxPanel
Public zLabel as New xxLabel(Me)
Public PanelTimer as New System.Timers.Timer
Sub New()
PanelTimer.SynchronizingObject = Me
End Sub
Public Property Ticker() As Long
End Class
Public Class xxLabel
Public zParentPanel as xxPanel
Public LabelTimer as New System.Timers.Timer
Sub New(ByVal zGivenParent as xxPanel)
zParentPanel = zGivenParent
AddHandler LabelTimer.Elapsed, AddressOf LabelTimer_Tick
LabelTimer.SynchronizingObject = zParentPanel
End Sub
Sub LabelTimer_Tick(Object, ElapsedEventArgs)
If zParentPanel.InvokeRequired = False And zParentPanel.IsHandleCreated = True Then
Me.Text = zParentPanel.Ticker.ToString
End If
End Sub
End Class
I will still look into the BackgroundWorker thing and MultiThreading, though - it'll probably come in handy one day (soon).
Thanx for the replies, folks, you helped me out a lot and it's truly appreciated! 