postsharp observablecollection firing collectionchanged on propertychanged

postsharp observablecollection firing collectionchanged on propertychanged

非 MVVM。 我得到了这个 ObservableCollection machines,它由 Machine 类型的对象组成:

[Serializable]
[NotifyPropertyChanged]
public abstract class Machine
{
    public MachineNames MachineType { get; set; }
    public int MachineVersion { get; set; }
    public string LatestEditorName { get; set; }
    public DateTime LatestSaveTime { get; set; }

    public ObservableCollection<Parameter> Parameters { get; set; }
    public string Notes { get; set; }

    public abstract double CalculateThroughPut();

    public Machine()
    {
        string[] nameParts = this.GetType().Name.Split('_');
        Enum.TryParse(nameParts[0], out MachineNames currentMachineType);
        MachineType = currentMachineType;
        MachineVersion = int.Parse(nameParts[1]);

        Parameters = new ObservableCollection<Parameter>();
        ICollectionView icv = CollectionViewSource.GetDefaultView(Parameters);
        icv.GroupDescriptions.Add(new PropertyGroupDescription("Group"));


        LatestEditorName = Environment.UserName;
        LatestSaveTime = DateTime.Now;
    }

    public double getValue(string parameterName)
    {
        Parameter currentParameter = Parameters.Where(x => x.Name == parameterName).First();
        return currentParameter.Value * currentParameter.MetricConversionFactor;
    }

这是它的声明:

public partial class MainWindow : MetroWindow
{
    IEnumerable<string> namesOfExistingMachines { get; set; }

    public ObservableCollection<Machine> machines { get; set; }

及以后:

