How to update the View using an init method in the ViewModel? - wpf

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.

Related

ListView with grouping and sorting not refresh while INotifyPropertyChanged used

I have my own class which uses INotifyPropertyChanged correctly (Raising updates events), but when a property of type DateTime updated and called (View.Run) the listView not updating untill another property changing (not this property)
Now with the code:
Public Class EntryInfo
Implements INotifyPropertyChanged
ReadOnly Property DateAccessed As Date
Get
.......
Return _Access
End Get
End Property
Readonly Property Property1 as object
Get
.......
Return _Property1
End Get
End Property
Friend Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
RaiseEvent ApropertyHasChanged()
End Sub
Then when I need to Change the "DateAccessProperty" I use this code:
Friend Sub SetAccessTime(Dt As Date)
_Access = Dt
NotifyPropertyChanged("DateAccessed")
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''
After this I have a ListView named "LV1"
Dim Coll as new observableCollection(Of EntryInfo)
....... filing "Coll" with items (EntryInfo)
Lv1.ItemsSource =Coll
Then I do the following:
Do some sort and group operations.
Changing "DateAccessed" value. so that the "ApropertyHasChanged" event fired and at this point I used the following code
Private Sub RefreshViewNow()
Dim _view As ListCollectionView = TryCast(CollectionViewSource.GetDefaultView(LV1.ItemsSource), ListCollectionView)
If _view IsNot Nothing Then _view.Refresh()
'\\\ Items.Refresh()
End Sub
But _view not refreshed.
But if the property "Property1" changed the _View refreshed.
Any help?
The solution is by set the following "_view" properties:
_view.IsLiveFiltering = True
_view.IsLiveGrouping = True
_view.IsLiveSorting = True
or at least one of them if you want one of them only to be activated.

WPF Textbox Binding. VB.Net 2017

Scenario:
A structure is associated with an indexed random access file.
Data is loaded from the file in the constructor at boot time , and the structure is automatically assigned the data values from the file, and the textboxes in the WPF window is automatically populated.
The structure is also updated if the user enter new values in a textbox. So far so good.
The problem arise when the user loads a different dataset from the file when the program is running. This happen in a Button Click event. The structure is updated, but this change is not reflected in the textboxes.
Can someone hopefully shed some light on this.
Pretty new to both WPF and VB.Net
Public Class MainWindow
Shared myStruct As aStruct
Public Structure aStruct
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public year As Integer
Public Property YearP As Integer
Get
Return myStruct.year
End Get
Set(value As Integer)
myStruct.year = value
End Set
End Property
Public salary as Integer
Public Property SalaryP As Integer
Get
Return myStruct.salary
End Get
Set(value As Integer)
myStruct.salary = value
End Set
End Property
.......
.......
End Structure
Public Sub New()
Me.New(".\indxfile.ptx", ".\datafile.dat")
' This call is required by the designer.
'InitializeComponent() ' Moved
' Add any initialization after the InitializeComponent() call.
End Sub
Public Sub New(Optional _IndexFileName As String = "", Optional _DataFileName As String = "")
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.DataContext = myStruct
Dim Retval As Integer
Retval = GetRecord(2018, DataFileName, Len(myStruct), myStruct, IndexFilename)
If Retval <> 0 Then
MsgBox("Error")
End If
End Class
<TextBox x:Name="Year" Text = "{Binding YearP, Mode = TwoWay}"
Your 'Set' properties need to invoke the PropertyChanged event so that the data binding updates.

Updating label binding with property isn't setting right the first time

I have a simple application, and i'm trying to get a grasp on binding, and properties.
What I'm trying to do:
Load a modal window, from the main window. I know this blocks all access to it, so I'm trying to update a label on the modal window through a property binding.
I set the datacontext:
DataContext = busyupdate
InitializeComponent()
Set the variable:
Property busyupdate As BusyWindowGetSet = New BusyWindowGetSet
Then I bind the label to the current context:
Content="{Binding Stage, UpdateSourceTrigger=PropertyChanged}"
Content="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
Here is my BusyWindowGetSet class, where I have 2 properties... Stage and Description. It implements INotifyPropertyChanged
Imports System.ComponentModel
Public Class BusyWindowGetSet
Implements INotifyPropertyChanged
Public Property Stage() As String
Get
Return m_stage
End Get
Set(value As String)
m_stage = value
NotifyPropertyChanged("Stage")
End Set
End Property
Private Shared m_Stage As String
Public Property Description() As String
Get
Return m_description
End Get
Set(value As String)
m_description = value
NotifyPropertyChanged("Description")
End Set
End Property
Private Shared m_Description As String
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
#End Region
#Region "Private Helpers"
Public Sub NotifyPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
End Class
When I load the "busy window" the labels are not updated.. but If I load the window a second time, they show up and change like normal.
This is how I'm setting the properties...
busyupdate.Stage = String.Format("Stage: {0}", "Warming up1")
busyupdate.Description = String.Format("Description: {0}", "Warming up1")
What am I missing here?
Update for Mark:
Dim mm As New BusyWindow
mm.ShowDialog()
busyupdate.Stage = String.Format("Stage: {0}", "Warming up1")
busyupdate.Description = String.Format("Description: {0}", "Warming up1")

