How to update UI when a property change - vb.net

I'm trying to update my UI when a property in my BL class changes. Please can someone advise the best way to do this in vb.net

Not a really precise question so I will explain the standard way (in my opinion).
Implement the INotifyPropertyChanged interface in your class and handle the PropertyChanged event of your object.
First the the class of the object that contains the property in question:
Public Class MySweetClass
Implements System.ComponentModel.INotifyPropertyChanged
Private _MyProperty As String
Public Property MyProperty As String
Get
Return _MyProperty
End Get
Set(value As String)
_MyProperty = value
RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("MyProperty"))
End Set
End Property
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Notice that the PropertyChanged event is raised once the value of the property changes.
In your form handle this event:
Public Class Form1
Private WithEvents MySweetObject As MySweetClass
Private Sub MySweetObject_PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Handles MySweetObject.PropertyChanged
'Update gui here
End Sub
End Class
This lets you update the GUI whenever the value changes.

Related

DataBind a Simple String Property to Textbox

I have a Simple Property called Customer as string
I want to bind this property to a Textbox.Text Databinding
I use the INotifyPropertyChanged Interface.
If I want to add the Databindings with
TextBox1.DataBindings.Add("Text", Customer, "Text")
I get an Error with:
You cannot bind text to the property or column for the DataSource.
Parameter name: dataMember
Public Class Form1
Implements INotifyPropertyChanged
Private _Customer As String = "DEFAULT"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TextBox1.DataBindings.Add("Text", Customer, "Text")
End Sub
Public Property Customer As String
Get
Return _Customer
End Get
Set
_Customer = Value
NotifyPropertyChanged()
End Set
End Property
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
The reason is that you can't bind to a property directly, you need to bind to an object which contains the property. Also you can't use a property that is inside the Form1 class. You need to set up an instance of an object.
I've created a sample that uses a class named Customer with a single property called Name. I've also created a base class. This is not required, but is useful if you create multiple classes.
Public Class BaseNotify
Implements INotifyPropertyChanged
Friend Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Friend Sub NotifyPropertyChanged(<CallerMemberName()> Optional propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Public Class Customer
Inherits BaseNotify
Private _name As String = "DEFAULT"
Public Property Name As String
Get
Return _name
End Get
Set
If (_name = Value) Then Return
_name = Value
NotifyPropertyChanged()
End Set
End Property
End Class
Finally set up the form (I also renamed the textbox to something more meaningful.
Public Class Form1
Private _customer As Customer
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
BindProperties()
End Sub
Private Sub BindProperties()
_customer = New Customer()
Me.tbName.DataBindings.Add("Text", _customer, NameOf(Customer.Name))
End Sub
End Class
Using NameOf is recommended, as it won't break the code if you decide to change the property name at a later stage.

Is there a Singleton that raises events?

I have a singleton class, but I want its object to be able to raise events.
My current singleton code is as follows:
Private Shared ReadOnly _instance As New Lazy(Of WorkerAgent)(Function() New _
WorkerAgent(), LazyThreadSafetyMode.ExecutionAndPublication)
Private Sub New()
End Sub
Public Shared ReadOnly Property Instance() As WorkerAgent
Get
Return _instance.Value
End Get
End Property
Whenever I change ReadOnly _instance As New.. into ReadOnly WithEvents _instance As New...
I get an error saying ReadOnly is not valid on a WithEvents deceleration
Although I can create the instance in the property itself, but I liked the above code because it is using .NET Lazy keyword which probably have great multithreading benefits.
This isn't an answer to your question as asked but it demonstrates why that question doesn't make sense. It also requires a fair chunk of code so posting in a comment wasn't really an option. This is how your singleton class would raise events, i.e. just like any other class, and how a consumer would handle those events, i.e. just like for any other type.
Singleton:
Public Class WorkerAgent
Private Shared ReadOnly _instance As New Lazy(Of WorkerAgent)
Private _text As String
Public Shared ReadOnly Property Instance As WorkerAgent
Get
Return _instance.Value
End Get
End Property
Public Property Text As String
Get
Return _text
End Get
Set
If _text <> Value Then
_text = Value
OnTextChanged(EventArgs.Empty)
End If
End Set
End Property
Public Event TextChanged As EventHandler
Private Sub New()
End Sub
Protected Overridable Sub OnTextChanged(e As EventArgs)
RaiseEvent TextChanged(Me, e)
End Sub
End Class
Note that the instance event is raised when the instance property changes, just as for any other type, singleton or not.
Consumer:
Public Class Form1
Private WithEvents agent As WorkerAgent = WorkerAgent.Instance
Private Sub agent_TextChanged(sender As Object, e As EventArgs) Handles agent.TextChanged
'...
End Sub
End Class
The field that the single instance is assigned to is where WithEvents gets used. As your error message states, that field cannot be declared ReadOnly too. If they want a ReadOnly field then they need to use AddHandler to handle events.

Binding a VB.NET label.text to an object property

I want to have a label in a form whose text value changes depending upon the value of an instance of a class. It looks like I can bind the text value of the label to an object dataSource. When I try this it does not seem to work.
Me.Label4.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.ItemInfoBindingSource, "ItemNumber", True, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged))
My itemInfoBindingSource:
Me.ItemInfoBindingSource.DataSource = GetType(CFP.ItemInfo)
and the class definition:
Public Class ItemInfo
Public Property ItemNumber As String = "rename"
Public Property Description As String
Public Property FileLocation As String
Public Property CompileHistory As List(Of CompileHistory)
End Class
I think what I have done is to bind to a class, not an instance of a class. Thinking about it, what I really want to do is bind an instance of a class to a label... How?
Is this possible?
Yes, this is possible, but you need to raise an event to let the label know that the property has changed. If you were using a type like a BindingList, this would be done automatically, but you're trying to bind to a String which doesn't raise PropertyChanged events.
To add the event to your class:
Change your class definition to implement INotifyPropertyChanged
Add the corresponding PropertyChanged event
Change the auto-implemented property to an expanded property and raise the event.
Here's the result of these changes for just the ItemNumber property in your class:
Public Class ItemInfo
Implements System.ComponentModel.INotifyPropertyChanged
Private _itemNumber As String = "rename"
Public Property ItemNumber As String
Get
Return _itemNumber
End Get
Set(value As String)
_itemNumber = value
RaiseEvent PropertyChanged(Me,
New System.ComponentModel.PropertyChangedEventArgs("ItemNumber"))
End Set
End Property
Public Event PropertyChanged(sender As Object,
e As System.ComponentModel.PropertyChangedEventArgs) _
Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
I added a text box and label to a form, added the data binding in the Form.Load event, added a field called ItemInfoBindingSource of type ItemInfo, and updated the ItemNumber in the TextBox.TextChanged event.
Private ItemInfoBindingSource As New ItemInfo
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.DataBindings.Add("Text", Me.ItemInfoBindingSource, "ItemNumber")
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) _
Handles TextBox1.TextChanged
ItemInfoBindingSource.ItemNumber = TextBox1.Text
End Sub
Now, when you type in the text box, ItemNumber.Set is called, and raises an event to let anything listening know that it's been changed. The label is listening, and it updates its Text property so that you can see the new value.

