postharp observablecollection在propertychanged上触发collectionchanged

时间:2017-07-10 16:16:58

标签: wpf binding observablecollection postsharp change-notification

非MVVM。 我得到了这个由machines - 类型对象组成的ObservableCollection 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的初始窗口部分:

<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>

绑定部门的一切都很好。我想要的是每当CollectionChanged成员中的某个属性在内部更改属性时,为machines调用Machine事件(或类似事件)。换句话说:如果我更改Parameter Parameters Machine machine内的<TextBlock FontSize="20" Text="{Binding Converter={StaticResource throughputCalculationConverter}, UpdateSourceTrigger=PropertyChanged}"/>,我希望更新计算

Step 3: Startup: Configuration Script A configuration script will run if this is the first login. When prompted for HANA database master password, enter a strong password. Tip: Make a note of this password, since you’ll need it later. You can enter the same password you used earlier, or a new password. If you are entering a new password, see the password rules earlier in this tutorial. XSA_ADMIN XSA_DEV XSA_SHINE TEL_ADMIN When prompted to Confirm “HANA database master password”, enter the strong password again.

谢谢!

1 个答案:

答案 0 :(得分:1)

要从集合中的项目传播PropertyChanged通知,您需要订阅其订阅项目更改通知的集合类。标准ObservableCollection<T>类不会这样做。您可以扩展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);
    }
}

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

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

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