|
-
Nov 3rd, 2008, 08:03 PM
#1
Thread Starter
Hyperactive Member
Link a label to a global variable?
Is there anyway to make a label display the current content of a variable without explicitly updating it? I find that I have this code in many places
ChangesMade = False
lblChanges.Text = "No Changes"
What I'm wondering is can I just link lblChanges to the variable ChangesMade so that I can just say
ChangesMade = False
and lblChanges.text will reflect that?
Thanks,
Dave
-
Nov 3rd, 2008, 08:28 PM
#2
Re: Link a label to a global variable?
No you can't. You can bind the Text property of the Label to a property rather than a filed though, although the property would have to be a member of an object that raised an event when the property value changed in order to notify the binding to update the Label.
This may sound complex but think about it. How could a Label possibly know that a variable had changed otherwise? The Label would have to receive some sort of notification that the value had changed in order to know to get the new value and update itself. This is what data-binding is for. You bind the control property to a property of some other object. When the object property is changed it will raise an event that is handled by the Binding in between. The Binding then knows that the object property has changed so it gets the new value and assigns it to the control property, thereby updating the UI.
Most of this is done for you behind the scenes. It's up to you to define the object and its property and event though. Here's an example:
1. Create a new WinForms application project.
2. Add a TextBox, a Button and a Label.
3. Replace all the existing code with this:
Code:
Imports System.ComponentModel
Public Class Form1
Private data As New DataSource
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Bind the Text property of the Label to the Value property of the DataSource object.
Me.Label1.DataBindings.Add("Text", Me.data, "Value")
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.data.Value = Me.TextBox1.Text
End Sub
End Class
Public Class DataSource
Implements INotifyPropertyChanged
Private _value As String
Public Property Value() As String
Get
Return Me._value
End Get
Set(ByVal value As String)
If Me._value <> value Then
Me._value = value
'Raise the event to notify listeners that the property value has changed.
Me.OnPropertyChanged(New PropertyChangedEventArgs("Value"))
End If
End Set
End Property
Public Event PropertyChanged(ByVal sender As Object, _
ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
End Class
4. Run the project, type into the TextBox and click the Button.
Tada! The Label is updated to display the Text without you explicitly setting its Text property. Here's what happened:
1. You set the Value property of the DataSource object.
2. The DataSource object raised its PropertyChanged event.
3. The event was handled by the Binding object that was created when you called DataBindings.Add.
4. The Binding was listening to the PropertyChanged event for the property named "Value".
5. The Binding retrieved the value of that property and assigned it to the bound property of the control, named "Text".
This may seem a lot of work and, frankly, it is for such a simple scenario. Data-binding is a great time-saver in more complex scenarios though, especially with existing classes that already have such properties and events.
-
Nov 3rd, 2008, 08:35 PM
#3
Thread Starter
Hyperactive Member
Re: Link a label to a global variable?
great thanks - that makes sense - i'll give it a try
-
Nov 3rd, 2008, 08:40 PM
#4
Re: Link a label to a global variable?
Note that your data source doesn't necessarily have to implement the INotifyPropertyChanged interface. Doing so means that you only need one event for notifications on multiple properties, but if there's only one property it's cleaner to just create an event specifically for that property:
Code:
Public Class DataSource
Private _value As String
Public Property Value() As String
Get
Return Me._value
End Get
Set(ByVal value As String)
If Me._value <> value Then
Me._value = value
'Raise the event to notify listeners that the property value has changed.
Me.OnValueChanged(EventArgs.Empty)
End If
End Set
End Property
Public Event ValueChanged(ByVal sender As Object, _
ByVal e As EventArgs)
Protected Overridable Sub OnValueChanged(ByVal e As EventArgs)
RaiseEvent ValueChanged(Me, e)
End Sub
End Class
Property-specific events are also better if you need notifications in user code rather than just for binding.
-
Nov 3rd, 2008, 09:42 PM
#5
Thread Starter
Hyperactive Member
Re: Link a label to a global variable?
What I understand is that the protected overridable sub says to call ValueChanged() whenever the set() function is called. but it seems to do this in a convoluted way - by first calling OnValueChanged() and then OnValueChanged() calls ValueChanged() - but ValueChanged() has no body??
the label is just listening to "Value"
Dim ChangeData As DataSource
lblChanges.DataBindings.Add("Text", ChangeData, "Value")
so is that implying that it's listening to the the OnValueChanged event?
Is there a good short tutorial on this somewhere so I dont have to ask so many silly questions?
Thanks
Dave
-
Nov 3rd, 2008, 09:53 PM
#6
Re: Link a label to a global variable?
OnValueChanged is NOT an event. It's a method that raises an event. ValueChanged is NOT a method. It IS an event. An event is basically a notification that something has happened that other code can listen for. That's how event-driven applications work: an object listens for a event and when it receives that event it will do something.
Consider a Button that you add to a form. You handle that Button's Click event. When the Button is clicked by the user it raises its Click event. Your code can listen for that event and when it receives it it knows that the Button was clicked, so it should perform whatever action the Button is supposed to initiate.
In my code the OnValueChanged method exists specifically to raise the ValueChanged event, hence the RaiseEvent statement. When the Value property changes, it calls the OnValueChanged method and that raises the event. You could do away with the OnValueChanged method altogether and just do this:
vb.net Code:
Public Property Value() As String Get Return Me._value End Get Set(ByVal value As String) If Me._value <> value Then Me._value = value 'Raise the event to notify listeners that the property value has changed. RaiseEvent ValueChanged(Me, EventArgs.Empty) End If End Set End Property
and that would be fine in this simple case.
The reason you use a Protected Overridable method to raise the event is so that derived classes can override the method and implement their own custom functionality. A perfect example of this is the Paint event and OnPaint method that all controls have. You can add a control to a form and handle its Paint event and perform some custom drawing each time the control is painted. That's fine for an application developer. If you want to develop a custom control though, e.g. a custom Button that always has something specific drawn on it, then you are supposed to override the OnPaint method and put your custom drawing there.
-
Nov 4th, 2008, 06:40 AM
#7
Thread Starter
Hyperactive Member
Re: Link a label to a global variable?
I think i get it now.
I'm just having one problem: on this line:
lblChanges.DataBindings.Add("Text", ChangeData, "Value")
i get
Object of type "System.EventHandler" cannot be converted to type 'vb_test.DataSource+ValueChangedEventHandler'
I did not make a function to handle the value changed event because I thought the binding was supposed to update the label automatically?
If I were to make a function to handle the event
Private Sub UpdateLabel() Handles ChangeData.ValueChanged
End Sub
It says "handles clause requires a WithEvents variable defined in the containing type"
Any more hints?
Thanks for all the help.
Dave
-
Nov 4th, 2008, 04:19 PM
#8
Re: Link a label to a global variable?
I'm not really sure what would cause that error. Can you post all the relevant code?
It seems like I may have led you astray a little. That second implementation of the DataSource class that doesn't implement INotifyPropertyChanged appears not to work. From what I've read I think it should but I might have to do a bit more research on that. For now you should stick with the first code example.
Yes, if done properly the binding will handle the event and update the Label automatically. If you DID want to handle the event yourself then, to include a variable in a Handles clause, it MUST be declared WithEvents, i.e.
vb.net Code:
Private WithEvents data As New DataSource
Otherwise you must use the AddHandler statement to attach an event handler.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|