ViewModelBase 中的 PropertyChanged 始终为 null
我做了一个简单的例子来更好地理解 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
继承自具有标准 INotifyPropertyCHanged 代码的 ViewModelBase
类:
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
我正在尝试使用 ICommand 更改员工的年龄:
public void Increase()
{
this.SelectedEmployee.Age++;
NotifyPropertyChanged("Age");
}
属性已更改,但绑定的 TextBLock 不会更改其值。 我检查并看到 NotifyPropertyChanged
被调用,但 PropertyChanged
为 null
。 我还确保我的应用程序中只有一个 PeopleViewModel
。 那么,为什么 PropertyChanged
是 null
呢?
编辑: 以下是 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
并设置为 数据上下文
。 属性值已更改,但如果不重新加载对象,则不会显示更改。
以下是显示绑定的 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>
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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在您的项目中,您实际上并未在视图模型上实现 INotifyPropertyChanged。您有:
但这应该是:
因为您没有实现 INotifyPropertyChange,WPF 绑定系统将无法为您的 PropertyChanged 事件添加处理程序。
In your project, you don't actually implement INotifyPropertyChanged on your view-model. You have:
But this should be:
Because you don't implement INotifyPropertyChange, the WPF binding system will not be able to add a handler for your PropertyChanged event.
在 ViewModelBase 上实现 INotifyPropertyChanged 接口。
http://msdn.microsoft.com/en-us/library /system.componentmodel.inotifypropertychanged.aspx
您已经定义了 PropertyChanged 事件,但重要的是接口。
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.
我使用
MVVM-Light
而不是 BaseViewModel 实现检查了您的应用程序,它的工作原理如下它应该。我建议使用 MVVM-Light,因为它具有其他功能,例如消息传递、处置和可混合性。
您可以使用
NuGet
轻松下载并安装它。如果您无论如何都想实现 INotifyPropertyChange,可以使用以下代码:
I checked you application using
MVVM-Light
instead of your BaseViewModel implementation and it worked as it should.I suggest using MVVM-Light because of other features like Messaging, Disposing and Blendability.
You can easily download and install it using
NuGet
.If you want to implement INotifyPropertyChange anyway, here is code that will do it: