【问题标题】:How to associate custom data with a CollectionViewGroup?如何将自定义数据与 CollectionViewGroup 关联?
【发布时间】:2012-10-25 11:11:19
【问题描述】:

我在 XAML 中有一个 ItemsControl,我在其中为每个组显示一个展开器,以便我可以展开/折叠该组。我想保持IsExpanded 属性的状态(以及可能与组标题显示相关的其他设置)。通常你只有一个带有属性的类并绑定到它。但是,该组的数据上下文是CollectionViewGroup。现在这个类不是很有帮助,因为它只为您提供 Name 属性和组中的项目(如果您只想要一个标题并且可能根据组中的项目数或它们的项目数显示某种度量,这很好内容,但如果您只想存储有关组标题 UI 状态的自定义数据)。我想做的是从这个类派生并将其他属性添加到我的派生类并绑定到它。但似乎没有任何简单的方法可以做到这一点。组生成的所有细节似乎都隐藏在内部类中,这非常令人沮丧。有没有人自己实现ICollectionView 的路线(因此可能还有所有其他相关的类)?复制ListCollectionView 中的所有内容似乎是一项艰巨的工作,只是为了能够创建一个自定义的CollectionViewGroup 类并与之绑定!谢谢。

【问题讨论】:

    标签: wpf collectionviewsource icollectionview


    【解决方案1】:

    一种方法是使用MultiBinding 来查找或计算自定义数据和绑定时间。

    我用 Groups 创建了一个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>
    

    等等!它就像一个魅力!

    HTH

    【讨论】:

    • 这如何回答 OP 的问题?他询问如何保持 IsExpanded 值,而不是从他在问题中排除的项目生成指标。
    【解决方案2】:

    一种简单的方法是将 CollectionViewGroup 包装到另一个 ViewModel 类中,该类提供其他所需的显示属性,例如 IsExpanded。我学到的一个教训是不要弯曲 xaml / 视图以匹配业务数据。而是弯曲/包裹或转换业务数据以匹配 UI 的要求。

    【讨论】:

    • 这是个坏建议。通常业务逻辑已经完成或超出您的控制,因此无法“扭曲”它。此外,如果你想在另一个 GUI 上使用相同的逻辑,你会怎么做?重新扭曲它?
    【解决方案3】:

    我能够完全解决这个问题(即绑定到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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-17
      • 1970-01-01
      • 2021-09-07
      相关资源
      最近更新 更多