Windows Liveのインストーラを落としてきてWindows Live Writerwo選択して実行しても必ず失敗する。
Proxyとか何かの影響なのかもしれない。
なので、会社からメモをUPするときはコードに色をつける気がしない!!
何処かにWindows Live Writerの最新版のインストーラ落ちてないかなぁ…
Java開発者なら耳慣れた(大体の人が体験したこともあるかな?)単語のXML地獄。
設定ファイルのxmlが大量に出来すぎて泣きたくなるような状況のことをいう。
でも、それも昔の話。
最近は、XMLに記述するんじゃなくてアノテーション(.NETで言うところのアトリビュート)を使ってソース内にエレガントに記述するぜ!!っていうのがトレンド。
普通に考えたらXMLに書いててしんどかったものを、アノテーションで書いてもしんどいよね。
っていうことでannotation hellということが巷で起きてるらしい。
この手の問題は、最近流行?のCoC(Convention over Configuration)かIDEによる手厚いサポートが無いとどうにもならないんじゃないかと思う。
CoCの場合は、覚える規約がいっぱいすぎてソースは綺麗だけど、謎の法則満載に見えてしまうこともあるから、最終的には人間の脳みそを退化させるIDEに頑張ってもらわないと辛い。
まぁ、どれもやり込んだ達人レベルになれば、目を閉じていてもXMLかけるぜ~!とかアノテーション書けるぜ!とか、ここはこういう規約だからこうだ!ってなるんだろうけどね。
そこまで行くには時間が…orz
というか、そこに行くまでの補助輪としても充実したIDEのサポートが欲しいと思う今日この頃でした。
1つ前の記事でWindowsFormを使って作ったものと似たようなものをWPFのListViewを使って作ってみようと思う。WPFのListViewのほうは、さくっとやるだけじゃ編集とかはサポートされないので、とりあえず読み取り専用で作る。
ついでに、2つ前の記事でやったようにWindows FormにWPFのコントロールを埋め込む形で1つ前の記事のWindows Formアプリケーションに埋め込んでWPFとDataGridViewの見た目の比較もできるように作ってみようと思う。
まずは、WPFのUserControlを作成する。名前はDataSetViewerにした。名前に反して汎用的な部品じゃないのを作る予定なのでご了承を。とりあえず、簡単にEmployeesテーブルの中身を出すところまでやってみる。
特に悩むことも無い。DataContextにEmployeesDataTableが設定されているという前提でぽちぽちListViewを組み立てただけだ。
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
これを、フォームの下側に貼り付ける。
フォームのロードイベントで、WPFのユーザコントロールのDataContextにEmployeesDataTableのインスタンスを設定するコードを追加する。
private void Form1_Load(object sender, EventArgs e)
{
// データ取得
this.departmentsTableAdapter.Fill(this.empMngDataSet.Departments);
this.customersTableAdapter.Fill(this.empMngDataSet.Customers);
this.employeesTableAdapter.Fill(this.empMngDataSet.Employees);
dataSetViewer1.DataContext = empMngDataSet.Employees;
}
そして、実行するとEmployeesDataTableのデータがWPFのListViewのほうにも出てる!
次は右側に、選択した従業員の顧客の情報も出してみようと思う。
これは、顧客情報を表示する側のBindingのPathに何を渡すかがわかれば簡単。DataTableのRelationの名前を渡せばOK。DataSetデザイナは、外部キーの名前をRelationの名前にしてくれるので、FK_CustomersEmployeesをBindingのPathに設定すればいける。
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<!-- 従業員データ表示用の列 -->
<ColumnDefinition />
<!-- 顧客データ表示用の列 -->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
<!-- DataTableのリレーション名をパスに指定することでバインドができる -->
<ListView Grid.Column="1" ItemsSource="{Binding FK_CustomersEmployees}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
ばっちり出た。いい感じ。
最後に、従業員の所属する部署名を出してみようと思う。
正直、これにちょっと苦労した。というのも、ListViewのItemsSourceにはEmployeesDataTableを指定してるから、EmployeesRowがListViewの各行にあたるだろうと思ってたら実はDataRowViewのインスタンスだった。なので、何も考えずにBindingのPathにDataSetデザイナが作ってくれるDepartmentsRowプロパティのNameプロパティを指定しても、うまいこと表示されない。
DataRowViewのRowプロパティのDepartmentsRowのNameプロパティという感じでPathを指定することでうまくいった。メモメモ
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<!-- 従業員データ表示用の列 -->
<ColumnDefinition />
<!-- 顧客データ表示用の列 -->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
<!-- DataRowViewに対してBindingのPathを書く! -->
<GridViewColumn Header="DeptName" DisplayMemberBinding="{Binding Row.DepartmentsRow.Name}" />
</GridView>
</ListView.View>
</ListView>
<!-- DataTableのリレーション名をパスに指定することでバインドができる -->
<ListView Grid.Column="1" ItemsSource="{Binding FK_CustomersEmployees}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
実行結果。ばっちり表示できてる。