Handling Parent Property Event

Is it possible to listen to a parent class' object's event via the property accessor?
What I've tried (a minimal example):
Public Class ParentFoo
Private WithEvents m_bar As EventyObj
Public Property Bar() As EventyObj
Get
Return m_bar
End Get
Set(ByVal value As EventyObj)
m_bar = value
End Set
End Property
End Class
Public Class ChildFoo
Inherits ParentFoo
[...]
Public Sub Bar_OnShout() Handles Bar.Shout
' Some logic
End Sub
End Class
The specific error message I'm getting (VS2005) is "Handles clause requires a WithEvents variable defined in the containing type or one of its base types." Does accessing a private WithEvents variable via a public property strip away the 'WithEvents'?
In ParentFoo:
Public Overridable Sub OnShout() Handles m_bar.Shout
'No Logic Necessary
End Sub
In ChildFoo:
Public Overrides OnShout()
'Logic Here
End Sub
Since ParentFoo will call OnShout when m_bar raises a Shout Event and you override it in ChildFoo, your ChildFoo's OnShout will handle that event.

Binding control property to user control property

I have a user control that has some public properties (like Dirty :boolean) and an event (ControlValueChanged) that change that property.
I added that control to a form. In the form I have a button (btnOK) and I want to bind the property Enabled of the button to the Dirty property.
I read http://msdn.microsoft.com/en-us/library/ms229614.aspx but I face some problems to implement this to my project.
My code in the form:
btnOK.DataBindings.Add("Enabled", Me.wwdp, "Dirty") 'wwdp is my user Control
So from my research I have to add in my custom control:
Imports System.ComponentModel
Public Class wwDynamicPanel
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Public Property Dirty As Boolean
Get
Return mbDirty
End Get
Set(ByVal value As Boolean)
mbDirty = value
NotifyPropertyChanged()
End Set
End Property
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
I get an error : Type 'CallerMemberName' is not defined.
The thing is that I haven't found in msdn anything more.
I am very sorry. The link in MSDN was for framework 4.5
I found the right http://msdn.microsoft.com/en-us/library/ms184414(v=vs.100).aspx. for my framework
and I solved the problem.
I am leaving the question because someone else find it useful.
So the working code is:
Imports System.ComponentModel
Public Class wwDynamicPanel
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Public Property Dirty As Boolean
Get
Return mbDirty
End Get
Set(ByVal value As Boolean)
mbDirty = value
NotifyPropertyChanged("Dirty")
End Set
End Property
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub