読者です 読者をやめる 読者になる 読者になる

何故かIronPythonからDataGridにデータをバインドできない (1)

結果的には動いたんですが、Silverlight + IronPythonな環境でDataGridが使えるようになるまで大分手間取ってしまいました。Googleさんで検索してもほとんどヒットしない事例なのでメモを残しておきます。

なお、自分はIronPythonを使っていますが、他のDLR言語(Managed JScriptIronRuby)でも同様の事が発生するはずです。(対応方法も同じで良いはず…)

現象

何も考えずにSilverlight 2のSDKドキュメントのサンプルプログラムIronPythonに移植してみたが、どうもうまく動作しない。

ダメだった手順
  1. IronPythonのスケルトンコードを生成
  2. Silverlight2 SDKのフォルダから「System.Windows.Controls.Data.dll」をdatagrid/pythonフォルダへコピー
  3. AppManifest.xamlを生成
  4. AppManifest.xamlのDeployment.Partsに「System.Windows.Controls.Data.dll」への参照を追加
  5. SDKドキュメントのサンプルプログラムを参考にIronPythonのコードを書いてみる
ダメだったプログラム
  • app.xaml
<UserControl x:Class="System.Windows.Controls.UserControl"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
  <Grid x:Name="layout_root" Background="White">
    <data:DataGrid x:Name="datagrid"  Margin="0,5,0,10" 
        RowHeight="40" AutoGenerateColumns="False" >
      <data:DataGrid.Columns>
        <data:DataGridTextColumn Header="ID" 
            Width="SizeToHeader" Binding="{Binding id}" 
            FontSize="20" />
        <data:DataGridTextColumn Header="name" 
            Width="SizeToHeader" Binding="{Binding name}" 
            FontSize="20" />
      </data:DataGrid.Columns>
    </data:DataGrid>
  </Grid>
</UserControl>
  • app.py
from System.Windows import Application
from System.Windows.Controls import UserControl

# サンプルコードと同様にクラスを作ってみる
# プロパティは2種類用意してみた
class Item(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def _get_name(self):
        self._name
    def _set_name(self, val):
        self._name = val
    name = property(_get_name, _set_name)

# バインドするデータを用意
source = [
    Item('001', 'foo'),
    Item('002', 'bar'),
    Item('003', 'baz'),
]

# xaml読み込み、DataGridへバインド
root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")
root.datagrid.ItemsSource = source
ダメだったプログラムの動作イメージ

配列の要素数は正しく認識され、DataGridの行数は正しく描画されるが、要素のプロパティがバインドされず出力されていない。

f:id:terurou:20081126211316p:image

原因

Googleさんで検索していたら以下のページを見つけた。

DevInfra-US: AgDatagrid and Silverlight Datagrid : how to build a dynamic datasource ?

要するに以下の通りらしい。

  • DataGridにバインドするにはmanaged code(CLR)上に静的なclassが必要
    • Dictonaryなどのような動的なデータはバインドできない
    • DataGrid自体、バインドされるオブジェクトのプロパティをReflectionで取得する実装になっているらしい
    • IronPythonのclass ≠ managed codeのclass
  • 動的データをバインドしたい場合はReflectionで静的なclassを生成してしまえばよい

対応策

長くなってしまったので次回に続く。まだ書いてない。