2013年10月02日

WPFサンプル:ControlTemplate で水平スクロールするListBox

   このエントリーをはてなブックマークに追加 Clip to Evernote
水平スクロールするListBoxのサンプルです。

HListBox

見てお分かりのようのリストボックスの要素として、画像を表示しています。
リストボックス内の画像が選択されると、ウィンドウ下部に選択された画像とその名前が表示されます。

まずは、C#側のコードから。
リストボックスに表示するオブジェクトのクラスMyImageクラスを定義します。

public class MyImage {
    public string Name { get; set; }
    public BitmapImage Bitmap { get; set; }
    public MyImage(string name, string uriStr) {
        Name = name;
        Bitmap = new BitmapImage(new Uri(uriStr, UriKind.RelativeOrAbsolute));
    }
}

MainWindowのコンストラクタでは、このMyImageを保持するListの初期化をして、このコレクションオブジェクトを DataContextの設定しています。

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media.Imaging;
namespace HorizontalScrollListBoxSample {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            List<MyImage> myImages = new List<MyImage> {
                new MyImage("砂漠", "Images\\Desert.jpg"),
                new MyImage("アジサイ", "Images\\Hydrangeas.jpg"),
                new MyImage("くらげ", "Images\\Jellyfish.jpg"),
                new MyImage("コアラ", "Images\\Koala.jpg"),
                new MyImage("灯台", "Images\\Lighthouse.jpg"),
                new MyImage ("菊", "Images\\Chrysanthemum.jpg"),
                new MyImage("ペンギン", "Images\\Penguins.jpg"),
            };
            this.DataContext = myImages;
         }
    }
}

C#側のコードはこれだけです。

XAMLでは、まずは、Window.Resourcesに、ListBoxのStyleを定義します。
このStyleの中で、ControlTemplateを使い、ListBoxの見た目を変更しています。
一番内側に、StackPanelを配置し、Orientation="Horizontal" とすることで 要素が横に配置されるようにします。IsItemsHost="True" とすることで ListBoxの各要素が、このSTackPanelに配置されるようにします。
その外側に、ScrollViewer を配置し、スクロールバーで横スクロールするようにします。
さらのその外側に、Border を配置して枠が込みをします。

これで横スクロールするListBoxができたわけですが、まだ、MyImageオブジェクトを表示させることができません。
これをやっているのが、キー名に "PictOnly" をつけたDateTemplateです。

2つめのDateTemplate(キー名:"PictAndName")は、選択されたイメージを表示するもので、 ContentControl の ContentTemplate でBindingしています。

なお、ListBoxでは、ScrollViewer.CanContentScroll="False"を指定することで、 項目単位ではなく、ピクセル単位でスクロールするようにしています。

<Window x:Class="HorizontalScrollListBoxSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:HorizontalScrollListBoxSample"
        Title="MainWindow" Height="240" Width="360">
    <Window.Resources>
        <Style x:Key="myStyle" TargetType="ListBox">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBox">
                        <Border BorderThickness="1" BorderBrush="Gray">
                            <ScrollViewer HorizontalScrollBarVisibility="Auto"
                                   Margin="1,1,1,1"
                                   Background="{TemplateBinding Background}">
                                <StackPanel IsItemsHost="True"
                                            Orientation="Horizontal" />
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <DataTemplate x:Key="PictOnly"   DataType="{x:Type local:MyImage}">
            <Image Height="70" Stretch="Uniform" Width="80"
                   Source="{Binding Bitmap}"/>
        </DataTemplate>
       
        <DataTemplate x:Key="PictAndName"  DataType="{x:Type local:MyImage}">
            <StackPanel Name="stackPanel1" Orientation="Horizontal">
                <Image Height="80" Stretch="Uniform" Source="{Binding Bitmap}"/>
                <Label Content="{Binding Name}" FontSize="14" VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <!-- ScrollViewer.CanContentScroll="False" で少しずつスクロール-->
        <ListBox Height="92" HorizontalAlignment="Stretch" Margin="5"
                 Name="listBox1" VerticalAlignment="Top" 
                 ScrollViewer.CanContentScroll="False"
                 Style="{StaticResource myStyle}"
                 ItemTemplate="{Binding Mode=OneWay, Source={StaticResource PictOnly}}"
                 ItemsSource="{Binding}" />
        <ContentControl Name="myImage" Height="80"
                 ContentTemplate="{Binding Mode=OneWay, Source={StaticResource PictAndName}}"
                 Content="{Binding SelectedItem, ElementName=listBox1}" />
    </StackPanel>
</Window>



WPFサンプル・目次


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52334759