如何将自定义数据与CollectionViewGroup关联?

7
我在XAML中有一个ItemsControl,每个组都有一个可展开的expander,因此我可以展开/折叠该组。 我想持久化IsExpanded属性的状态(以及与组标题显示相关的其他设置)。通常,您只需要拥有具有属性的类并绑定到它即可。 但是,该组的数据上下文是CollectionViewGroup。 现在,这个类并不是很有用,因为它只提供了Name属性和组中的项(如果您只想要标题并根据组中项的数量或内容显示某种指标,则这很好,但如果您只想存储有关组头UI状态的自定义数据,就不行了)。 我想做的是从这个类派生并向我的派生类添加其他属性,然后绑定到该属性。 但似乎没有任何简单的方法来实现这一点。 所有组生成的详细信息似乎都隐藏在内部类中,这非常令人沮丧。 是否有人走过手动实现ICollectionView的路线(因此预计也会实现所有其他相关类)? 看起来复制ListCollectionView中的所有内容仅仅是为了能够创建自定义的CollectionViewGroup类并绑定到那里而已!谢谢。
3个回答

1
一种方法是使用MultiBinding来查找或计算自定义数据和绑定时间。
我创建了一个带有分组的DataGrid,在标题中显示组中特定值的项目总和,为了在组项更改时更新此总和,我使用了自定义多值转换器的多值绑定,具有ItemCount属性的多值绑定允许在组项更改时得到通知,然后更新总和并显示新的总和值。
以下是多值转换器类的代码:
Public Class UserBalanceConverter
Implements IMultiValueConverter

Private Function GetSubTotal(ByVal obj As CollectionViewGroup) As String

    Dim total As Decimal
    For Each objItem As Object In obj.Items
        If TypeOf objItem Is Account Then
            Dim a As Account = DirectCast(objItem, Account)
            Dim rate As Decimal = 1
            rate = 1 / ExchangeRatesInfo.GetExchangeRate(a.currencyCode.ToString)

            total += a.Balance * rate
        Else
            total += GetSubTotal(objItem)
        End If
    Next

    Return total.ToString("C")
End Function

Public Function Convert(ByVal value() As Object,
                        ByVal targetType As System.Type,
                        ByVal parameter As Object,
                        ByVal culture As System.Globalization.CultureInfo) _
         As Object Implements System.Windows.Data.IMultiValueConverter.Convert

    Dim cvg As CollectionViewGroup = CType(value(1), CollectionViewGroup)

    Return GetSubTotal(cvg)

End Function


Public Function ConvertBack(ByVal value As Object,
                            ByVal targetType() As System.Type,
                            ByVal parameter As Object,
                            ByVal culture As System.Globalization.CultureInfo) _
        As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack

    Throw New NotImplementedException

End Function

End Class

然后在XAML中,您可以在用于GroupItem的样式中使用多值转换器:

  <Style TargetType ="{x:Type GroupItem}" x:Key="UserGroupHeaderStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander x:Name="exp" IsExpanded="False">
                            <Expander.Header>
                                <StackPanel >
                                    <TextBlock Text="{Binding Name}" />
                                    <StackPanel Orientation="Horizontal" >
                                        <TextBlock Text="{Binding ItemCount}">
                                        <TextBlock Text=" "/>
                                        <TextBlock Text="items" />
                                        <TextBlock Text=" "/>
                                        <TextBlock Text="Balance: " />
                                        <TextBlock>
                                            <TextBlock.Text>
                                                <MultiBinding Converter="{StaticResource UserBalanceConverter}">
                                                    <Binding Path="ItemCount"/>
                                                    <Binding />
                                                </MultiBinding>
                                            </TextBlock.Text>
                                        </TextBlock>
                                    </StackPanel>
                                </StackPanel>
                            </Expander.Header>
                            <ItemsPresenter />
                        </Expander>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

完成对您的DataGrid应用样式:
<DataGrid.GroupStyle>
     <GroupStyle ContainerStyle="{StaticResource UserGroupHeaderStyle}">
             <GroupStyle.Panel>
                   <ItemsPanelTemplate>
                           <DataGridRowsPresenter/>
                   </ItemsPanelTemplate>
             </GroupStyle.Panel>
     </GroupStyle>
 </DataGrid.GroupStyle>

还有,不要忘记在XAML资源部分声明您的转换类:

  <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
             <local:UserBalanceConverter x:Key="UserBalanceConverter"/>
        </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>

就是这样!它像魔法一样工作!

希望有所帮助


这个回答如何回应OP的问题?他问如何持久化IsExpanded值,并且不从在问题中排除的项生成指标。 - Firo

0

我能够解决这个问题(即绑定到IsExpanded)使用了一种方法,这种方法与Cédric的建议有些相似,但在看起来更符合MVVM的方式:

<ControlTemplate TargetType="GroupItem">
    <TreeViewItem IsExpanded="{Binding Items[0].IsGroupExpanded, Mode=TwoWay}">
        <TreeViewItem.Header>
            <TextBlock Text="{Binding Name}" />
        </TreeViewItem.Header>
        <TreeViewItem.Items>
            <ItemsPresenter />
        </TreeViewItem.Items>
    </TreeViewItem>
</ControlTemplate>

ItemViewModel.IsGroupExpanded 的 setter 和 getter 都重定向到 Group.IsExpanded

请注意,必须指定Mode=TwoWay,因为IsExpanded默认情况下似乎是绑定OneWay


0
一个简单的方法是将CollectionViewGroup包装到另一个ViewModel类中,该类提供额外所需的显示属性,如IsExpanded。我从一次艰难的经历中学到的教训是不要弯曲xaml /视图以匹配业务数据。相反,应该弯曲/包装或转换业务数据以满足UI的要求。

这是错误的建议。通常业务逻辑已经完成或超出了您的控制,因此没有办法“扭曲”它。此外,如果您想要在另一个GUI中使用相同的逻辑,那么该怎么办?重新扭曲吗? - AsPas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接