C# CollectionViewGroup.Items是否在添加项目后未引发属性更改?
我正在尝试向DataGrid中添加带有小计的分组。阅读几篇文章:解决方案是使用数据创建一个C# CollectionViewGroup.Items是否在添加项目后未引发属性更改?,c#,wpf,data-binding,datagrid,C#,Wpf,Data Binding,Datagrid,我正在尝试向DataGrid中添加带有小计的分组。阅读几篇文章:解决方案是使用数据创建一个ObservableCollection,将其包装到CollectionViewSource中,然后将其作为数据网格的ItemsSource。使用转换器计算小计,该转换器接收CollectionViewGroup的项作为输入,并计算总和 只有在可观测集合的初始填充时或添加项目创建新组时,“所有”都可以正常工作。但是如果一个项目被添加到任何现有的组中,转换器就不会被调用进行重新计算-显然是Collection
ObservableCollection
,将其包装到CollectionViewSource
中,然后将其作为数据网格的ItemsSource
。使用转换器计算小计,该转换器接收CollectionViewGroup
的项作为输入,并计算总和
只有在可观测集合的初始填充时或添加项目创建新组时,“所有”都可以正常工作。但是如果一个项目被添加到任何现有的组中,转换器就不会被调用进行重新计算-显然是CollectionViewGroup.Items
没有引发PropertyChanged
事件?
我在-中浏览了一些项目
是ReadOnlyObservableCollection
,它应该在添加项目后触发属性更改
,不是吗
然后我注意到,CollectionViewGroup.ItemCount
在添加新项目后正确显示,因此我尝试了一个MultiBinding
的技巧-添加了一个IMultiValueConverter
转换器,它将项目
和ItemCount
作为参数,期望ItemCount
触发重新计算。它成功了,但同样没有完全成功——在创建新组时,转换器只获得一次正确的输入。如果将项目添加到现有组,ItemCount
是正确的,但Items
不是<代码>项目
集合缺少新添加的项目!
例如,当项目计数
=2时,项目
只有1个“旧”项目(项目.计数
=1)。当ItemCount
=3时,Items
只有2个“旧”项(Items.Count
=2),等等。因此转换器同样无法计算正确的小计,因为输入不完整
看起来唯一可行的解决方案是为整个CollectionViewSource
调用Refresh()
,但这会扩展所有组,导致闪烁,破坏MVVM概念,因此很难看
因此,我的问题是:
- 是否仍有任何更改要进行
CollectionViewGroup.Items
raisePropertyChanged
正确更改
- 多转换器接收
项。计数=ItemCount
-1,这不是CollectionViewGroup
中的一个错误吗
任何建议都将不胜感激
完整的示例代码已打开
下面是一些代码摘录-
XAML:
<DataGrid.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" BorderThickness="1,1,1,5">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock FontWeight="Bold" Text="Sum 1: " Margin="5,0,0,0"/>
<TextBlock FontWeight="Bold" >
<TextBlock.Text>
<Binding Path="Items" Converter="{StaticResource sumConverter}" ConverterParameter="AmountValue" StringFormat="{}{0:N2}"/>
</TextBlock.Text>
</TextBlock>
<TextBlock FontWeight="Bold" Text="Sum 2: " Margin="5,0,0,0"/>
<TextBlock FontWeight="Bold" >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource sumMulConverter}" ConverterParameter="AmountValue" StringFormat="{}{0:N2}">
<Binding Path="Items"/>
<Binding Path="ItemCount"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
public class SumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == DependencyProperty.UnsetValue) return DependencyProperty.UnsetValue;
if (null == parameter) return null;
string propertyName = (string)parameter;
if (!(value is ReadOnlyObservableCollection<object>)) return null;
ReadOnlyObservableCollection<object> collection = (ReadOnlyObservableCollection<object>)value;
decimal sum = 0;
foreach (object o in collection)
{
sum += (decimal)o.GetType().GetProperty(propertyName).GetValue(o);
}
return sum;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class SumMulConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (null == parameter) return null;
if (!(parameter is string)) return null;
string propertyName = (string)parameter;
if (values == DependencyProperty.UnsetValue) return DependencyProperty.UnsetValue;
if (values == null) return null;
if (values.Length < 2) return null;
if (!(values[0] is ReadOnlyObservableCollection<object>)) return null;
ReadOnlyObservableCollection<object> collection = (ReadOnlyObservableCollection<object>)values[0];
if (!(values[1] is int)) return null;
Debug.Print($"ItemCount={(int)values[1]}; Collection Count = {collection.Count}");
decimal sum = 0;
foreach (object o in collection)
{
sum += (decimal)o.GetType().GetProperty(propertyName).GetValue(o);
}
return sum; //.ToString("N2", CultureInfo.CurrentCulture);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
转换器:
<DataGrid.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" BorderThickness="1,1,1,5">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock FontWeight="Bold" Text="Sum 1: " Margin="5,0,0,0"/>
<TextBlock FontWeight="Bold" >
<TextBlock.Text>
<Binding Path="Items" Converter="{StaticResource sumConverter}" ConverterParameter="AmountValue" StringFormat="{}{0:N2}"/>
</TextBlock.Text>
</TextBlock>
<TextBlock FontWeight="Bold" Text="Sum 2: " Margin="5,0,0,0"/>
<TextBlock FontWeight="Bold" >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource sumMulConverter}" ConverterParameter="AmountValue" StringFormat="{}{0:N2}">
<Binding Path="Items"/>
<Binding Path="ItemCount"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
public class SumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == DependencyProperty.UnsetValue) return DependencyProperty.UnsetValue;
if (null == parameter) return null;
string propertyName = (string)parameter;
if (!(value is ReadOnlyObservableCollection<object>)) return null;
ReadOnlyObservableCollection<object> collection = (ReadOnlyObservableCollection<object>)value;
decimal sum = 0;
foreach (object o in collection)
{
sum += (decimal)o.GetType().GetProperty(propertyName).GetValue(o);
}
return sum;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class SumMulConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (null == parameter) return null;
if (!(parameter is string)) return null;
string propertyName = (string)parameter;
if (values == DependencyProperty.UnsetValue) return DependencyProperty.UnsetValue;
if (values == null) return null;
if (values.Length < 2) return null;
if (!(values[0] is ReadOnlyObservableCollection<object>)) return null;
ReadOnlyObservableCollection<object> collection = (ReadOnlyObservableCollection<object>)values[0];
if (!(values[1] is int)) return null;
Debug.Print($"ItemCount={(int)values[1]}; Collection Count = {collection.Count}");
decimal sum = 0;
foreach (object o in collection)
{
sum += (decimal)o.GetType().GetProperty(propertyName).GetValue(o);
}
return sum; //.ToString("N2", CultureInfo.CurrentCulture);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
公共类SumConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
如果(value==dependencProperty.UnsetValue)返回dependencProperty.UnsetValue;
if(null==参数)返回null;
字符串propertyName=(字符串)参数;
如果(!(值为ReadOnlyObservableCollection))返回null;
ReadOnlyObservableCollection=(ReadOnlyObservableCollection)值;
十进制和=0;
foreach(集合中的对象o)
{
sum+=(十进制)o.GetType().GetProperty(propertyName).GetValue(o);
}
回报金额;
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
公共类SumMulConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
if(null==参数)返回null;
如果(!(参数为字符串))则返回null;
字符串propertyName=(字符串)参数;
如果(value==dependencProperty.UnsetValue)返回dependencProperty.UnsetValue;
if(value==null)返回null;
if(values.Length<2)返回null;
如果(!(值[0]为ReadOnlyObservableCollection))返回null;
ReadOnlyObservableCollection=(ReadOnlyObservableCollection)值[0];
如果(!(值[1]为int))返回null;
Debug.Print($”ItemCount={(int)值[1]}