I made a simple example to better understan the MVVM pattern. Here is a link to the sample solution, because its difficult to explain the whole problem: http://www.2shared.com/file/jOOAnacd/MVVMTestMyCopy.html
There is Employee
model (with Age
property) and EmployeeViewModel
, which contains Employee
object and changes its Age
property in the following code:
public int Age
{
get { return _employee.Age; }
set
{
if (value == _employee.Age)
return;
_employee.Age = value;
NotifyPropertyChanged("Age");
}
}
EmployeeViewModel
is inherited from ViewModelBase
class with standard INotifyPropertyCHanged code:
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
I'm trying to change employee's age using ICommand:
public void Increase()
{
this.SelectedEmployee.Age++;
NotifyPropertyChanged("Age");
}
The property is changed, but the binded TextBLock does not change its value.
I checked and saw that NotifyPropertyChanged
is called, but PropertyChanged
is null
.
I also ensured that I have only one PeopleViewModel
in my app.
So, why is the PropertyChanged
is null
?
EDIT:
Here is full code for ViewModelBase
:
public class ViewModelBase
{
public String DisplayName { get; set; }
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
#endregion
}
There is PeopleViewModel
which contains ObservalbleCollectio
n with EmployeeViewModels
and set as DataContext
.
The values of properties are changed, but the changes are not shown without reloading objects.
Here is the PeopleViewer.xaml that shows the binding:
<UserControl x:Class="MVVMTestMyCopy.View.PeopleViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:MVVMTestMyCopy.ViewModel"
mc:Ignorable="d"
d:DesignHeight="316" d:DesignWidth="410">
<UserControl.Resources>
<vm:PeopleViewModel x:Key="viewModel"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource viewModel}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding People}"
Grid.Column="0"
Margin="5,5,4,5"
SelectedItem="{Binding SelectedEmployee, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2"
Text="{Binding FirstName}" />
<TextBlock Margin="2"
Text="{Binding LastName}" />
<TextBlock Margin="0 2"
Text="[" />
<TextBlock Margin="2"
Text="{Binding Age}" />
<TextBlock Margin="0 2"
Text="]" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="0.75*" />
<RowDefinition Height="0.25*" />
</Grid.RowDefinitions>
<Grid x:Name="EmployeeDetails"
Grid.Row="0"
DataContext="{Binding SelectedEmployee}"
Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding FirstName}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.Column="0"/>
<TextBlock Text="{Binding LastName}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.Row="1" />
<TextBlock Text="{Binding Age}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.Row="2" />
</Grid>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
Grid.Row="1">
<Button x:Name="button"
Content="-"
Width="32"
Height="32"
Command="{Binding DecreaseCommand}">
</Button>
<Button x:Name="button1"
Content="+"
Width="32"
Height="32"
Command="{Binding IncreaseCommand}">
</Button>
</StackPanel>
</Grid>
</Grid>
</UserControl>
Although you haven't shown us the XAML use of the property I would think that one way the PropertyChanged is null is when you set the value of a control (which is bound) in code, this will destroy any binding.
Property-change events occur whenever the value of a bound property changes for a bean — a component that conforms to the JavaBeans™ specification. You can find out more about beans from the JavaBeans trail of the Java Tutorial. All Swing components are also beans.
In your project, you don't actually implement INotifyPropertyChanged on your view-model. You have:
public class ViewModelBase
But this should be:
public class ViewModelBase : INotifyPropertyChanged
Because you don't implement INotifyPropertyChange, the WPF binding system will not be able to add a handler for your PropertyChanged event.
Implement the INotifyPropertyChanged interface on your ViewModelBase. http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx You have defined a PropertyChanged event but it is the interface that is important.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With