    private void InitializeData()
    {
        machines = new ObservableCollection<Machine>();
        this.DataContext = machines;

        tcMainTabControl.ItemsSource = machines;

请注意 [NotifyPropertyChanged] 标记,它是 PostSharp 的一部分,它只是使 Machine 的所有属性更改通知以进行绑定。此外,它使属性的所有属性都可以更改。

这是 XAML 的初始 window 部分:

<Grid>
    <Controls:MetroAnimatedTabControl Name="tcMainTabControl">
        <TabControl.ItemContainerStyle>
            <Style TargetType="TabItem">
                <Setter Property="ToolTipService.ShowDuration" Value="100000"/>
                <Setter Property="ToolTipService.InitialShowDelay" Value="0"/>
                <Setter Property="Header" Value="{Binding Converter={StaticResource tabHeaderConverter}}"/>
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <StackPanel Orientation="Vertical">
                            <TextBlock HorizontalAlignment="Center" Margin="0,10" FontSize="40" FontWeight="Bold" Text="{Binding Path=MachineType}"/>
                            <Image HorizontalAlignment="Center" Source="{Binding Path=MachineType, Converter={StaticResource imageUriConverter}}"/>
                            <StackPanel HorizontalAlignment="Center" Margin="0,10" Orientation="Horizontal">
                                <TextBlock FontSize="20" Text="Throughput model version "/>
                                <TextBlock FontSize="20" Text="{Binding Path=MachineVersion}"/>
                            </StackPanel>
                            <StackPanel HorizontalAlignment="Center" Margin="0,10" Orientation="Horizontal">
                                <TextBlock FontSize="20" Text="created by "/>
                                <TextBlock FontSize="20" Text="{Binding Path=LatestEditorName}"/>
                                <TextBlock FontSize="20" Text=" on "/>
                                <TextBlock FontSize="20" Text="{Binding Path=LatestSaveTime, StringFormat=dd/MM/yyyy}"/>
                            </StackPanel>
                            <TextBlock Margin="0,10" FontSize="20" Text="{Binding Path=Notes}"/>
                        </StackPanel>
                    </Setter.Value>
                </Setter>
            </Style>
        </TabControl.ItemContainerStyle>
        <Controls:MetroAnimatedTabControl.ContentTemplate>
            <DataTemplate>
                <DockPanel LastChildFill="True" Margin="10,0">
                    <StackPanel Orientation="Vertical">
                        <Border BorderBrush="{DynamicResource AccentColorBrush}" BorderThickness="1,1,1,1" CornerRadius="8,8,8,8" Margin="0,20" HorizontalAlignment="Center">
                            <StackPanel Orientation="Horizontal" Margin="5">
                                <TextBlock FontSize="20" Text="Throughput: "/>
                                <TextBlock FontSize="20" Text="{Binding Converter={StaticResource throughputCalculationConverter}, UpdateSourceTrigger=PropertyChanged}"/>
                                <TextBlock FontSize="20" Text=" panel sides per hour"/>
                            </StackPanel>
                        </Border>
                        <ListView DockPanel.Dock="Left" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding Path=Parameters, UpdateSourceTrigger=PropertyChanged}">
                            <ListView.GroupStyle>
                                <GroupStyle>
                                    <GroupStyle.ContainerStyle>
                                        <Style TargetType="{x:Type GroupItem}">
                                            <Setter Property="Margin" Value="0,0,0,5"/>
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                                        <Expander IsExpanded="True" BorderBrush="Black" BorderThickness="0,0,0,1">
                                                            <Expander.Header>
                                                                <TextBlock FontSize="20" FontWeight="Bold">
                                                                <Run>Discipline: </Run>
                                                                <TextBlock Text="{Binding Path=Name, Converter={StaticResource titleCaseConverter}}"/>
                                                            </TextBlock>
                                                            </Expander.Header>
                                                            <Expander.Content>
                                                                <Border Margin="2" CornerRadius="3">
                                                                    <ItemsPresenter />
                                                                </Border>
                                                            </Expander.Content>
                                                        </Expander>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </GroupStyle.ContainerStyle>
                                </GroupStyle>
                            </ListView.GroupStyle>
                            <ListView.ItemTemplate>
                                <DataTemplate>
                                    <WrapPanel>
                                        <TextBlock FontSize="20" Text="{Binding Name}" Margin="0,0,10,0" VerticalAlignment="Center"/>
                                        <TextBox FontSize="20" BorderBrush="Black" BorderThickness="0,0,0,1" Background="Transparent" Controls:TextBoxHelper.Watermark="Enter value" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0,0,10,0" VerticalAlignment="Center" HorizontalContentAlignment="Center"/>
                                        <TextBlock FontSize="20" Text="{Binding Unit}" VerticalAlignment="Center"/>
                                    </WrapPanel>
                                </DataTemplate>
                            </ListView.ItemTemplate>
                            <ListView.ItemContainerStyle>
                                <Style TargetType="{x:Type ListViewItem}">
                                    <Setter Property="ToolTip" Value="{Binding Path=Notes}"/>
                                    <Setter Property="Background" Value="Transparent" />
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type ListViewItem}">
                                                <ContentPresenter />
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </ListView.ItemContainerStyle>
                        </ListView>
                    </StackPanel>

绑定部门一切正常。我想要的是每次 Machine 成员中的一个 属性 更改 属性 时为 machines 调用 CollectionChanged 事件(或类似事件) 】 内部。换句话说:例如,如果我更改 machineMachine 之一内的 Parameters 内的 Parameter,我希望它更新计算

<TextBlock FontSize="20" Text="{Binding Converter={StaticResource throughputCalculationConverter}, UpdateSourceTrigger=PropertyChanged}"/>

谢谢!

要从集合中的项目传播 PropertyChanged 通知,您需要订阅其项目更改通知的集合 class。标准 ObservableCollection<T> class 不会那样做。您可以扩展 ObservableCollection<T> ,如下所示。您还可以在 SO 上找到更多类似的示例(例如 ObservableCollection that also monitors changes on the elements in collection)。

[NotifyPropertyChanged]
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (T item in e.OldItems)
            {
                ((INotifyPropertyChanged) item).PropertyChanged -= OnItemPropertyChanged;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (T item in e.NewItems)
            {
                ((INotifyPropertyChanged) item).PropertyChanged += OnItemPropertyChanged;
            }
        }

        base.OnCollectionChanged(e);
    }

    protected void OnPropertyChanged(string propertyName)
    {
        base.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChangedServices.SignalPropertyChanged(this, "Item[]");

        NotifyCollectionChangedEventArgs collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
        base.OnCollectionChanged(collectionChangedEventArgs);
    }
}

当您使用此自定义集合 class 时,该集合将在项目的 属性 更改时引发事件。现在您还可以告诉 PostSharp 将此通知传播为集合 属性 本身的更改,使用应用于集合 属性 的 [AggregateAllChanges] 属性(例如 Parametersmachines).

[AggregateAllChanges]
public ObservableCollectionEx<Parameter> Parameters { get; set; }

[AggregateAllChanges]
public ObservableCollectionEx<Machine> machines { get; set; }