我在 XAML 中有一个 ItemsControl,我在其中为每个组显示一个扩展器,以便我可以展开/折叠该组。我想保留IsExpanded
属性的状态(以及可能与组标题显示相关的其他设置)。通常你只有一个带有属性的类并绑定到它。但是,该组的数据上下文是CollectionViewGroup
. 现在这个类不是很有帮助,因为它只为您提供 Name 属性和组中的项目(如果您只想要一个标题并且可能根据组中的项目数或它们的项目数显示某种指标,这很好内容,但如果您只想存储有关组头 UI 状态的自定义数据,则不需要)。我想做的是从这个类派生并将其他属性添加到我的派生类并绑定到它。但似乎没有任何简单的方法可以做到这一点。组生成的所有细节似乎都隐藏在内部类中,这非常令人沮丧。有没有人走上实现ICollectionView
自己的路线(因此可能还有所有其他相关的类)?复制所有内容似乎是一项艰巨的工作ListCollectionView
只是为了能够创建一个自定义CollectionViewGroup
类并绑定到它!谢谢。
3 回答
一种方法是使用 aMultiBinding
来查找或计算自定义数据和绑定时间。
我做了一个DataGrid
与组,在标题中显示组中项目特定值的总和,以便在组项目更改时更新此总和我使用自定义多值转换器进行了多值绑定,具有ItemCount
属性的多值绑定允许在何时收到通知组项目发生变化,然后更新总和并显示 newsum 值。
这是多值转换器类的代码:
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>
瞧!它就像一个魅力!
高温高压
一种简单的方法是将 CollectionViewGroup 包装到另一个 ViewModel 类中,该类提供其他所需的显示属性,如 IsExpanded。我学到的一个教训是不要弯曲 xaml / 视图以匹配业务数据。而是弯曲/包装或转换业务数据以匹配 UI 的要求。
我能够使用一种与 Cédric 的建议有点相似的方法来解决这个问题(即绑定到),但以一种看似更 MVVM 的方式:IsExpanded
<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