Archive : 2009

SEP
18

Webkit.NETを触ってみた

Published:2009-09-18 01:52:13 UTC

image 「C#凄い使いやすくて良い言語なんだけど、WebBrowserコントロールは残念だよなー、Trident最近頑張ってるんだけどWebkitとかに比べるとまだまだだよなー」とか常日頃から感じていたのですが、ふと「WebkitをC#から扱うためのラッパーとか探せばあるんじゃね?」という思いつきで「Webkit .net」とググってみると、ありましたありました、「Webkit.NET」というまんまなタイトルのプロジェクトが。オープンソース恐るべし。コンパイル済みのバイナリと共に、サンプルアプリがあったので実行してみました。

image

・・・なにこれ凄い。日本語も全く普通に通りますし、普通に使えそうです。というわけで自分でもテスト用にWinFormsプロジェクトを作って動かすテストをしてみたので、メモを残しておきます。

まず、WebKit.NETライブラリをWebKit .NET | Get WebKit .NET at SourceForge.netからDLしてきます。その中のbinフォルダ内のファイルがライブラリを構成しています。WebKitBrowser.dllがC#から参照するラッパーです。

まず、WebKitBrowserをツールボックスに追加してやります。ツールボックスのコンテキストメニューの「アイテムの選択」という項目をクリックします。

image

この際、ダイアログが表示されるまで、めちゃ重たいかもしれませんが、ぐっとこらえましょう。

image

そして参照ボタンをクリックして、WebKitBrowser.dllを選択してやれば、ツールボックスにWebKitBrowserが追加されます。

image

あとは普通にコントロールをポトベタしておわり…でもありません。。

まず、プロジェクトのプロパティから、プラットフォームターゲットをx86に設定します。Webkitは、現在、x86版のみ提供されているそうです。
image

