Blog2007年9月27日木曜日プロパティでSystem.Typeを指定したい?(5)今回はConvertTo関係。これでTypeConverterな話は一段落。前々の記事に書いたように「TypeConverterで扱う型・クラスをある型・クラスに変換」な処理を行うのがこのメソッド。使われる場面ってのはプロパティダイアログ・・・ではなく実行時だと思っていていいのかな?いきなりだけど実際のロジック。Functionプロパティに設定されるのはStringによるクラス名なので、それを実際のインスタンス(System.Type)から変換するのが主なお仕事になるね。その際に注意するのが、クラス一覧は名前空間を除去した形で利用したほうがいいということ。そりゃー、ダイアログのあの小さい領域にフルフル名称で表示されていたら見づらいのでね。ここまで準備できればあとは実際のプロパティ側で属性を指定すればOK。しては「とっととサポートうち切って.Netに完全移行」させてしまっていいと思うんだよねぇ。VB6がサポートされないと困る!なんて言っている人たちって、サポートうち切られたからって他OSに移る可能性は低いと思うんだよなぁ。WindowsでVBしか使えない人だから文句を言っているような気がしてならないのよ。この投稿へのリンク2007年9月21日金曜日PowerShellスゲーPowerShellだと、データベースに接続してどうのこうのするスクリプトも.Netな感覚そのままに記述ができるそうで。$command.ExecuteScalar();$connection.Close();バッチスクリプトだけでとんでもなくいろんなことができてしまうんだねぇ。月次更新とか一括更新系はもうAPにする必要すらないのかも・・・。現在ログインしているユーザーの判断あぁ、頭が固くなってきているようで・・・。どのAPIとかクラス使ってできるのかなぁ・・・なんて考えていたけど、一番簡単な手段があった。USERNAME変数を確認」なんでもかんでも自前でやろうとしてしまうのは、よくないクセだなぁ。この投稿へのリンク2007年9月19日水曜日プロパティでSystem.Typeを指定したい?(4)今回はConvertFrom関係。前の記事で書いたように「ある型・クラスから、このTypeConverterで扱う型・クラスに変換」にちなんだ処理を行うのがこのメソッド。System.Type」と変換できればよいので、CanConvertFromメソッドでは、ある型=StringであればTrueを返却するようにコーディングすればOK。Functionこんな感じで大丈夫。ConvertFromメソッドでは実際の変換処理を記述してあげればOK。内部でプロパティでSystem.Typeを指定したい?(3)の時に書いたロジックを使うのでそこも参照してください。Functionこんな具合かな?利用できるクラスの一覧を取得して、一覧に存在するクラスが指定された際にはそのTypeを返却する。一覧に存在しない際はNullを返却する。返却する際には一覧で保持しているクラス名から、実際のインスタンスを生成(System.Activator.CreateInstance)して、そのTypeを取得しています。こんな感じでFrom関係のメソッドも大したことがないのよね。To関係のメソッドもそれほど違いはないので、次回の記事と見比べてもらうといいかも。日本人と外国人との差に、「他の国の言葉でも躊躇無く突撃してくる」というのがある気がする。MSDNフォーラムでそれっぽいスレッドがあったんだよねぇ。機械翻訳かけて投稿したんだろうけど・・・。自分はそこまでできないなぁ・・・。やるなら自力で文章起こさないと気がすまない。この投稿へのリンク重みのない文字SqlServerのMVPな人の記事から。今まで全く知らなかった、こういった「重みの無い文字」。U+32C0とかその類の文字なんて、この記事みるまで存在すら知らなかったwんで、記事ではPowerShellでのソート結果となっているんだけど、なんか雰囲気は.Net全般の様な気がするんだよねぇ・・・。SqlServerだとソートの照合順序指定に関わるからまだ判るけど、シンプルに「文字のソート」全体の話題だとしたら結構面白い問題かも。アレな人じゃないとこんな文字打たないだろうけど。この投稿へのリンク2007年9月15日土曜日ヘッダの拡張・・・どうするよDataGridView本体は色々拡張しているんだけど、未だに拡張を行っていない部分があるんだよねぇ。「どうデザインさせるか」とかを考えると、エディタ作れるようにならなければ厳しい部分があるんだよねぇ。自分が使うだけならどうとでもやるんだけど、他の人が使うのが大前提だからなぁ。この投稿へのリンク2007年9月13日木曜日プロパティでSystem.Typeを指定したい?(3)前回書いた6つのメソッドの中で、まずはGetStandardValuesメソッドとGetStandardValuesSupportedメソッドから。「標準値リスト」を提供する部分に関わるメソッドで、IDE側ではGetStandardValuesSupportedメソッドがTrueを返した際に、GetStandardValuesメソッドでドロップダウンリストに表示する一覧を取得しにくる、という流れになっているのよ。今回提供したい標準値リストって何が入っていればいいか?と言われると。「自分のプロジェクトと参照設定されているアセンブリなどに存在するクラスの一覧」が目標になるわけだ。同じようなものとしては、DataGridViewのカラムを設定するあたりだね。説明はあとで大体のロジックを。Function中々お目にかからないクラスが多いと思う。IDesignerHostとかITypeDiscoveryServiceとか。言ってしまうと、ITypeDiscoveryServiceインターフェースは「プロジェクトと参照設定されているアセンブリ」に対して探し物をしてくれるクラスが継承しているもの。IDesignerHostインターフェースはMSDNあたりで見てくださいwなのでITypeDiscoveryServiceを利用してクラス一覧を取得、んでその中からインスタンス化できないクラスを除去。一つついでにデザイン時に利用していいクラスかどうか(DataGridViewColumnDesignTimeVisibleAttribute)を判断して一覧を整理してあげればOK。最後の属性を見てってのは特にやらなくても問題ないケースが多いかな。デザイン時には非表示だけど実行時には使いたいようなクラスを自前で用意するような、そんな面白いケースになった時にこの属性を使ってあげていればいいんだけどね。今のところであってません、そんなケースにはwこれで標準値リストについては大体OK。考えるとSystem.Globalization関係って使っていたほうが楽になりそう。和暦→西暦変換とか西暦→和暦変換もOSの機能で用意されているものを利用できるんだよね、こっちだと。Cultureの中でCalendarクラスのインスタンスを持っているんだけど、こいつが色々用意されているのよ。和暦用にJapaneseCalendarクラスとかもあるんで。この投稿へのリンク2007年9月12日水曜日ISO86011週間というものを定義しているISOがあるなんて知りませでしたよ、ええ。日以上かかる週になるように指定します。」なんてルールに基くので、1月2日が土曜日なんて場合は、1/1~1/2は「前年度の最終の週」という扱いにするそうだ。第x週の扱いを調べているとこんなのが出てきて少々驚き。この投稿へのリンクプロパティでSystem.Typeを指定したい?(2)プロパティでTypeConverterを利用したデザイン時サポートを行う際には、System.ComponentModel.TypeConverterクラスを継承して実装していくのが楽なんだと思う。実際には大した作業量の違いはないかも知れないけど。このクラスのメソッドで実装する必要になるのは次にあげるものくらい。GetStandardValuesSupportedメソッドGetStandardValuesメソッドCanConvertFromメソッドCanConvertToメソッドConvertFromメソッドConvertToメソッド上にあげた6つのメソッドは、実際のところ2つ*3組という考え方で捉えるといいかも。GetStandardValuesSupportedメソッドとGetStandardValuesメソッド。これはプロパティダイアログでドロップダウン型の時に関わってくるメソッドで、「標準値リスト」というのをサポートするかどうか、という関連で利用されるね。GetStandardValuesSupportedメソッドでTrueを返却するなら標準値リストをサポートする、Falseならサポートしないという風にIDE側で判断するのに使われます。ドロップダウン型は標準値リストをサポートする時だけ利用できると思っていればいいかな。そのリストに設定される値一覧がGetStandardValuesメソッドで取得できる、と。CanConvertFromメソッドとConvertFromメソッド。これは「ある型・クラスから、このTypeConverterで扱う型・クラスに変換」という処理に関連している。変換可能な場合はCanConvertFromメソッドでTrueを返却して、実際の変換処理をConvertFromメソッド内部で行うことになるね。今回みたいなケースでは「文字列からSystem.Type」という変換をすればよし。それと逆の動作をするのがCanConvertToメソッドとConvertToメソッド。こっちは「TypeConverterで扱う型・クラスをある型・クラスに変換」という処理を行うことになる。変換可能であればCanConvertToメソッドでTrueを返却、実際の処理をConvertToメソッドで行えばよし。実際にはConvertFrom程処理は少なくないんだよね、こっち。細かい中身については次回以降で。この投稿へのリンク2007年9月8日土曜日プログラムのセルフアップデートVista以降のOSで一番問題になるのがこれかも。今回のシステムでも(一応)は機能として最新モジュールのコピーやらそういった機能を持たせているんだけど、適切に設定されているセキュリティ、具体的に言うとProgramFilesフォルダ関連にセットアップしだ場合は、セルフアップデート機能は「自分自身」以外は失敗してしまうことになるね。「ProgramFilesはユーザー領域ではなく、システム領域なので勝手に更新されるのはよくない」という事なんだよな。管理者でも読み取りと実行権限しか持たせないってのはよくわかる。実際に対応するとなるとWindowsInstallerかClickOnceなどの純正テクノロジを利用するのがベスト。VistaやWindows2008Serverなどで用意されている救済策を利用して、セットアップ系プログラムと誤認させる手段もあることはあるけど、かなり後ろ向きというかいきあたりばったり。考えると次の3通りになるのかなぁ?システムのAP全てに自己更新機能を持たせる(ClickOnce)特定のタイミングでシステム全体のAPをインストールするmsiを作成し、ActiveDirectoryなどで配布ProgramFilesにインストールさせない(w技術屋としては1か2だけど・・・。Propertyなんて実装してしまえばできるから使っている人は多いと思う。今回の伝票レイアウトな話題でも、それを利用しているんだけど単純にロジック書くだけではちょっと問題があるんですな、DataGridView関連では。それは「InitializeComponentメソッドで処理されないプロパティは、明示的に対応処理を行わないといけない」という問題。DataGridViewで有名どころはデザイン時のRowTemplate関連かな?こいつはデザイン時にプロパティを設定しても、デザイン画面では即座に反映されてくれない。一度表示されている行を消して、その後に戻してあげないといけないんだよね。仕様としてRowTemplate関連は「行を追加する」タイミングでしか適用されないので、仕様通りっちゃーその通りなんですな。これと似ていて、ある種のプロパティはInitializeComponent内部で操作されていないと、実装者がロジックでゴリゴリ対応してもらわないといけない状態になるんだよね。実装者がゴリゴリ、となってしまうわけだ。いうかバグ出してくれそうwではどうするか、というとSystem.ComponentModel.TypeConverterというクラスを利用することになります。これは「変換」を行うためのクラスで、「文字列→インスタンス」とか「インスタンス→文字列」なんてことをするために利用するね。今回ではプロパティダイアログ上で、「クラスを選択→クラス名を文字列で」と「クラス名→System.Type」という機能が必要なので用意することにします。今のところデータベースの文字型項目で容量を考える際、「その項目に必要なバイト数」で領域を定義していると思うんだけど、今後を考えるとこのやり方では非常にマズイというか。CHARやVARCHAR世代は主にバイト数でカウントする世代で文字コードなんてものは全然考えていない場合が多い。文字コードを考え出して、「バイト数で定義なんてできねーよ」となってでてきたNCHARやNVARCHAR世代は、文字数でカウントする世代だね。後者の「文字数で定義」になれている人ならサロゲートペアがこようと基本は問題ない。(内部的にバイト数を利用していたりしなければ)そしてもう一つの問題がVistaより可能になった「UniCode文字結合」。゙」は同一に扱うという問題。本当に厄介なのはこっちかも知れない。Vistaからなんだから。対応としては、文字列を扱うときにはカルチャを意識してロジック組まないといけないってことだそうで。文字を結合するのは現状と同じでいいけど、比較するときにカルチャを指定するってこと。これを踏まえると文字列比較用のメソッドを、今のうちに用意しておいたほうがいいってことなんだよねぇ。ちなみに文字結合はSqlServer2005では対応されている。゙」もちゃんと条件にひっかかってくれる。この投稿へのリンク2007年9月4日火曜日シマンテックやるねェ!サーバープログラムをアンインストールするとプログラムフォルダの内容が削除されるシマンテックが久々に放ったホームランwいやぁ、こりゃ豪快すぎる。その3Paintメソッドでイメージを表示させるにあたってもう一つ考えておく必要がある話題が。いうのも、このPaintメソッド自体はやたらめったらに呼ばれるから。「マウスを動かす」「キーを押す」などDataGridViewでちょっとでも変更が起きそうな際には必ず呼ばれる。そのあたりを考慮しておかないと、もともとコストの高いイメージキャプチャ処理なので重いAPとなってしまうわけだ。何をもって判断してあげればよいかというと。DataGridViewElementStatesDataGridViewCellStyleこの二つ。DataGridViewElementStatesは引数elementstateに設定されて、DataGridViewCellStyleは引数cellstyleに設定されてくる。これらの中身をセルレベルで保持させておいて、Paintメソッドの都度引数と保持したものとを比較し、異なる際に限ってイメージのキャプチャと描写処理を行ってあげるのがベターだと思う。・・・多分もう少し適切な方法もあるとは思うんだけど。ちなみにelementstateはEnumなのでそのまま保持だけど、cellstyleはClassなので、cellstyle.Cloneの結果を保持するようにしておく必要があるね。しないと引数と保持しているものが同じものを参照してしまう。Subロジックとしてはこんな感じかと。ここまでの記事で用意した拡張メソッドやらなんやらてんこもりなので、昔の記事も色々と見てください。その2今回はセルクラスの一番のポイント。このメソッドでやることってのは単純で、「DataGridViewの必要な領域にイメージを描写する」ということ。テキスト系のセルであれば、設定されている値とかを画面に描写するし、イメージ系であればそのままグラフィックを描写してあげればいいんだよね。この伝票レイアウトセルの場合、表示したいイメージというのはセル側からではわからないのよ。(実際には編集コントロールにて生成されるユーザーコントロールのイメージを描写したいから)そのためDataGridView.Paintメソッドでは「編集コントロールでホストするコントロールのインスタンスを生成、値を展開後イメージをキャプチャする」という処理が必要になるね。みても重い処理になるのは間違いないところだwユーザーコントロールその2で書いてあるイメージのキャプチャを利用することになりやす。こいつを「値の展開後」に呼び出してあげてキャプチャ、その次にgraphics.DrawImageメソッドで画面に表示というか描写というか。ユーザーコントロールその1で定義した、「値をコントロールへ」と「コントロールから値へ」というイベントはここで呼び出すことになります。あー、なのでイベント用メソッドはProtectedで問題なし、というのは間違いですね。Friendじゃないといけないっす。ちなみにインスタンスを生成した際、親DataGridViewに追加するのではなく、親.TopLevelControl.Controls.Addとしたほうがいいと思われ。そのほうが余分な制御が走らない分いいと思いますわ。追加するインスタンスの座標は-1でも掛けて目に見えない場所にしておくこと。それでPaintメソッドはもう少し話が続くので次回の記事までひっぱります。毎回こんな処理やられたら大変だー、というところです。オートメーションについてKBで公開された記事なんだけど、これを読むと「なんちゅー作りだ」と思ってしまう・・・。原則異なるバージョンの同居を許さない、という思想だからなんだろうけどねぇ・・・。インストール時、バージョンによっては起動時にPROGIDの値を更新してるってんなら、そりゃ毎回挙動が代わるわな。