我做了一个简单的例子来更好地理解MVVM模式。 这是一个示例解决方案的链接,因为它很难解释整个问题: http://www.2shared.com/file/jOOAnacd/MVVMTestMyCopy.html
Employee
模型(包含Age
属性)和EmployeeViewModel
,其中包含Employee
个对象,并在以下代码中更改其Age
属性:< / p>
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
?
编辑:
以下是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>
答案 0 :(得分:17)
在您的项目中,您实际上并未在视图模型上实现INotifyPropertyChanged。你有:
public class ViewModelBase
但这应该是:
public class ViewModelBase : INotifyPropertyChanged
因为您没有实现INotifyPropertyChange,所以WPF绑定系统将无法为您的PropertyChanged事件添加处理程序。
答案 1 :(得分:1)
在ViewModelBase上实现INotifyPropertyChanged接口。 http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx 您已定义了PropertyChanged事件,但它是重要的接口。
答案 2 :(得分:1)
我使用MVVM-Light
代替您的BaseViewModel实现检查了应用程序,并且它按预期工作。
我建议使用MVVM-Light,因为Messaging,Disposing和Blendability等其他功能。
您可以使用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);
}
}
}