问题
I would like to enable a given wizard page when all preceding pages are valid. Here is my view model:
[Aggregatable]
[NotifyPropertyChanged]
[ContentProperty("Pages")]
public class Wizard
{
[Child, AggregateAllChanges]
public AdvisableCollection<Page> Pages { get; } = new AdvisableCollection<Page>();
}
Here is the Page
itself:
[Aggregatable]
[NotifyPropertyChanged]
public class Page : INotifyPropertyChanged
{
[Parent] Wizard Wizard { get; set; }
public string Name { get; set; }
public bool Valid { get; set; }
[SafeForDependencyAnalysis]
public bool Enabled
{
get
{
if(Depends.Guard)
Depends.On(Wizard.Pages);
return Wizard.Pages
.TakeWhile(p => p != this)
.All(p => p.Valid);
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
if (Wizard != null)
NotifyPropertyChangedServices.SignalPropertyChanged(Wizard, nameof(Wizard.Pages));
}
}
I was expecting PostSharp to notify about Enabled
property change when Wizard.Pages
changes. It does not work unfortunately – there is no updates to Enabled
properties. What is wrong about this code?
XAML to test:
<Window.DataContext>
<local:Wizard>
<local:Page Name="First"/>
<local:Page Name="Second"/>
<local:Page Name="Third"/>
<local:Page Name="Forth"/>
</local:Wizard>
</Window.DataContext>
<ListBox ItemsSource="{Binding Pages}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Page}">
<CheckBox Content="{Binding Name}" IsChecked="{Binding Valid}" IsEnabled="{Binding Enabled}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
回答1:
We have investigated the provided sample and it looks like the cause is a compatibility issue between the NotifyPropertyChanged
and Aggregatable
aspects.
If you remove or comment out the [Aggregatable]
attributes, then the event is raised for the Enabled
property as expected. Actually, it's even enough to mark the Wizard
property as a reference instead of parent to fix the NPC behavior. Once the Wizard
property is not marked as a parent, you'll need to ensure the correct value by setting the property manually.
Please note, that you also need to add a property name check in the OnPropertyChanged
method to avoid the infinite loop "Wizard.Pages changed" -> "Enabled changed" -> "Wizard.Pages changed"...
[Aggregatable]
[NotifyPropertyChanged]
public class Page : INotifyPropertyChanged
{
//[Parent]
[Reference]
public Wizard Wizard { get; set; }
public string Name { get; set; }
public bool Valid { get; set; }
[SafeForDependencyAnalysis]
public bool Enabled
{
get
{
if ( Depends.Guard )
Depends.On( Wizard.Pages );
return Wizard.Pages
.TakeWhile( p => p != this )
.All( p => p.Valid );
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
void OnPropertyChanged( string propertyName )
{
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
if ( Wizard != null && propertyName != nameof( Enabled ) )
NotifyPropertyChangedServices.SignalPropertyChanged( Wizard, nameof( Wizard.Pages ) );
}
}
We'll continue investigating the issue and we'll update the answer once the fix is released.
UPDATE. The compatibility bug between the NotifyPropertyChanged
and Aggregatable
aspects has been fixed in PostSharp version 6.0.29. Please update your NuGet packages to the latest version.
来源:https://stackoverflow.com/questions/52359967/tracking-property-changes-with-postsharp