続いて、デバッグのタブにある、「Visual Studio ホスティング プロセスを有効にする」という項目のチェックを外します。Visual Studioホスティングプロセスは、Visual Studioでのデバッグを効率化させるためのもののようですが、今回のようにアンマネージドコードを連携する場合は上手く働かず、エラーの原因になることがあるようです(Visual Studioホスティングプロセスの解説:VSホスト・プロセス(*.vshost.exe)とは何か?[VS 2005のみ、C#、VB] - @IT)。これが原因のエラーにぶつかって、@JZ5さんに助けを求めたところ、このオプションを教えていただけました。ありがとうございました。

image

こうしてビルドした上で、最後に仕上げに、ビルドして出来た実行ファイルやWebKitBrowser.dllと同じディレクトリに、Webkit本体であるWebkit.dllや、その依存するdll群を放り込みます。ビルド後のイベントでコピーするコマンドを発行してやると良いようです。

image

というわけで出来ました。よいよい。素晴らしい。DOM周りのメンバの実装が未だらしく、出来ることは結構限定されていますが、Monoでも動かせるようにしたいよねー、とREADMEに書かれていたりと、これからの進展に期待したいプロジェクトです。

SEP
15

タイ行ってきました。

Published:2009-09-15 02:08:18 UTC

タイ行ってきました。寺院めぐりとかしてみると、日本の仏教建築との違いが結構面白かったのですが、街中ではタイにおける日本の文化的な影響力が強すぎて、「海外に来た―!」という高揚感があんまりなかったのも事実。まぁ楽しかったです。

P1020226P1020091
P1020097P1020075
P1020062P1020166
P1020217P1020214

SEP
14

物欲沸々。。

Published:2009-09-14 23:46:52 UTC

涼しくなってきましたね。秋です。物欲の秋です!

夏にしていた頼まれ仕事が落ち着いて、普段しているバイトとあわせて財布に結構余裕が出てきたので、物欲がどんどん膨らんできている今日この頃です。

ラップトップ

今買いたいなぁと思っているのはまずラップトップ。何しろ10/22にWindows 7が一般向けにリリースされますし、Visual Studio 2010はWPF化されてやたら重くなりそうなので、そろそろラップトップを買い替えたいなぁと思っています。買い換える上で基準としたいのは、処理速度、堅牢性、携帯性、適度な画面サイズです。

今気になっているのはThinkPadのX200とVAIO Type Z。ThinkPadは大学の研究室に結構あり、触れてみる限りでは確かに噂通り頑丈で良さそうな印象を持っています。逆にVAIOは、現在使っているVAIO Type SZから判断するに、結構軟弱です。機嫌よく動いていてくれている時は良い機種なのですが、故障が多く、かなり修理に出費を強いられたのは苦い思い出です。まぁSonyは延長保証(\15,000程)さえ入れば3年間無償修理をしてくれるので、今度はそれに入っておけば問題にならないかなぁと。。

ちなみに筐体で言えば、MacのUnibodyは正直無いなぁと思っています。結構周りでぶつけた拍子にMBPの角が凹んでしまった人を見かけますし、Airは筐体が歪んで机に置いたときにがたつく様になったという話も聞きます。その上延長保証サービスであるAppleCare Protection Planは¥31,500もしますし(そんなに故障率が高いのか?)。。表面的なカタログスペックや見てくれは立派なんですが、ちょっとMacBookは、ねぇ。。

話をThinkPadに戻すと、やはり携帯性を考えると、モバイル最重視のXシリーズっていいなぁと。画面サイズで言えばX301が13.3インチで1.5kg程と一番望ましく感じられるのですが、CPUが低電圧版なのが気にくわないところです。低電圧版はバッテリの持ちは良くなりますが、値段が跳ね上がり、処理性能は落ちます。自分はたとえバッテリの持ちが悪くなっても通常電圧版CPUであってほしいと考えるタイプなので、やはり画面の小ささは我慢してX200なのかなぁと。

頑健さでいえばLet’s Noteがありますが、こちらは全てのモデルのCPUが低電圧版、超低電圧版に限られているので、これも自分的にはないなぁと。

一方VAIO。Type Z、以前は30万越えは普通というとてつもなく高いシリーズというイメージがありましたが、最近はSSD他の値段の下落に応じてか、20万半ば頑張って捻出すれば十分すぎる性能のモデルが手に入るようになってきたようで、心惹かれるものがあります。画面サイズは13.1インチあり、重量は1.6kg、CPUは通常電圧版と、カタログスペックは非常に素敵です。

ただ、じゃあType ZかX200を買うかというと、まだ迷っていて、というのはコードネームCalpellaとかいうモバイル向けCPUが出てくるそうですし、それにあわせたモデルチェンジをまってみるのもいいかなぁと考えています。なかなか、腹が括れません。。

ハンディデバイス

それより、いま一番買おうかと悩んでいるのがiPod Touch。自分はApple教信者じゃないので、iPhoneは買わずにきました(アプリ開発にMacが要るのが気にくわなかった)。ですが、これだけiPhone/iPod Touchのアプリが揃ってくると流石に興味が出てくるもので、アプリは書けないものの、おもちゃとして買ってみようかなぁと考えています。本当はiPhone 3GSがGPSやカメラなど各種機能が一番統合されていて便利なのでしょうが、今手持ちのTouch DiamondにE-Mobile公認の機能としてあるラップトップとのテザリング機能を手放す気にはなれないので、iPhoneを買うのではなく、iPod Touchを買い、Touch DiamondとiPod TouchをWifiかBTで結んで使ってみるという絵図を描いています。

Appleが出すと噂のタブレットも気になって入るのですが、登場時期が早くとも年明け以降と予測されていて、結構まだ時間が空いていること、出たとしても結構値が張りそう、タブレットだと片手で歩きながら弄れるサイズではない、ということを理由にiPod Touchの方が自分には合っているのだと自分に言い聞かせています(笑)。(しかし、タブレットが出たとして、通信モジュールはどうなるんでしょうね?Touch以上にインターネットへの接続が重要なデバイスになりそうですが、Expressカード型などの通信カードに頼るのか、WiMAX/Wifiモジュールを内蔵するのか、3Gを内蔵するのか、結構興味があります。USBドングルやExpressカード型の通信カードをぶっさすスタイルは見てくれがスマートじゃないのでJobsが嫌いそうなものですが。。)

まぁ、というわけで、これから数カ月は節制生活に入ります。。買ってやるぞー!

以前組み立てたは良いものの、大学やバイト先に持っていくので常用しているラップトップ(VAIO Type SZ)と使い分けが出来ず、メインマシンになりそこねていたShuttleのベアボーンを使って、流行りの仮想化というものに挑戦してみました。

仮想化というのは、一台のマシンの上で、実機をエミュレートした仮想のマシンを走らせることで、複数のOSを並行して走らせたりすることをいいます。一台のサーバーが複数のマシンの役割を果たしてくれる仮想化は、遊んでいるハードウェアは殆ど持っていない自分にとって夢のような技術です。幸い、組み立てていたPCは、こういうこともあろうかと余裕を持たせて4コアのCPUを積んでいたりしたので、挑戦することが出来ました。

これまでもWindows 7 RCとUbuntuをデュアルブートで入れてみたり、それらのOSの上で動くVirtual Boxという仮想化用のソフトを使いDebianやら色々走らせること(ホストOS方式)はしていたのですが、今回は仮想化でも、ハイパーバイザ方式での仮想化を試みてみました。ハイパーバイザ方式とは、ハイパーバイザという仮想化専用のOSを実機にインストールし、そのハイパーバイザが提供する仮想のマシンの上でOSを動かす方式です。ハイパーバイザ方式だと何がいいかというと、仮想化専用のOSがホストOSなため、ホストOSに無駄なリソースを喰われたり、ホストOSのアップデートなどでVMを落とす必要に迫られることが少ない点が優れています。今回は、VMware ESXiというハイパーバイザを入れ、その上にWindows 7 RCとUbuntu、CentOS、Free NASなど諸々を入れてみることを目指しました。VMware ESXiは以前、大学のサーバーで触らせてもらったことがあったのですが、そのときはCPUのコア:たくさん、メモリ:いっぱい、という、まぁ化け物みたいな構成のもので、後はVMを作るだけという状態で弄らせてもらったので簡単だったのですが、今回はサーバー機でない単なるベアボーンで一から構築したので少し難儀しました。

まず一点目がインストール時にHDDを認識しないという点。IDEのHDDを認識しないというのは聞いていたのですが、SATAで繋いでいた自分のマシンでも駄目でした。色々試したりしているうちに、ググって出てきたのがVMware ESXi を IDE HDD にインストール – trial and errorというページ。曰く、SATAでもAHCI モードで動いてない場合、IDE HDDとして認識され、それがもとで弾かれているとかなんとか。そこでBIOSの設定を見直し、AHCIモードに切り替えてみたのですが、こんどはSATA接続のDVDドライブが認識されないという問題が発生。どうもDVDドライブのファームウェアに問題があるらしく、泣く泣く設定を戻し、VMware ESXi を IDE HDD にインストール – trial and errorで紹介されている、インストールスクリプトでIDE接続のHDDをはじいている部分を書き換えるという方法で乗り切りました。DVDドライブをあきらめても良かったのですが、そうするとESXiをアップデートする必要に迫られた時に面倒がおきそうだったので、AHCIモード動作化は今回は見送りました。

続いて直面したのがオンボードのNICが認識されないという問題。なんでもESXiはIntelかBroadcomのチップを載せた一部のLANボードにしか対応していないとか。。こればかりは仕方がないので、EXPI9301CTというLANボードをAmazonでポチリ。\4,680と、目玉が飛び出るような高さではないけれど、今じゃ\4000もあればバルクのDVD±RWドライブが買えてしまうことを考えると、ちょっと高いかなと感じたり。そういうものなのでしょうか。

image ここまで来ると後は簡単で、ハイパーバイザに固定IPを割り振り、そのIPに対して、ラップトップにインストールしたVMware Infrastructure Clientで接続してVMを作っていくだけの簡単なお仕事になります。

なにはともあれまず入れたのはWindows 7。もうRTMもMSDNやTech Netで出てますし、Tech Net Direct Plusに申し込んで、RTMを手に入れても良いかと思ったのですが、折角Tech Net Direct Plusに申し込むならOffice 2010も欲しいよね、ということで、ぐっと我慢してOffice 2010のリリース時期がもう少し信じられるレベルまで固まるまで待つことにし、とりあえずはWindows 7 RCをインストール。その上でそのWindows 7に対し、リモートデスクトップ接続できるように色々と設定を行いました。VMware Infrastructure Clientのコンソールも、よいのですが、Aeroが効かないし、効率はやはりリモートデスクトップ接続に劣るからです。LAN内での接続はすぐ上手くいったのですが、外からインターネット経由で繋ぐのは少し難儀しました。自分の家は当然固定IPなぞ持っていないので、ダイナミックDNSサービスを利用し、ドメイン名でアクセスし、ブロードバンドルータからWin7のVMに対してリモートデスクトップ接続に使うポートをポートマッピングしてやったのですが、なぜか繋がらないという。。ラップトップからLANケーブルを引っこ抜き、代わりにイーモバイルの回線経由で接続のテストをしているつもりだったのですが、実は無線LANで家のネットワークにぶら下がりっぱなしだったのが原因でした。VMware Infrastructure Clientの接続が切断されない時点で気付くべきだったのですが、なかなか。。。時間を無駄にしてしましました。

つづいてセットアップしたるはFreeNAS。古いPCを簡単お手軽にNAS化できるアプライアンスOSです。数日前に7年程前のPCを引っ張り出してきて試してみたものの、そのPCのファンの五月蠅さに常時立ち上げておく気になれず、どうしたものかと思っていたものを移行させるために作成しました。本当はRAID化やバックアップの設定もしたいところなのですが、何せ物理HDDがベアボーンに内蔵させている一台しかないので、今のところはあきらめています。いずれeSATAでいくつもHDDを足したいところです。

更に続くはUbuntu.今のところ一応入れてみただけです。多分ずっと寝かせっぱなしになりそうだなぁ。。

そしてCentOS。とりあえずこいつを安定的に運用するのが目的。ぶっ壊すの覚悟のテスト用と、安定的に運用する奴と二つ。仮想化環境でなければ自分には到底実現できない、ぶるじょあな構成(笑)。壊したとしても、スナップショットがあるので、直ぐ戻せるという仮想化の利点を生かして、これでLinuxの勉強をしてみたいと思います。

AUG
9

明石海峡大橋を渡ってきました。

Published:2009-08-09 00:14:23 UTC

P10103317日から墓参りなどで大阪の母方・父方の実家を回っていまして、昨日は一日時間があったので、レンタカーを借りて明石海峡大橋を渡り、鳴門まで行ってきました。いやー明石海峡大橋、デカい!流石世界一の吊り橋。垂水側のアンカレイジ脇で写真を撮ったのですが、淡路島側はロクに写りませんでした。。

鳴門側では大鳴門橋の下部から、有名な鳴門の渦潮を見てきました。途中、渋滞に引っかかったりしたので、満潮時刻には間に合わず、綺麗な写真は撮れなかったのですが、波が渦を巻いている様は、非常に迫力のあるものでした。

そして鳴門では「釜揚げうどん」を食べてきました。本当は本場、讃岐まで行きたかったのですが、時間がなかったので。。とても美味しかったです。

P1010363P1010386

AUG
3

中国でTwitterを利用する方法

Published:2009-08-03 23:30:25 UTC

image ご存知の通り、中国では政府にとって好ましくないとされるサイトへのアクセスはブロックされており、Twitterもその一つです。TwitterのWebページのアクセスも、TwitterクライアントがTwitter APIを叩きに行くのもブロックされています(自分は普段TweetDeckを使っています)。しかし、それで「はいそうですか」、と素直に引き下がれるほど自分のTwitter依存度は低くなく。。一緒に上海に行った人達は日本にWebプロキシを建てた上で使っていたようですが、自分はちょっと違った方法を使いました。sobeesを使うという方法です。これはSilverlightで作られたTweetDeckライクなマルチカラムTwitterクライアントで、これはSilverlight3で構築されていて、Out of Browser機能が有効化されているので、これをデスクトップにインストールして使用していました。

ではなぜTweetDeckが使えずにsobeesが使えるかというと、sobeesはSilverlightで構築されているので、直接クライアントがTwitterのAPIを叩きに行けず、クライアントの配布されているsobeesのサーバーがsobeesのクライアントからのAPI呼び出し要求をTwitter APIに中継しているという性質によるものです。実は、中国国内からのアクセスが制限されいるのはTwitterのWebページとTwitter APIを直接呼び出すケースだけで、もばついやsobeesのように、Twitter APIを叩くサーバーが中国国外にあるWebクライアントは利用可能なのです。sobeesは現在リリースされているSilverlightアプリケーションの中では最もよく作り込まれているアプリケーションの一つで、TweetDeckと互角か、それ以上に使いやすいアプリケーションと言えるので、中国に行かれる場合はおススメのクライアントと言えるでしょう。ただ、ひとつだけ残念なことがあり、それは、IMEによる変換を行うときに誤動作をするという点。変換を行う時のEnterキー入力で入力が完了したものと勘違いし、そこでTweet送信をしてしまうというバグがあります。そのため、現状では、Tweetはテキストエディタで書いた上で張り付けて送信をせざるおえないという残念な状態です。バグレポートを投げようと思うので、それが対応されたらTweetDeck代替として結構使えるのではないかと思います。

AUG
3

上海から帰還

Published:2009-08-03 23:24:10 UTC

何とか上海から帰ってきました。今回は自分の研究室が提携している研究室のネットワークでの発表会で、自分もちょっと刺激を受けてこい、ということで行かせて貰ったのですが、いやはや向こうの学生のレベルは高かったです。研究内容のレベルはともかくとして(向こうは院生ばかりですから)、英語力の面からみて。中国からはFudan Univ.が、韓国からはKAISTが参加していたのですが、どちらも発表後の質疑応答をちゃんとこなしていて、しどろもどろになってしまった自分とは大違いでした。反省します。。

そういえば、滞在していたホテルが予想に反してあまりに綺麗だったので写真を撮りまくってPhotosynthでの合成表示を試してみました。Silverlightをインストールした上で観てみてください。

JUL
30

ちょっと上海行ってきます

Published:2009-07-30 09:00:02 UTC

提携している研究室同士の研究発表会ということで、2日までの日程で上海行ってきます。まぁ要は、ちょっと海外行って自分の英語の出来なさに打ちのめされて来い、というイベント。ありがたい話です。

JUL
29

Mac始めました。

Published:2009-07-29 01:48:20 UTC
Mac

IMAGE_291 唐突ですが、Mac使いになりました。まさか自分がMacを使う日が来るとは思っていなかったので、自分でも驚いています(笑) SAをやらせて貰ったりと色々とお世話になっている大学の先生からMacBook KUROを貸していただけることになり、今、手元にあのMacが。研究室で同期や後輩が次々にMacに乗り換えているのを見て、「WPFの使えないデスクトップOSなんて使う奴の気が知れないわ~」とかのたまっていたのですが、いちいち画面が綺麗で統一感があり、Macも目的によれば良いかもしれないなーと思ったりしています。これまでずっとWindowsで、全くMacをつかったことがないので、まず操作からしてよくわからないことが多いのですが(GNOMEの方が百倍とっつきやすいです)、躓きながら慣れていこうかと思います。ただ、残念なことに、八月の頭にかけては全く触る暇がなさそうなので、ちょっとの間、放置になりそうではあります。しかしMacかー。どう使ったものか。流石にMacまで来てMonoでC#コードをゴリゴリ書くというのは考えていないのですけど(まぁMonoDevelopは入れるでしょうが)、今更Objective Cとやらを覚えるのもなー、とも思います。なるべく潰しのきかない言語は勉強したくないという思いがあるので、pureなCや、Pythonを書くのに使わせて貰おうかなと思います。

IMAGE_292 しかし貸して頂いているマシン、先生が新しいマシン(勿論Mac)を買ったので使わなくなったから、ということで貸して頂いているのですが、自分のラップトップ(VAIO)よりパワーがあるという。。自分のはVAIO Type SZ53Bをメモリ4GBに増設して使っているのですが、CPUはIntel Core 2 Duo 1.67GHzで、借りているMacBookはIntel Core 2 Duo 2GHz。。なんか、ブートキャンプでWindows 7 RC入れてWindows機としてVAIOをリプレースしたくなるのですが(笑)うーむ。

FILCO FKB108M/NB

IMAGE_294 そしてFILCOのキーボードもお借りしました。いやーこれまでキーボードにはそれほど拘らずにきたのですが、良いキーボードってあるんですね。なかなか打ち心地が滑らかで、変な突っかかりや重さがないので、軽快にタイピングをすることができます。この打ち心地を覚えてしまうと、もう安キーボードには戻れない気がするので、もう少しこのキーボードを試したら、秋葉原でRealforceとかと打ち較べてみて新しいキーボードを自分で買ってみようかと思います。

 

なんか最近、部屋がますますマニアックな雰囲気になってきてヤバいです。。どげんかせんといかん(ぇ

IMAGE_287

CardSafe/EはMVVMパターンに則って作るように心掛けたのですが、WPFと同じ感覚でSilverlightにMVVMパターンを適用しようとすると、色々と不都合が出てきて苦労させられました。Silverlightではオミットされている機能が結構あるので、そこに引っかかるとしばしば手戻りが発生します。このエントリではCardSafe/Eを書いていて気付いた点をとりあえず二点ほど。

SilverlightにはDataTemplate.Datatypeが存在しない

地味に痛いですこの仕様。ItemsControlから派生したコントロール(ListBoxなど)のItemをItemsSourceにセットしたINotifyPoropertyChangedを実装したコレクションから生成する際に、コレクションが列挙するインスタンスの型によってDataTemplateを切り替える場合、WPFではDataTemplate.Datatypeがあるので重宝するのですが、Silverlightでは3 RTWでもサポートされていません。DataTemplateSelectorもサポートされていないので、インスタンスの型や状態によってDataTemplateを切り替えることはできないようです。とりあえず逃げ道として自分はDataContextにセットされたインスタンスをみてContentを書き換えるロジックを書いたUserControlを用意しているのですが、面倒ですね。XAMLで宣言的に書きたいのでDataTemplate.Datatypeは是非サポートしてもらいたいものです。

TabcotrolのItemsSourceはTabItemのコレクションしか受け付けない

なんでー!?これまたあんまりな仕様。WPFではItemsControlから派生したコントロールのItemsSourceにINotifyPoropertyChangedを実装したコレクションをセットすると、その列挙する内容をListBoxItemやTabItemなど適当なコンテナに包んで表示してくれるので、あとはDataTemplateで表示内容を好きなようにカスタマイズしてやればよかったのですが、SilverlightのTabControlのItemsSourceはTabItemのコレクションしか受けてつけてくれないという。。これではTabItemに対応するViewModelのインスタンスをセットし、DataTemplateでViewを設定して表示内容をカスタマイズするというM-V-VMでよく知られたパターンが使えません。SilverlightでもListBoxではListBoxItem以外も受け付けてくれたのですけどねぇ。。ではどうするか。自分の場合はViewModelのコレクションをラップしてTabItemのコレクションとして公開するラッパークラスとConverterを用意することで凌ぎました。

ラッパークラスはこんな感じです。ViewModelのコレクションとViewModelからTabItemへの変換を行うFuncをコンストラクタの引数として取ります。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Controls;

namespace SharpLab.CredentialsLockerSilverlight.ViewModels {
	public class ReadOnlyObservableTabItemCollection<TViewModel, TViewModelCollection> : ICollection<TabItem>, INotifyCollectionChanged where TViewModelCollection : ICollection<TViewModel>, INotifyCollectionChanged {

		private TViewModelCollection _viewModels;
		private ObservableCollection<TabItem> _tabItems;
		private Func<TViewModel, TabItem> _converter;

		public ReadOnlyObservableTabItemCollection(TViewModelCollection viewModels, Func<TViewModel, TabItem> converter) {
			_converter = converter;
			_viewModels = viewModels;
			_tabItems = new ObservableCollection<TabItem>();

			foreach (var item in _viewModels) {
				_tabItems.Add(_converter(item));
			}

			_viewModels.CollectionChanged += new NotifyCollectionChangedEventHandler(_viewModels_CollectionChanged);

			_tabItems.CollectionChanged += new NotifyCollectionChangedEventHandler(_tabItems_CollectionChanged);
		}

		void _viewModels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
			switch (e.Action) {
				case NotifyCollectionChangedAction.Add:
					_tabItems.Insert(e.NewStartingIndex, _converter((TViewModel)e.NewItems[0]));
					break;
				case NotifyCollectionChangedAction.Remove:
					_tabItems.RemoveAt(e.OldStartingIndex);
					break;
				case NotifyCollectionChangedAction.Replace:
					_tabItems.RemoveAt(e.OldStartingIndex);
					_tabItems.Insert(e.NewStartingIndex, _converter((TViewModel)e.NewItems[0]));
					break;
				case NotifyCollectionChangedAction.Reset:
					_tabItems.Clear();
					foreach (var item in _viewModels) {
						_tabItems.Add(_converter(item));
					}
					break;
			}
		}

		void _tabItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
			if (CollectionChanged != null) {
				CollectionChanged(this, e);
			}
		}


		public event NotifyCollectionChangedEventHandler CollectionChanged;

		#region ICollection<TabItem> メンバ

		public void Add(TabItem item) {
			throw new NotSupportedException();
		}

		public void Clear() {
			throw new NotSupportedException();
		}

		public bool Contains(TabItem item) {
			throw new NotImplementedException();
		}

		public void CopyTo(TabItem[] array, int arrayIndex) {
			throw new NotSupportedException();
		}

		public int Count {
			get {
				throw new NotImplementedException();
			}
		}

		public bool IsReadOnly {
			get {
				return true;
			}
		}

		public bool Remove(TabItem item) {
			throw new NotSupportedException();
		}

		#endregion

		#region IEnumerable<TabItem> メンバ

		public IEnumerator<TabItem> GetEnumerator() {
			foreach (var item in _tabItems) {
				yield return item;
			}
		}

		#endregion

		#region IEnumerable メンバ

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}

		#endregion
	}
}

これを以下のようなConverterから利用します。

using System;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Data;
using SharpLab.CredentialsLockerSilverlight.ViewModels;

namespace SharpLab.CredentialsLockerSilverlight.Views.Converter {
	public class CardVMCol2TabItemColConverter : IValueConverter{
		#region IValueConverter メンバ

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
			return new ReadOnlyObservableTabItemCollection<CardViewModel, ObservableCollection<CardViewModel>>((ObservableCollection<CardViewModel>)value,
				(each) => {
					var newTabItem = new TabItem() {
						DataContext = each,
						Header = new CardTabHeaderView(),
						Content = new SharpLab.CredentialsLockerSilverlight.Views.CardView()
					};
					return newTabItem;

				});
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
			throw new NotImplementedException();
		}

		#endregion
	}
}

こうしてやることでTabControlのItemsSourceにViewModelのコレクションをバインドできるようになります。Converterは無理を通すのに便利な機能ですね。。

 ItemsSource="{Binding Path=CardViewModels, Converter={StaticResource CardVMCol2TabItemColConverter}}"