Results 1 to 8 of 8

Thread: Link a label to a global variable?

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2004
    Posts
    263

    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

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2004
    Posts
    263

    Re: Link a label to a global variable?

    great thanks - that makes sense - i'll give it a try

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2004
    Posts
    263

    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

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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:
    1. Public Property Value() As String
    2.         Get
    3.             Return Me._value
    4.         End Get
    5.         Set(ByVal value As String)
    6.             If Me._value <> value Then
    7.                 Me._value = value
    8.  
    9.                 'Raise the event to notify listeners that the property value has changed.
    10.                 RaiseEvent ValueChanged(Me, EventArgs.Empty)
    11.             End If
    12.         End Set
    13.     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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2004
    Posts
    263

    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

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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:
    1. Private WithEvents data As New DataSource
    Otherwise you must use the AddHandler statement to attach an event handler.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width