INotifyPropertyChanged implementation not working with Entity Framework 4.1 Navigation property
Using EF 4.1 I added the INotifyPropertyChanged interface to notified my view when properties change.
public class Department : INotifyPropertyChanged
{
public Department()
{
this.Courses = new ObservableCollection<Course>();
}
// Primary key
public int DepartmentID { get; set; }
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
// Navigation property
public virtual ObservableCollection<Course> Courses { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Course : INotifyPropertyChanged...
In a Master Detail scenario I have a lookup combo to change the Department: When the INotifyPropertyChanged is implemented the department property won’t update, but removing the INotifyPropertyChanged implementation from the Department and Course class it does:
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid
AutoGenerateColumns="False"
EnableRowVirtualization="True"
Height="173"
HorizontalAlignment="Left"
ItemsSource="{Binding CourceViewSource}"
x:Name="departmentDataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top"
Width="347">
<DataGrid.Columns>
<DataGridTextColumn x:Name="CourseID" Binding="{Binding Path=CourseID}"
Header="CourseID" Width="SizeToHeader" />
<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Path=Title}"
Header="Title" Width="SizeToHeader" />
<DataGridTextColumn x:Name="nameColumnw" Binding="{Binding Path=Department.Name}"
Header="Department" Width="SizeToHeader" />
</DataGrid.Columns>
</DataGrid>
<ComboBox Grid.Row="1"
ItemsSource="{Binding DepartmentLookUp}"
SelectedItem="{Binding CourceViewSource/Department}" />
<Button Grid.Row="2" Content="Save" Click="Button_Click"/>
</Grid>
Code Behind ...
private SchoolEntities _context = new SchoolEntities();
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public ICollectionView CourceViewSource { get; private set; }
public ICollectionView DepartmentLookUp { get; private set; }
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_context.Departments.Load();
_context.Courses.Load();
DepartmentLookUp = new ListCollectionView(_context.Departments.Local);
CourceViewSource= new ListCollectionView(_context.Courses.Local);
RaisePropertyChanged(() => DepartmentLookUp);
RaisePropertyChanged(() => CourceViewSource);
}
...
I have included a sample of the problem here.
When selecting a Department in the details the Department in the Master don't update, when changing the Credit % on the master the Credits on the detail gets updated.!
Now changing the SchoolModel.cs so that the Notify class don't implement the INotifyPropertyChanged interface (public class Notify //: INotifyPropertyChanged):
When selecting a Department in the details the Department in the Master DO update, when changing the Credit % on the master the Credits on the detail DON'T get updated.
Im not getting it maybe there is something missing to get both to wor开发者_JAVA技巧k?
Don't know C# well enough to coment on that, but below is my implementation of INotifyPropertyChanged in VB.NET. I do not check the handler status, but just raise the event regardless. Has never failed me.
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Looking into the code you have uploaded the problem seems to be that you have an event handler in code behind (CourceViewSource_CurrentChanged
) which sets the Credits
property when CreditPersentage
in the DataGrid is changed but there is not the counterpart - an event handler which sets the CreditPersentage
when the Credits
TextBox is changed.
If your relationship between Credits
and CreditPersentage
is always a factor of 100 then it doesn't make much sense to have two database columns for both fields. I would consider one of the fields as "calculated" and "dependent" on the other and directly express this in the model. In the database I would store only one of the values. It could look like this:
public class Course : Notify
{
//...
private double _credits; // only one backing field for both properties
public double Credits
{
get { return _credits; }
set
{
_credits = value;
RaisePropertyChanged(() => Credits);
RaisePropertyChanged(() => CreditPersentage);
// notify WPF that also CreditPersentage has changed now
}
}
[NotMapped] // add using System.ComponentModel.DataAnnotations; for this
public double CreditPersentage
{
get { return _credits / 100; }
set
{
_credits = value * 100;
RaisePropertyChanged(() => Credits);
// notify WPF that also Credit has changed now
RaisePropertyChanged(() => CreditPersentage);
}
}
public int DepartmentID { get; set; }
// also add change notification to Department
private Department _department;
public virtual Department Department
{
get { return _department; }
set
{
_department = value;
RaisePropertyChanged(() => Department);
}
}
}
The [NotMapped]
attribute makes sure that there is no CreditPersentage
column in the database. This property is just calculated in memory based on the _credits
field.
Then you can remove the CourceViewSource_CurrentChanged
in the code behind. And for your textbox you could add an UpdateSourceTrigger
:
<TextBox Grid.Row="4" Grid.Column="1"
Text="{Binding Path=CourceViewSource/Credits,
UpdateSourceTrigger=PropertyChanged}" />
It should now be possible to edit the percentage in the DataGrid (the textbox gets updated when you write) and the Credits value in the textbox (the percentage column in the DataGrid gets updated when you write). And when you select a new entry in the comboxbox the Department column in the DataGrid gets updated.
精彩评论