Silverlight 2でTodoアプリを作ってみる その2

前回でTodoアイテムの一覧をListBoxに表示した。
といってもタイトルが表示されているだけなので今回はまず、完了したかどうかを示すチェックボックスを表示してみる。
チェックボックスを表示するためにはListBoxに表示するアイテムの表示方法を変える必要があるが、DisplayMemberPath属性では、データバインドしたオブジェクトのプロパティ名しか指定できないのでこれは使えない。

ではどうするかというと、テンプレートを使う。テンプレートはASP.NETでお馴染みの機能で、その名の通りデータを流し込む画面のテンプレートを自由に定義できる。変更したXAMLが以下

Page.xaml
<ListBox x:Name="ItemList" Grid.Row="1">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="4,0,0,0" Orientation="Horizontal">
                <CheckBox x:Name="Complete" IsChecked="{Binding Complete}" />
                <TextBlock Text="{Binding Title}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

ListBox.ItemTemplate要素のDataTemplate要素の中にテンプレートを定義している。

CheckBoxでチェックボックスを表示する。

  • IsChecked属性でチェック状態を指定できる。ここでは「{}」で囲んで「Binding Complete」と設定しているが、これはバインドされたオブジェクトのCompleteプロパティの値をバインドするという意味になる。

TextBlockのTex属性にも同様の方法でTitleプロパティをバインドしている。

そしてこの二つをStackPanelのOrientation属性をHorizontalにして水平方向に配置している。あとMargin属性で左側だけをちょっと空けている。

これで一度実行してみる。

実行画面

チェックボックスが表示されてるね。

Todoアイテムを追加する

次はTodoアイテムを追加する画面を作成する。

イメージ

Addボタンを押したらこの画面を表示するわけだけど、どうやらSilverlightでは画面遷移みたいなものはあまりしないらしい。どちらかというとWindowsアプリみたいにモーダルダイアログを表示してメイン画面の上でずっとやりつづけるのが流儀みたい。

モーダルダイアログみたいなインターフェースを作るには、まず新しく「Silverlight User Control」ファイルを追加する。ファイル名は「AddItemView.xaml」とする。

イメージ通りに作成したのが以下。

AddItemView.xaml

<UserControl x:Class="SLTodo.AddItemView"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Rectangle Fill="Silver" Opacity="0.8" />
        
        <Border Background="WhiteSmoke" Width="300" Height="200" CornerRadius="20">
            <Grid Margin="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="30" />
                    <RowDefinition />
                    <RowDefinition Height="45" />
                </Grid.RowDefinitions>
                
                <TextBlock Text="Title:" HorizontalAlignment="Right" VerticalAlignment="Center" />
                <TextBlock Text="Description:" HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Center" />
                
                <TextBox x:Name="Title" Grid.Column="1" Margin="4" />
                <TextBox x:Name="Description" Grid.Column="1" Grid.Row="1" Margin="4" />
                
                <StackPanel Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal">
                    <Button x:Name="AddButton" Content="Add"
                            Width="60" Height="30" Margin="4" Click="AddButton_Click" />
                    <Button x:Name="CancelButton" Content="Cancel"
                            Width="60" Height="30" Margin="4" Click="CancelButton_Click" />
                </StackPanel>
            </Grid>
        </Border>
    </Grid>
</UserControl>

解説

ルート要素はメイン画面と同じでUserControlになる。ここではWidth、Heightを指定していないので画面全体(か親要素全体)に表示される。

レイアウトはGridにする。

Rectangleで四角形を描画できる。

  • Fill属性で塗りつぶす色を指定できる。
  • Opacity属性で不透明度を指定できる。

ここではSilverで塗りつぶして、ちょっと透けさせることで背景(メイン画面)が見えるけど、触れないという状態にできる(まさにモーダル)。ちなみにGridでも同様のことができるけど、コンテナ要素にやっちゃうと子コントロール全てに適用されるのでここでは駄目。

二列三行で、一、二行目にラベルとテキストボックス、三行目にボタンを表示している。

AddボタンとCancelボタンにイベントハンドラを追加しているので、この処理をコードビハインドファイルに追加しておく。

AddItemView.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace SLTodo {
    public partial class AddItemView : UserControl {
        public AddItemView() {
            InitializeComponent();
        }

        private void AddButton_Click(object sender, RoutedEventArgs e) {
            this.Visibility = Visibility.Collapsed;
        }
        private void CancelButton_Click(object sender, RoutedEventArgs e) {
            this.Visibility = Visibility.Collapsed;
        }
    }
}

VisibilityプロパティCollapsedを設定しているだけ。これでコントロールを非表示にできる。

とりあえず今のところはこれだけにして、この画面をメイン画面に表示する処理を追加する。

自作のコントロールを使うためには、XAML上で名前空間を宣言する必要がある。

Page.xaml
<UserControl x:Class="SLTodo.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:My="clr-namespace:SLTodo"
    Width="400" Height="300" Loaded="UserControl_Loaded">
    ...
</UserControl>

ここでは「xmlns:My="clr-namespace:SLTodo"」と宣言している。

これでAddItemViewコントロールを使えるようになるので、「Page.xmal」を以下のように変更する。

Page.xaml
<UserControl x:Class="SLTodo.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:My="clr-namespace:SLTodo"
    Width="400" Height="300" Loaded="UserControl_Loaded">
    <Grid Background="White" Margin="8">
        ...
        <My:AddItemView x:Name="AddItemView" Grid.RowSpan="3" Visibility="Collapsed" />
    </Grid>
</UserControl>

My:AddViewItemで追加画面を表示できる。

  • Grid.RowSpan属性で複数行に渡ってコントロールを表示できる。
  • Visibility属性でコントロールの表示状態を指定できる。

ここでは名前を「AddViewItem」にして、非表示にしている。

この追加画面はメイン画面のAddボタンが押された時に表示するので、Addボタンにイベントハンドラを追加する。

Page.xaml
<Button x:Name="AddButton" Content="Add" Grid.Row="2"
        Height="30" Width="60" HorizontalAlignment="Left" Click="AddButton_Click" />

イベントハンドラの処理。

Page.xaml.cs
private void AddButton_Click(object sender, RoutedEventArgs e) {
    AddItemView.Visibility = Visibility.Visible;
}

AddItemViewのVisibilityプロパティをVisibleにしているだけ。

実行して、Addボタンを押してみると、

実行結果

イカス!!