I found this tutorial and I was able to implement it.
How can I disable a button when an errors occurs?
I searched a lot over the net, but I can't find a piece of code that resembles mine. (Yes, I know there about a zillion threads about this matter, but I just don't understand it.)
Here is my current code, it's a bit lengthy:
Public Class GradeVm
Implements IDataErrorInfo
Public Interface IDataErrorInfo
Default ReadOnly Property Item(columnName As String) As String
ReadOnly Property [Error]() As String
End Interface
#Region "Properties"
Property Grade As Integer
Property Adjust As Integer
#End Region
Public ReadOnly Property [Error] As String Implements IDataErrorInfo.Error
Get
Return "Error"
End Get
End Property
Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
Get
Select Case columnName
Case "Grade"
If IsNumeric(Me.Grade) = False Then
Return [Error]
End If
Case "Adjust"
If IsNumeric(Me.Adjust) = False Then
Return [Error]
End If
End Select
Return ""
End Get
End Property
End Class
This combined with the code here did the trick! Finally!! :)
If you're binding button to RelayCommand, you can disable the button by setting CanExecute() function to return False :
Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
Return False
End Function
But RelayCommand doesn't meant to be used this way. I'd suggest to pick a MVVM framework (MVVMLight for example), and you'll get better RelayCommand implementation ready to use. Then you can use it like this :
Private _myCommand As RelayCommand = New RelayCommand(Me.ExecuteCommand, Me.CanExecuteCommand)
Public ReadOnly Property MyCommand As ICommand
Get
Return Me._myCommand
End Get
End Property
Private Sub ExecuteCommand()
......
End Sub
Private Function CanExecuteCommand() As Boolean
'do logic to disable (return false) or enable (return true) button
'based on specific criteria
'just for example, disable the button forever :
Return False
End Function
UPDATE :
Why you deleted your RelayCommand implementation? The 1st approach meant, use RelayCommand in your original post, but change return value of CanExecute() function to False instead of True. Then you can use it in ViewModel like so :
Private _myCommand As RelayCommand = New RelayCommand()
Public ReadOnly Property MyCommand As ICommand
Get
Return Me._myCommand
End Get
End Property
Related
I'm new in WPF and MVVM (I'm using MvvmLight Toolkit) so the way I'm coding is maybe wrong.
The scenario is the following:
I would like to perform initialisation stuff every time i switch views.
So I have created a new InitViewModelBase which inherits ViewModel
Public MustInherit Class InitViewModelBase
Inherits ViewModelBase
...
Public MustOverride Sub Init()
End Class
I call this Init method when switching view
Private _currentViewModel As InitViewModel
Public Property CurrentViewModel() As InitViewModel
Get
Return _currentViewModel
End Get
Set(ByVal value As InitViewModel)
If _currentViewModel IsNot value Then
_currentViewModel = value
_currentViewModel.Init
End If
End Set
End Property
Now I would like to update for example the content of a Label in the Init method
Private _test As String
Public Property Test() As String = "TEST"
Get
Return _test
End Get
Set(ByVal value As String)
_test = value
RaisePropertyChanged("Test")
End Set
End Property
Public Overrides Sub Init()
Test = "UPDATE"
End Sub
<Label Content="{Binding Test}"/>
Why is my label content never updated when i set a new value in my Init method ?
If I set a new value in the constructor it works great.
Is there some special rules I have to be careful about when binding my view to the commands defined in my singleton ViewModel, opposed to normal (non-singleton) ViewModels?
All my ViewModels except the one in question behave normally. Each of them exposes two public members called HasChanges (bool property) and SaveChanges (method) that I'm calling in the CanExecute and Execute functions of my commands.
While all other Views behave normally, enabling/disabling the buttons when the value of HasChanges changes and saving the contents when those buttons are clicked, the only ViewModel that implements Singleton pattern happens to call CanExecute only upon the first loading of the View.
After that, any number of PropertyChanged events raised from within that ViewModel (all my ViewModels implement INotifyPropertyChanged) do not affect the disabled state of the button.
Wondering what I'm missing here.
Here's the singleton ModelView:
Public NotInheritable Class MyViewModel
Private Shared ReadOnly mInstance As New CommonListsViewModel
Public Shared ReadOnly Property Instance() As CommonListsViewModel
Get
Return mInstance
End Get
End Property
Public Property SaveChangesCommand As ICommand
Private Sub New()
SaveChangesCommand = New Commands.SaveChangesCommand()
End Sub
Public ReadOnly Property HasChanges As Boolean Implements IEditorViewModel.HasChanges
Get
...
End Get
End Property
Public Function SaveChanges() As Boolean Implements IEditorViewModel.SaveChanges
...
End Function
End Class
Here's the command:
Friend Class SaveChangesCommand
Inherits CommandBase
Public Overrides Function CanExecute(parameter As Object) As Boolean
Return MyViewModel.Instance.HasChanges
End Function
Public Overrides Sub Execute(parameter As Object)
MyViewModel.Instance.SaveChanges()
End Sub
End Class
And here's my View:
<Grid DataContext="{x:Static local:CommonListsViewModel.Instance}">
<Button Command="{Binding SaveChangesCommand}">
</Grid>
There shouldn't be any difference in the behavior due to the fact that a class follows the singleton pattern. Anything with a reference to the singleton will not care how the construction of the class is restricted, only that the instance of the class exists.
The problem probably lies in a lack of a proper link between the PropertyChanged event of the ViewModel and the CanExecuteChanged on the Command.
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.
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.