Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PropertyChanged is always null in ViewModelBase

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 ObservalbleCollection 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>
like image 809
MyUserName Avatar asked Jul 26 '11 11:07

MyUserName


People also ask

Why PropertyChanged is null?

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.

What is PropertyChanged?

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.


2 Answers

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.

like image 107
CodeNaked Avatar answered Oct 28 '22 20:10

CodeNaked


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.

like image 35
Scott Munro Avatar answered Oct 28 '22 19:10

Scott Munro