I have a class that implements INotifyPropertyChanged for a property.
I have a control that is bound to that property.
I have another class that listens to the propertychanged event. In the event handler of that class I change the value of the property in code.
The problem I have is that I don't want to do any logic in the event handler for the next time it will fire due to the change of the property due to code.
However if the user changes the value of the property in the mean time (via async gui input) I still want the logic to fire. I also need to make sure that the control gets updated (this is twoway binding).
What is the best way to do this without this becoming a complete mess?
One way to accomplish this would be to refactor the setter on your property so that it called a method taking a parameter indicating whether or not to raise the event. Here is a simple code sample:
Imports System.ComponentModel
Public Class Class1
Implements INotifyPropertyChanged
Public Property MyData() As String
Get
Return _myData
End Get
Set(ByVal value As String)
SetMyData(value, True)
End Set
End Property
Private Sub SetMyData(ByVal value As String, ByVal triggerPropertyChanged As Boolean)
_myData = value
If triggerPropertyChanged Then
OnPropertyChanged("MyData")
End If
End Sub
Private _myData As String
Private Sub OnPropertyChanged(ByVal propertyName As String)
SetMyData("new value", False)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Your question is a bit vague, but you can check to see if the value has actually changed to determine if you should do your logic.
It would be better if you include some code to be more specific in your question.
Related
This is supposed to be easy, yet I can't get it to work.
This is a simplified example so I can illustrate my problem. I have a List(Of Object) and I want to bind the Content of a Label to some property of an object in the list. I want to do this in code (Because those labels will be generated in runtime).
I create my object that will hold the value for the label and the list, that will hold those objects:
' The List to hold objects
Public Class BList
Public Shared listy As New List(Of BindTest)
End Class
' Object to hold label text
Public Class BindTest
Public Property Namy As String
End Class
Then I try to create the object and add it to the list. And try to set the binding for the label (for sake of simplicity, lets say I want bind to the first list item).
Dim bb As New BindTest
bb.Namy = "FirstName"
BList.listy.Add(bb)
B_label.SetBinding(Label.ContentProperty, "Namy")
B_label.DataContext = BList.listy.Item(0)
So far it works fine and label shows "FirstName" as expected. But then if I try to change the value of that first item like this:
BList.listy.Item(0).Namy = "Something else"
nothing happens and the label is not updated.
Thanks to Mike Eason.
I needed to implement INotifyPropertyChanged. I somehow thought, that it would be implemented automatically with all that WPF default-way of databinding everything. Oh well, one needs implement this manually.
So for the code to work, this part:
' Object to hold label text
Public Class BindTest
Public Property Namy As String
End Class
..must be changed to this:
' Object to hold label text
Public Class BindTest
Implements INotifyPropertyChanged
Private _Namy As String
Public Property Namy
Set(value)
_Namy = value
_PropertyChanged("Namy")
End Set
Get
Return _Namy
End Get
End Property
Private Sub _PropertyChanged(Optional ByVal PropertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
Private Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
I am using VB.NET and WPF within Visual Studio 2010 Express.
Currently, I have:
A DataGrid by the name of downloadListDG. This has a column which is a template containing an image.
An ObservableCollection of a custom DownloadListItem class.
This DownloadListItem has a public property which is another custom class.
This class has a private dim which is a StateType (a custom enum), and a public readonly property which returns a string depending on what the StateType is (actually an image URI if you're curious).
The DownloadListItem also has a public property which just returns the StateType (this is just for binding purposes)
My problem is that whenever the StateType changes, the image column in the DataGrid does not change. I have been trying to use the IPropertyChangedNofity, but nothing changes, so either I'm using it incorrectly or I need to use another method.
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
AddHandler ControllerRef.StateChanged, AddressOf StateChangeHandler
Private Sub StateChangeHandler(NewState As State)
MsgBox(NewState)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("CurrentState"))
End Sub
Thanks in advance
Make sure the PropertyChanged event is notifying the UI of the property name you are bound to, not the property that triggers the change. Example:
Imports System.ComponentModel
Public Class DownloadListItem : Implements INotifyPropertyChanged
Friend Enum StateEnum
State1 = 0
State2 = 1
End Enum
Private _CurrentState As StateEnum
Private Sub ChangeEnumValue(NewValue As StateEnum)
_CurrentState = NewValue
OnPropertyChanged("ImageURI")
End Sub
Public ReadOnly Property ImageURI As String
Get
' TODO: Implement conditional logic to return proper value based on CurrentState Enum
End Get
End Property
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(PropertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
End Class
I am sorry if this question is double somewhere, I've searched but did not find.
I have created my own class.
Public Class MyListService
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(ByVal Title As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Title))
End Sub
Private _IsLoggedIn As Boolean = False
Public Property IsLoggedIn As Boolean
Get
Return _IsLoggedIn
End Get
Set(value As Boolean)
If _IsLoggedIn <> value Then
_IsLoggedIn = value
Call OnPropertyChanged("IsLoggedIn")
End If
End Set
End Property
End Class
In WPF project, I have in codebehind
Private WithEvents cWebService As new MyListService
In XAML:
<CheckBox IsChecked="{Binding IsLoggedIn}" x:Name="chkIsLoggedIn" />
Please can you tell me how to bind that "IsLoggedIn" property now to the Checkbox?
Regards
I have absolutely no VB experience but I've used WPF with C#.
Here is my guess:
you need to set DataContext of your CheckBox to point to the MyListService instance for the binding to work since the binding systems needs to know which object the IsLoggedIn property belongs to.
At the moment I have the following Command class:
Public Class SubscribeCommand
Implements ICommand
Private ReadOnly _vm As MainWindowViewModel
Public Sub New(ByVal vm As MainWindowViewModel)
_vm = vm
End Sub
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
Return Not String.IsNullOrEmpty(_vm.Symbol)
End Function
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged
Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
_vm.Subscribe()
End Sub
End Class
In a tutorial i read, you have to implement add {} and remove {} for the canExecuteChanged-Event. But how can i do that, with vb.net?
thanks a lot..
I don't think you're required to implement the add and remove pieces for the CanExecuteChanged event. I'm pretty sure it'll work just fine the way you have it now. But if you did want to for some reason (to make it match what you see in this post in C#, for instance), you would change
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs)
to
Public Custom Event CanExecuteChanged As EventHandler
AddHandler(ByVal value As EventHandler)
CommandManager.RequestSuggested += value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
CommandManager.RequestSuggested -= value
End RemoveHandler
End Event
if you wanna use Commands in wpf please look at the wpf frameworks out there. you will find at least two nice command implementation:
RelayCommand
DelegateCommand
I'm using Linq to SQL classes in my WCF. Those classes are returned from the WCF methods to the Silverlight. Now, I want to add a custom property on a the generated class (Silverlight side) and trigger a PropertyChangedEvent on that particular property, based on another PropertyChangedEvent from another property. To be clear, here's a piece of code that doesn't work :
Partial Public Class DataConnection
Public Sub New()
AddHandler Me.PropertyChanged, AddressOf _PropertyChanged
End Sub
Private Sub _PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If e.PropertyName = "ConnectionType" Then
Me.RaisePropertyChanged("ConnectionTypeEnum")
End If
End Sub
Private _ConnectionTypeEnum As String
Public ReadOnly Property ConnectionTypeEnum() As String
Get
Select Case Me.ConnectionType
Return //Something based on ConnectionType //
End Select
End Get
End Property
End Class
The problem is that the code in New() is never executed, so I never know when the ConnectionType is changed, so I can't trigger the PropertyChanged on ConnectionTypeEnum. (this property is used a in One-Way binding so I need it)
Does anyone have a solution for this ?
Thanks
You can use OnDeserializedAttribute
<OnDeserializedAttribute()> _
Public Sub WhenDeserialized(context As StreamingContext)
AddHandler Me.PropertyChanged, AddressOf _PropertyChanged
End Sub