后尖可观察集合触发集合在属性上更改更改



Non MVVM. 我得到了这个 ObservableCollectionmachines它由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 的一部分,它只是使机器的所有属性都可以更改通知绑定。 此外,它还使属性的所有属性都可更改通知。

下面是 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>

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

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

谢谢!

若要从集合中的项传播PropertyChanged通知,需要订阅其项的更改通知的集合类。标准ObservableCollection<T>类不会这样做。您可以扩展ObservableCollection<T>,如下所示。您还可以在 SO 上找到更多类似示例(例如,ObservableCollection 还监视集合中元素的更改(。

[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);
}
}

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

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

最新更新