ということで、DataTableをWPFにバインドするときのメモでした。
ただ、注意しないといけないのは、DataGridViewからデータの追加をしたときにはWPFのほうも追従してくれるけど、従業員名の変更とかは追従してくれないということ。要注意や!
何か、巷の見たことあるサンプルだとMaster/Detailパターンとかで1対多の関係にあるもののデータを表示してしまおう!とかいうのはよく見るような気がする。
文章で説明するのは苦手なので、よく見るパターンから作っていこうと思う。
DatabaseAppという名前でプロジェクトを作ってEmpMng.sdfという名前でローカルデータベースを作成する。ついでにDataSetも作るか?的なことを聞かれるので一緒に作っておく。
EmpMng.sdfにDataSetデザイナにドロップしたら下のような感じになるテーブルを作成する。
部署があって、部署に所属する従業員がいて、従業員に紐づくお客さんがいる。といったイメージ。
フォームにDataSetと、BindingSourceと、BindingNavigator、DataGridViewを置いてEmployeesテーブルの中身を画面に表示するように構成する。
実行すると、Employeesテーブルのデータが画面に表示される。(データは適当に入れました)
ありがちな例は、選択した従業員に紐づくお客さんを表示するといったような感じのものが多い。これは、DataGridViewを、もう1つ置いてDataSourceにbindingSourceEmployeesのFK_CustomerEmployeesを選択すればOKだ。実行すると、左側で選択した従業員に紐づく顧客の情報が表示される。
いい感じだ。
んで、今まで悩んでたのが、従業員テーブルのデータを表示してるDataGridViewに部署情報を表示したい!というとき。
そんでもって見た目は、なるべく普通のテキストを表示するセルと同じにしたい。というものだった。
やり方は、わかってしまえば簡単。DataGridViewComboBoxColumnで、データソースに部署情報、DisplayMemberにNameを指定して、ValueMemberにIDを指定する。
バインド先のプロパティはもちろん、EmployeesテーブルのDeptIDだ。
これだと、普通のドロップダウンになってしまうので、最後にDisplayStyleをNothingにする。これで見た目がぐぐっと普通のセルっぽくなる。
編集中はドロップダウンで、普段の見た目は普通のセルっぽいのが完成。ReadOnlyにすれば同然のことながら普通のセルと区別がつかないかんじになる。
巷にもよくある情報だけど、Windows FormのアプリケーションにWPFを置く方法。
- Windows Form Applicationを作成する
- WPFのUserControlを作成する(作成後ビルドもする)
<UserControl x:Class="WinFormAndWPF.WpfContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button Content="Hello world" />
</Grid>
</UserControl>
- WPF相互運用機能からElementHostをフォームに置く
- ホストするコンテンツの選択で、表示したいWPFのUserControlを選択する
- 完成(上がWPFで下が普通のWindowsFormのボタン)
フォーム上に置いたWPFのUserControlは、普通のWindows Formのコントロールと同じように、フィールドに変数が作られる。ということで、普通に使える。

タイトルの通りです。要はマージンの話。
WPFは、レイアウトを指定すると、そのレイアウトの通りにコントロールを配置してくれる。
恐らくお世話になる率が高いGridレイアウトは、大体のレイアウトをこれだけで記述できちゃうくらいパワフルな代物です。
たとえば、下のようなコードを書くと絵のような画面になります。
<UserControl x:Class="SilverlightTest2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="何か入れてね" />
<TextBox Grid.Row="1" AcceptsReturn="True" />
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="決定" />
<Button Content="キャンセル" />
</StackPanel>
</Grid>
</UserControl>

