ListViewを使ったDataGridもどきの作成-準備編-

まずは、公開されているサンプルを手に入れることから始めます。本来であれば下記のページからダウンロードできるはずですが、現在はまだできないようです。

編集機能を持つ ListView のサンプル | Microsoft Docs



07/10追記
英語ページではダウンロード可能です。

ListView with Editing Capability Sample



11/06/17追記
2011年6月現在では、こちらのページからダウンロード可能です。

編集機能を持つ ListView のサンプル | Microsoft Docs



というわけで、「VS 2005 SP1用MSDNライブラリ2007年6月版」、もしくは「Windows SDK日本語版」をインストールし、こちらからサンプルを手にいれましょう。
ドキュメントは下記の場所になります。

MSDNライブラリ
ms-help://MS.MSDNQTR.v80.ja/MS.MSDN.v80/MS.NETDEVFX.v20.ja/wpf_samples/html/03893980-1aa0-4dd8-9b81-5645f933722d.htm
Windows SDK
ms-help://MS.MSSDK.1041/MS.NETFX30SDK.1041/wpf_samples/html/03893980-1aa0-4dd8-9b81-5645f933722d.htm



ダウンロードする時点で気がつくかと思いますが、このサンプルはC#しか用意されていません。VBのプロジェクトでも使えるよう、まずはEditBoxコントロールをコンポーネント化したいと思います。


Visual Studio 2005を起動し、[新しいプロジェクト]からC#の「CustomControlLibrary (WPF)」を選択し、[OK]ボタンを押します。プロジェクト名は任意のもので構いませんが、ここでは「EditBox」とします。


[プロジェクト]-[既存項目の追加]で、先ほど手に入れたサンプル内に含まれる「EditBox.cs」と「EditBoxAdorner.cs」をプロジェクトへ追加します。プロジェクトに既定で作成されていた「UserControl1.xaml」は今回は必要ないので削除しておきます。


プロジェクトをビルドすると「EditBox.dll」が作成されます。

ListViewを使ったDataGridもどきの作成-作成編-

作成したEditBoxコントロールを使い、編集機能を持つListViewコントロールを作成していきます。サンプル「ListViewEditable」では、ObjectDataProviderを使ってオブジェクトにバインドしていますが、ここではデータベースを使ってDataTableとバインドするものを作成します。


そのため、ローカルコンピュータのSQL Server Express EditionにNorthWindサンプルデータがインストールされた環境を前提としています。


今度はC#ではなく、Visual BasicのWPFアプリケーションプロジェクトを新規に作成します。もちろんExpression Blend、Visual Sutido 2005のどちらでも構いません。


先ほど作成した「EditBox.dll」への参照を追加します。Expression Blendでプロジェクトを新規作成した場合には、System.Dataアセンブリへの参照が入っていませんので、こちらのアセンブリへの参照も追加します。


下記の内容を入力します。
Window1.xaml

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:Editing="clr-namespace:Editing;assembly=EditBox"
  x:Class="Window1"
  x:Name="Window"
  Title="Window1"
  Width="450" Height="380" Loaded="Window_Loaded">
 
  <Window.Resources>
 
  <Style TargetType="{x:Type Editing:EditBox}" >
      <Setter Property="HorizontalAlignment" Value="Left"  />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type Editing:EditBox}">
            <TextBlock x:Name="PART_TextBlockPart"
                Text="{Binding Path=Value,Mode=Twoway,RelativeSource =
                          {RelativeSource TemplatedParent}}"
                Width="{Binding Path=Width,Mode=Twoway,RelativeSource =
                          {RelativeSource TemplatedParent}}">
            </TextBlock>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
 
  </Window.Resources>
 
  <StackPanel x:Name="LayoutRoot">
    <ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}"
      x:Name="ListView1" Width="Auto" Height="Auto">
      <ListView.View>
        <GridView>
          <GridViewColumn DisplayMemberBinding="{Binding Path=LastName}"
            Header="苗字" Width="100"/>
          <GridViewColumn DisplayMemberBinding="{Binding Path=FirstName}"
            Header="名前" Width="100"/>
          <GridViewColumn Header="役職" Width="200" x:Name="gvColumn3">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <Editing:EditBox Value="{Binding Path=Title, Mode=TwoWay}"
                Height="25" Width="{Binding Path=Width, ElementName=gvColumn3}"/>
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
        </GridView>
      </ListView.View>
    </ListView>
    <Button HorizontalAlignment="Left" Margin="10"
      Width="75" Height="25" Content="更新" Click="Button_Click"/>
  </StackPanel>
</Window>


Window1.xaml.vb
Imports System
Imports System.IO
Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Navigation
Imports System.Data
Imports System.Data.SqlClient
 
Partial Public Class Window1
    Public Sub New()
        MyBase.New()
 
        Me.InitializeComponent()
 
        ' オブジェクト作成に必要なコードをこの点の下に挿入します。
    End Sub
 
    Dim table As New DataTable()
    Dim dataAdapter As SqlDataAdapter
 
    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim connectionString As String = _
                    "Integrated Security=SSPI;Persist Security Info=False;" + _
                    "Initial Catalog=Northwind;Data Source=.\sqlexpress"
        Dim selectCommand As String = "SELECT * FROM Employees"
 
        dataAdapter = New SqlDataAdapter(selectCommand, connectionString)
        Dim cmdBuilder As New SqlCommandBuilder(dataAdapter)
 
        dataAdapter.Fill(table)
        ListView1.DataContext = table
    End Sub
 
    Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        dataAdapter.Update(table)
    End Sub
End Class


このサンプルでは、サンプル「ListViewEditable」での使用方法に2点ほど追加している部分があります。
どちらもxmalコード部分ですが、ひとつは
Text="{Binding Path=Value,Mode=Twoway,RelativeSource =
          {RelativeSource TemplatedParent}}"
で、テンプレートの親のValueプロパティとバインドしている部分ですが、ここにMode=TwoWayを追加しています。これを追加しないと、入力した値をデータベースへ反映させることができません。


もう一つは
Width="{Binding Path=Width,Mode=Twoway,RelativeSource =
          {RelativeSource TemplatedParent}}">
と
<Editing:EditBox Value="{Binding Path=Title, Mode=TwoWay}"
  Height="25" Width="{Binding Path=Width, ElementName=gvColumn3}"/>
の部分で、これにより入力した値に合わせてTextBoxの幅が大きくなった場合に対応しています。





更新ボタンを押すことで、データベース上のデータも更新することができます。簡単なものであれば、この方法を使ってDataGridコントロールのようなUIを実現することが可能だと思います。