Windows Phone 7でDataTemplateSelectorを使う

DataTemplateSelectorを使うとListBoxなどのアイテムの表示方法をそれぞれのアイテムによって変更することができます。例えばFacebookでは画像や動画といったアイテムが存在するため、それぞれのアイテムによって画像を表示したり動画を表示したりすることが可能となります。
これをWindows Phone 7で利用しようと思っても残念ながら今の段階ではできません。WPFでは利用できるのですがSilverlightでは実装されていないからです。そこでSilverlightでDataTemplateSelectorを利用する例が下記にあります。
Silverlight DataTemplateSelector - CodeProject
これを参考にWindows Phone 7でも利用してみます。
まずはDataTemplateSelectorの定義。
DataTemplateSelectorは抽象クラスとして定義し、OnContentChangedをオーバーライドします。SelectTemplateメソッドはDataTemplateを選択するメソッドで、派生クラスでオーバーライドして実装します。

public abstract class DataTemplateSelector : ContentControl
{
    public abstract DataTemplate SelectTemplate(object item, DependencyObject container);

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        ContentTemplate = SelectTemplate(newContent, this);
    }
}

このDataTemplateSelectorを利用してPivot Applicationの見た目を変えてみます。アイテムの表示をを交互に変更します。
新規に作成したPivot Applicationに上記のクラスを追加します。DataTemplateSelectorクラスを派生してAlternateDataTemplateSelectorクラスを作ります。このクラスは奇数用のテンプレートと偶数用のテンプレートを保持して、偶奇数を判断するために親のリストボックスも保持します(ツリーをたどるのが面倒なので...)。

public class AlternateDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate OddDataTemplate { get; set; }
    public DataTemplate EvenDataTemplate { get; set; }

    public static readonly DependencyProperty ParentListBoxProperty =
  DependencyProperty.Register("ParentListBox", typeof(ListBox), typeof(AlternateTemplateSelector), new PropertyMetadata(null));

    public ListBox ParentListBox
    {
        get { return (ListBox)this.GetValue(ParentListBoxProperty); }
        set { this.SetValue(ParentListBoxProperty, value); }
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return (ParentListBox.Items.IndexOf(item) % 2 == 0)
            ? EvenDataTemplate
            : OddDataTemplate;
    }

SelectTemplateではアイテムのインデックスが偶数が奇数で返すテンプレートを選んでいます。
次はこのAlternateDataTemplateSelectorをPivot Itemに適用します。Main.xamlにlocalのnamespaceを追加し、firstのPivot Itemに適用します。

<controls:PivotItem Header="first">
  <ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <local:AlternateDataTemplateSelector Content="{Binding}" ParentListBox="{Binding ElementName=FirstListBox}">
          <local:AlternateDataTemplateSelector.OddDataTemplate>
            <DataTemplate>
              <StackPanel Margin="0,0,0,17" Width="432" Background="LimeGreen">
                <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
              </StackPanel>
            </DataTemplate>
          </local:AlternateDataTemplateSelector.OddDataTemplate>
          <local:AlternateDataTemplateSelector.EvenDataTemplate>
            <DataTemplate>
              <StackPanel Margin="0,0,0,17" Width="432" Background="IndianRed">
                <Button Content="{Binding LineOne}"/>
                <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
              </StackPanel>
            </DataTemplate>
          </local:AlternateDataTemplateSelector.EvenDataTemplate>
        </local:AlternateDataTemplateSelector>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</controls:PivotItem>

実行すると結果はこんな感じに偶数と奇数でDataTemplateが切り替わっているのが分かると思います。

今回のサンプルプロジェクトはこちらからダウンロードできます。ライセンスはフリーです。
DataTemplateSelector.zip 直