項目に String ではなく、
Object (Class) の集合を引き当てて、
ListBox の見た目を少し弄って見ましょう。
Form から来た WPF 初心者(私の様に)は、この バインド に手を焼きます
ここでは、 ListBox に バインドする例 で説明します。
ListBox に項目を表示する上では、
先の投稿 VB WPF お勉強 06 ListBox と項目 で書いた様に、
配列 でも、List(Of String) でも、Dictionary(Of Integer, String) でも、
Me.ListBox1.ItemsSource に値を代入する事で、
また、 Me.ListBox1.Items.Refresh() する事で、
項目の動的な変更が可能です。
単純な場合は、これでも OK でしょう。
でも、 やはり、WPF そしてバインドの醍醐味は、複雑なケースをもカバーするその機能にあります。
例えば、選択した項目に 関連した別の要素を絡める としたら ... 。
上の 配列等の項目をそのままで行くなら、
別の要素を 別の配列等で用意し、その添え字(Index)を頼りに、
Code-Behind で操作する事になるかと思います。
つまり選択された項目の Index を元に、別要素を探し出し、何らかの処理を行う です。
でも、別の方法もあります。
オブジェクトとして、これらの内容を一括りに纏めれば、良い事になります。
そう、LIstBox で選ぶのは、 表示されている項目(字面)ではなく、一連の内容を保持したオブジェクトになります。
ここで出て来るのが Class の作成です。
Class が苦手な方!、 是非、マスターして下さいね。.
と書きながら、 私も ... 苦手!。.
各要素を、 Class の Property として定義し、
それを ItemsSource にする のです。
そして、WPF の バインド用に調整された Collection である、
ObjectModel.ObservativeCollection を使いましょう。
これで、先の .Refresh() は不要になります。
色々な書き方があると思いますが、
オブジェクトを表す Class のみ宣言したのが、こちら。
Code Class
Public Class SourceObjClass
Public Property ObjText As String
Public Property ObjOneMore As String
Public Property ObjBool As Boolean
Public Sub New()
End Sub
Public Sub New(ByVal addText As String, ByVal addMore As String, ByVal addBool As Boolean)
ObjText = addText
ObjOneMore = addMore
ObjBool = addBool
End Sub
Public Overrides Function ToString() As String
Return ObjText
End Function
End Class
VB Code-Behind
Class MainWindow
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
SetItemsSource()
End Sub
Private Sub SetItemsSource()
Dim itemsTest As New ObjectModel.ObservableCollection(Of SourceObjClass)
itemsTest.Add(New SourceObjClass("Data1", "item1", True))
itemsTest.Add(New SourceObjClass("Data2", "item2", False))
itemsTest.Add(New SourceObjClass("Data3", "item3", True))
Me.ListBox2.ItemsSource = itemsTest
End Sub
End Class
バインドされた項目は ListBox に表示されますが、
その項目は itemsTest と言う ObservativeCollection に纏められた SourceObjClass の集団です。
Object.ToString は通常オブジェクトのインスタンスを表す文字列を返します。
何も考えずに、 Class を設計すると、 ListBox には この値が反映されます。
つまり、全て、同じクラス名が戻されます。 この例では ProjectName.SourceObjClass 。
これでは困るので、各項目を識別するものを設定するのが Public Overrides Function ToString() ... です。 (必須?).
さて では、いよいよ、 xaml を見て行きましょう。
WPF の ListBox は自由度が高いです。
.ItemTemplate ( 更にその子要素 DataTemplate ) で見た目を設定可能で、
その中の StackPanel で表示項目の指定や、 DataTemplate.Triggers で条件指定 が出来ます。
ここでは、
StackPanel で、各項目の持つ Property を横に並べて表示しつつ、
DataTemplate.Triggers で、 Property ObjBool の値に応じて、部分的な表示色 (Foregound) を指定しています。
そう、 ObjBool が True なら 青文字、 False なら 赤文字で、 別 Property (ObjText) の表示部分ですね。
どの部分か?を定義する為に、 TextBlock に命名して、 Trigger の中で TargetName を与えている処がポイントです。
Trigger 対象が True/False の2値なので、本来はひとつの Trigger で済むのですが ... 。 ご勘弁を。.
xaml
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="ListBox2" Height="100" Margin="10,5,10,20" VerticalAlignment="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<TextBlock Text=" / " />
<TextBlock Text="{Binding ObjText}"
Name="TextBlockColor"/>
<TextBlock Text=" " />
<TextBlock Text="{Binding ObjOneMore}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding ObjBool}" />
</StackPanel>
<DataTemplate.Triggers >
<DataTrigger Binding="{Binding ObjBool}" Value="True">
<Setter TargetName="TextBlockColor" Property="Foreground" Value="RoyalBlue"/>
</DataTrigger>
<DataTrigger Binding="{Binding ObjBool}" Value="False">
<Setter TargetName="TextBlockColor" Property="Foreground" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
はい。 少しは WPF っぽく なって来たみたい ですね。
でも、 横たわる 道 は遠く長い ... 。.
0 件のコメント:
コメントを投稿