Tracking property changes with PostSharp

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-08 05:30:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!