vb.net programmatically added binding not working

I am trying to bind a variable value to a button's content property. i created a button named "button" inside a dockpanel of my main window in XAML.
<Button x:Name="button" Content="Button" Height="100"
VerticalAlignment="Top" Width="75"/>
Then I want to add a binding to a public variable test programmatically.
The initial value (400) is displayed correctly at runtime, but when I hit the "NextTurn" button to raise the Click event, the bound value isn't updated.
Imports System.Windows.Data
Class MainWindow
Public test As Integer
Public Sub New()
InitializeComponent()
Dim usr As New UserNS.User
mainUser = usr
test = 400
Dim btest As New Binding()
btest.Source = test
button.SetBinding(Button.ContentProperty, btest)
End Sub
Private Sub NextTurn_Click(sender As Object, e As RoutedEventArgs) Handles NextTurn.Click
test = test - 10
End Sub
End Class
Could you please help me?
Thank you very much!
First of all, fields cannot be bound, only properties.
The binding source should be an object which has the property you would like to bind.
Ideally it is not the form class itself but a separate class (aka. view model).
E.g. the main window (named MainWindow) can have a view model named MainViewModel.
This object must implement the INotifyPropertyChanged interface.
In the property setter you have to call a method which raises the PropertyChanged event that comes with INotifyPropertyChanged interface.
In my example it is:
Private Sub NotifyPropertyChanged(...)
IMPORTANT: VB.NET works in case-insensitive mode so avoid naming a Button control as button. Also if you implement a full property the backing field should have a different name. You cannot have a test field and a Test property at the same time. That's why I chose the _Test name for the field.
Here is a working example:
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Class MainWindow
Implements INotifyPropertyChanged
Public Sub New()
' Actually we can initialize the Test property here as well.
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Test = 400
Dim bindingTest As New Binding() With {
.Source = Me, ' The object which has the property we want to bind.
.Mode = BindingMode.OneWay, ' We declare that the UI will accept changes from the object's property but not vica-versa.
.Path = New PropertyPath("Test") 'We have to pass the name of the property as a String value.
}
TestButton.SetBinding(Button.ContentProperty, bindingTest)
' We could also initialize the Test property here.
End Sub
' We can also initialize only the field instead of the property
' But new values must be set through the property setter.
Private _Test As Integer
Public Property Test() As Integer
Get
Return _Test
End Get
Set(ByVal value As Integer)
_Test = value
NotifyPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
' We use CallerMemberName attribute so that we do not need to pass the name of the property.
' The compiler will automatically pass the name of the caller property. In our case: "Test"
' To get it work we declare the parameter as Optional so that we really do not have to pass a parameter value.
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private Sub NextTurnButton_Click(sender As Object, e As RoutedEventArgs)
' You must set the property's value instead of the backing field!
Test = Test - 10
End Sub
End Class

RaisePropertyChanged doesn't update binding

I've come across some strange behavior. I have a control that binds to a property like so:
<HyperlinkButton x:Name="ProjectBeheerLink"
Visibility="{Binding IsBeheerder, Converter={StaticResource VisibilityConverter}}"/>
In my viewmodel I have the property implemented like this:
Public ReadOnly Property IsBeheerder As Boolean
Get
Return iwtApp.AllMyFunctieRollen.Any(Function(x) x.Rol.Equals(Constants.RoleBeheerder))
End Get
End Property
Then when I raise my PropertyChanged event in my callback method
Private Sub GetMyPersonCompleted(ByVal lo As LoadOperation(Of FunctieRol))
'Init FunctieRollen ect. ...
RaisePropertyChanged(Function() Me.IsBeheerder)
End Sub
my binding does not update.
However! If I implement a backend field like this:
_isBeheerder = iwtApp.AllMyFunctieRollen.Any(Function(x) x.Rol.Equals(Constants.RoleBeheerder))
RaisePropertyChanged(Function() Me.IsBeheerder)
And change my property like this:
Public ReadOnly Property IsBeheerder As Boolean
Get
Return _isBeheerder
End Get
End Property
Everything works fine... Can someone explain me this behavior?
Just curious as to why..
The best way to implement a bound property is as follows:
Dim _isBeheerder As Boolean
Public ReadOnly Property IsBeheerder As Boolean
Get
Return _isBeheerder
End Get
Set
If value <> _isBeheerder Then
_isBeheerder = value
RaisePropertyChanged(Function() Me.IsBeheerder)
End If
End Get
End Property
then in your service callback you just set this property:
Private Sub GetMyPersonCompleted(ByVal lo As LoadOperation(Of FunctieRol))
IsBeheerder = myNewValue
End Sub

Resources