割とありがちな、画面の説明のためのテキストと入力欄とOKなのかNGなのかを選択するためのボタンがあるタイプの画面です。なんというか、敷き詰められた感があって手抜き感たっぷりに感じてしまう。
何かの番組(今もしてるのかな?)に出てきそうな「ゆとりの空間魔術師」とまでは行かなくても、普通にそれっぽい隙間は入れたいと思うのは人間の性。そういうときに、マージンを使います。
マージンを指定するのは簡単で、Marginプロパティに値を設定するだけ。四方に同じマージンを指定する場合は、単純に値を1つ設定するだけでいいようになってる。
たとえば、ボタンやテキストボックスの周りに幅5のマージンが欲しかったら下のようにすればいい。
<TextBlock Grid.Row="0" Text="何か入れてね" />
<TextBox Grid.Row="1" AcceptsReturn="True" />
<StackPanel Grid.Row="2"
Margin="5"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Margin="5" Content="決定" />
<Button Margin="5" Content="キャンセル" />
</StackPanel>
一律に5とったもんだから、若干不自然な感じもするけど、隙間は開いた。こんな風に調整していけばピッチピチに詰まった画面じゃなくなる。後はセンスの問題だ!
ちなみに、マージンの指定方法には知ってるだけだと下のような指定方法がある。
多分これで全部じゃないかな…?
Margin="5":上下左右に5
Margin="5,10":左右に5、上下に10
Margin="10,20,30,40":左に10、上に20、右に30、下に40
ここら辺の変換は、Marginプロパティにコンバータがしかけてあるのだろう。実際のMarginプロパティの型はLeft,Top,Right,Bottomというdouble型のプロパティを持つThickness構造体であらわされてる。
C#からマージンを指定する場合は、この型を使うことになる。
7月もはじまった!初日からいきなり、プロジェクトの現地へ出張だった。
プロジェクトのメンバーじゃないけど、問題が起きたらいくのがうちの部署。
ということで、早めに終わって無事帰宅。らっき~!ということで6月のページビューです。
日, PV
2008/06/01 1684
2008/06/02 2472
2008/06/03 2768
2008/06/04 2447
2008/06/05 2377
2008/06/06 2661
2008/06/07 1391
2008/06/08 1405
2008/06/09 2824
2008/06/10 2697
2008/06/11 2389
2008/06/12 2566
2008/06/13 2356
2008/06/14 1501
2008/06/15 1365
2008/06/16 2618
2008/06/17 2333
2008/06/18 2188
2008/06/19 2779
2008/06/20 2762
2008/06/21 1349
2008/06/22 1241
2008/06/23 2739
2008/06/24 2524
2008/06/25 2518
2008/06/26 2508
2008/06/27 2553
2008/06/28 1256
2008/06/29 1397
2008/06/30 2410
合計 60992ページビュー
検索で、たまたまたどり着いた方や、見に来て頂いてるかた、どうもありがとうございました。
今月も変わらず、アレを続けると思ったら今度はコレか!ってくらいの幅広さでやっていけたらと思います。
ぱっと見た感じ見当たらない。
CommandBindingsとかがコードエディタで補完されない!!
う~ん。無いのか
参考URL:http://d.hatena.ne.jp/Yamaki/20080324/1206341328
結構好きな機能だったのに残念です。
c303さんが自作のDockPanelをSilverlightで使ってるので、何でだろ?って思ってSilverlightを弄くってみたら、DockPanel無かったのかorz
コンボボックスも無かったり、地味に使うものが無いSilverlight2!
まったく持ってけしからん!!
といっても、Silverlightも結構強力なもので「XXXXが無ければ作ればいいじゃない?」ということが平気で言える。
DockPanelに至っては、WPFで一番強力なレイアウトのGridが使えるので、そいつでまかなえたりする。
ということで、レッツトライ!
構造としては、縦方向にはTop,Center,Bottomにあたる3行をおく。横方向にもLeft,Center,Rightにあたる3列をおく。後は、RowSpanとColumnSpanを適当に設定してコントロールを置くと完成。
<UserControl x:Class="DockPanelModoki.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<!--
Top, Center, Bottom
TopとBottomに必要なだけ幅を指定して、Centerの部分は残り全部。
-->
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--
Left Center Right
LeftとRightに必要なだけ幅を指定して、Centerの部分は残り全部。
-->
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Content="Top"/>
<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"
Content="Left"/>
<Button Grid.Row="1" Grid.Column="2"
Content="Right"/>
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"
Content="Bottom"/>
<Button Grid.Row="1" Grid.Column="1"
Content="Centerにあたるボタン"/>
</Grid>
</UserControl>
実行してみると、DockPanelっぽくなってる。
小さくしても大丈夫

プロパティという概念は、C#には言語自体にある。JavaにはgetXxxxx,setXxxxxみたいなメソッドの組みでプロパティをあらわす。
言語仕様として、プロパティをサポートするかしてないかの違いはあるけれど、プロパティという概念は両言語にある。
んで、間違いやすいのがC#のプロパティ名は最初の一文字目が大文字。Javaは最初の一文字目は小文字。
間違えやすい。
最近Javaをやってることが多かったから、思い出すためにWPFを書いてたら間違えてて5分くらい悩んだ。
悩ましい。