データバインディングした ListBox の ListBoxItem にさわる方法

siokoshou2008-12-14


こんばんは、siokoshou です。先日、車で田舎道を走ってたら、でっかいネズミをくわえたネコがのそのそ渡って行きました。やるな!

WPF で一番お気に入りの点は、見た目のよさでもなく、HTML もどきの XAML でもなく、データテンプレートです。その発想はなかったわ!と感動しました。今は何段重ねにもして酷使してます。そんな使い方がいいのかどうかよくわかりませんが(^^;
んー、ここから話をつなげるはずだったんだけど、考えてみたらあまり関係ないやw

というわけで、表題の Tips。ListBox の ItemsSource でデータ列にバインディングすると、ListBox の Items から直接データが取り出せます。それはそれでスゲーのですが、例えばアプリの起動時に前回のアプリ終了時の選択状態を再現したいようなときに ListBoxItem にさわれなくて困ってしまいます。

で、ぐぐった結果 http://www.beacosta.com/blog/?p=7 に答えがありました。Firefox だと表示が崩れます…。
こうやってさわれるそうです。

( ( ListBoxItem ) ( this.listBox.ItemContainerGenerator.ContainerFromIndex( 1 ) ) )
  .IsSelected = true;

ちょっと注意が必要で、コンストラクタや EndInit() ではまださわれず、Loaded イベント以降でさわれるようになりました。

簡単なサンプル。ちょっとデータテンプレートに活躍してもらって、たったこれだけでグラフを書いてみたり。

Window1.xaml

<Window x:Class="ListBoxItemTest.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  Title="Window1" Height="200" Width="200">
  <Window.Resources>
    <DataTemplate DataType="{x:Type sys:Int32}">
      <Grid>
        <Rectangle Width="{Binding}" Height="20" Margin="5" Fill="LightSteelBlue" />
        <TextBlock Text="{Binding}" VerticalAlignment="Center" />
      </Grid>
    </DataTemplate>
  </Window.Resources>
  <Grid>
    <ListBox Name="listBox" SelectionMode="Multiple" ItemsSource="{Binding}" Background="Azure" />
  </Grid>
</Window>

そして Window1.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;

namespace ListBoxItemTest
{
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();

      this.Loaded += new RoutedEventHandler( Window1_Loaded );

      this.DataContext = new[] { 20, 50, 60, 15 };
    }

    private void Window1_Loaded( object sender, RoutedEventArgs e )
    {
      // こうやってさわる!
      ( ( ListBoxItem )
        ( this.listBox.ItemContainerGenerator.ContainerFromIndex( 1 ) ) )
        .IsSelected = true;

      // int:15 が取れる
      int n = ( int ) this.listBox.Items[ 3 ];
      System.Diagnostics.Debug.WriteLine( n );
    }
  }
}

最後に WPF への不満でも書いておくかw
VisualStudio で WPF のプロジェクト開いてると報告ダイアログも出ないでよく落ちる、落ちないけど応答しなくなったりもする、メモリも食いすぎ、そのくせデザイナが貧弱すぎ。
WPF はコントロールがまだまだ足りない。IME まわりがなんかおかしい。アイコンやらピクトグラムベクター化が面倒すぎ。あと、あと、……何だっけ……今日はこのへんにしとくか。