PropertyChanged всегда равен нулю во ViewModelBase - PullRequest
7 голосов
/ 26 июля 2011

Я сделал простой пример, чтобы лучше понять схему MVVM. Вот ссылка на пример решения, потому что трудно объяснить всю проблему: http://www.2shared.com/file/jOOAnacd/MVVMTestMyCopy.html

Существует модель Employee (со свойством Age) и EmployeeViewModel, которая содержит объект Employee и меняет свое свойство Age в следующем коде:

public int Age
{
    get { return _employee.Age; }
    set
    {
        if (value == _employee.Age)
            return;
        _employee.Age = value;
        NotifyPropertyChanged("Age");
    }
}

EmployeeViewModel наследуется от класса ViewModelBase со стандартным кодом INotifyPropertyCHanged:

if (PropertyChanged != null)
{
    PropertyChanged(this, new PropertyChangedEventArgs(p));
}

Я пытаюсь изменить возраст сотрудника с помощью ICommand:

public void Increase()
{
    this.SelectedEmployee.Age++;
    NotifyPropertyChanged("Age");
}

Свойство изменено, но привязанный TextBLock не меняет своего значения. Я проверил и увидел, что NotifyPropertyChanged вызывается, но PropertyChanged - это null. Я также гарантировал, что у меня есть только один PeopleViewModel в моем приложении. Итак, почему PropertyChanged это null?

EDIT: Вот полный код для 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

}

Существует PeopleViewModel, который содержит ObservalbleCollectio n с EmployeeViewModels и установлен как DataContext. Значения свойств изменяются, но изменения не отображаются без перезагрузки объектов.

Вот PeopleViewer.xaml, который показывает привязку:

<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>

Ответы [ 3 ]

17 голосов
/ 26 июля 2011

В вашем проекте вы фактически не реализуете INotifyPropertyChanged в своей модели представления.У вас есть:

public class ViewModelBase

Но это должно быть:

public class ViewModelBase : INotifyPropertyChanged

Поскольку вы не реализуете INotifyPropertyChange, система привязки WPF не сможет добавить обработчик для вашего события PropertyChanged..

1 голос
/ 26 июля 2011

Я проверил ваше приложение, используя MVVM-Light вместо вашей реализации BaseViewModel, и оно заработало должным образом.

Я предлагаю использовать MVVM-Light из-за других функций, таких как обмен сообщениями, удаление иСмешиваемость.

Вы можете легко загрузить и установить его, используя NuGet.

Если вы все равно хотите реализовать INotifyPropertyChange, вот код, который сделает это:

public class MainViewModel: INotifyPropertyChanged
{        
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    } 
}
1 голос
/ 26 июля 2011

Реализуйте интерфейс INotifyPropertyChanged на вашей ViewModelBase. http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx Вы определили событие PropertyChanged, но важен именно интерфейс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...