グループを展開/折りたたむことができるように、各グループのエキスパンダーを表示している XAML に ItemsControl があります。IsExpanded
プロパティの状態 (およびグループ ヘッダーの表示に関連するその他の設定)を保持したいと考えています。通常、プロパティを持つクラスがあり、これにバインドします。ただし、グループのデータ コンテキストはCollectionViewGroup
. このクラスは、名前プロパティとグループ内のアイテムしか提供しないため、あまり役に立ちません (見出しだけが必要で、グループ内のアイテムの数またはそのただし、グループ ヘッダー UI の状態に関するカスタム データを保存するだけの場合はそうではありません)。私がやりたいのは、このクラスから派生し、他のプロパティを派生クラスに追加して、代わりにそれにバインドすることです。しかし、これを行う簡単な方法はないようです。グループ生成の詳細はすべて内部クラスに隠されているようで、非常にイライラします。誰かが自分自身を実装する道をたどりましたかICollectionView
(したがって、おそらく他のすべての関連クラスも同様です)? すべてを複製するのは大変な作業のようですListCollectionView
カスタムCollectionViewGroup
クラスを作成し、代わりにそれにバインドできるようにするだけです! ありがとう。
3 に答える
1 つの方法は、 を使用しMultiBinding
てカスタム データとバインド時間を検索または計算することです。
グループ内の項目の特定の値の合計をヘッダーに表示するグループを作成しまし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>
Et Voilà ! それは魅力のように機能します!
HTH
簡単な方法は、CollectionViewGroup を、IsExpanded などの追加の必要な表示プロパティを提供する別の ViewModel クラスにラップすることです。私が苦労して学んだ教訓は、ビジネス データに合わせて 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
セッターとゲッターの両方が にリダイレクトされGroup.IsExpanded
ます。
デフォルトでバインドされているように見えるためMode=TwoWay
、指定する必要があることに注意してください。IsExpanded
OneWay