XML-RPC.NETを使ってカスタムフィールドを設定

.NET(C#)でXML-RPCを使ってブログに投稿する | Moonmile Solutions Blog

http://www.moonmile.net/blog/archives/1284 

の続きです。 

xml-rpc.net を使って、wordpress のカスタムフィールドを設定します。 

カスタムフィードってのは、記事に付随する情報で、WEB上でブログを書くときに追加できます。 

20100915_02.jpg 

カスタムなので、文字列ならば何でも入る(BASE64を使えばバイナリも入る)のですが、私がこれを使う理由は、書籍サイトを作る時のページ数とセクション名を入れるんですね。 

これを手作業でWEB上で、ぽちぽち入れるのは非常に面倒くさい。というか、間違えます。 

なので、クライアントツールを使って、一気に落とし込みます。 

xml-rpc.net を使って、カスタムフィールドを送信する場合は、 

    public interface IBlogger : IXmlRpcProxy
    {
        [XmlRpcMethod("metaWeblog.newPost")]
        string newPost(
            string blogid,
            string username,
            string password,
            Content content,
            bool publish);
    } 

    public struct Fields
    {
        public string key;
        public string value;
    }
    public struct Content
    {
        public string title;
        public string description;
        public DateTime dateCreated;
        public Fields[] custom_fields;
    }

な風に、metaWeblog.newPost メソッドを使います。 

カスタムフィールドは配列になっています。 

# List<Fileds> だと駄目だったので、配列しか駄目な模様。 

送信する時は、 

        public void BllogerNewPostWP(string title, string desc )
        {
            //プロキシクラスのインスタンスを作成
            IBlogger proxy = (IBlogger)
                CookComputing.XmlRpc.XmlRpcProxyGen.Create(
                typeof(IBlogger));
            //URLを指定
            proxy.Url = url;
            Console.WriteLine("url: " + url);

            string id = "";
            // content を生成
            Content cont;
            cont.title = title;
            cont.description = desc;
            cont.dateCreated = DateTime.Now;
            cont.custom_fields = new Fields[2];
            cont.custom_fields[0].key = "page";
            cont.custom_fields[0].value = "10";
            cont.custom_fields[1].key = "section";
            cont.custom_fields[1].value = "1.1.1";
            try
            {
                Console.WriteLine("title: " + title);
                //blogger.getRecentPostsを呼び出す
                id = proxy.newPost(
                    "1",            // 念のため1にしておく
                    username,
                    password,
                    cont,
                   true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("エラー:" + ex.Message);
                return;
            }

            //結果を表示する
            Console.WriteLine("id: " + id);
        }

という感じです。 

フィールドの生成が、ちょっと不様ですが、まあ、所詮ツールなので。 

これを実行すると、無事カスタムフィールドが設定されます。 

20100915_03.jpg 

次は、これらを使ってコマンドラインから記事の投稿ができるようにします。 

方法としては、 

  1. テキストエディタで編集する。
  2. 適当なツールを通して、HTML形式へ変換する。
  3. 適当なツールを通して、ヘッダ部を付ける。
  4. 投稿ツールで、wordpress へ投稿。

みたいな感じです。 

投稿するときのフォーマットは、俗にいう mail フォーマットで、ヘッダ部とボディ部に分けます。 

ID:   <記事のID> ... 編集時に使う
Date:   <投稿日時>
Title:  タイトル
Page:   <該当ページ>
Section:  <章番号>

本文が続く
...

のような感じ。 

ID:   100
Date:  2010/09/15 12:00:00
Title:  Linux初心者の基礎知識
Page:   2
Section: 1.2

<H3>ハードディスクのデバイスファイル名</H3>
<p>
ハードディスクには、SCSI、IDE、SATAなどがありますね。
Linuxからみると、デバイスファイル名といいまして、
</p>
<pre>
IDEは「/dev/hda」など
SCSI,SATAは「/dev/sda」など
</pre>
となります。

のようなフォーマットで送れるようにする予定です。

カテゴリー: Wordpress | XML-RPC.NETを使ってカスタムフィールドを設定 はコメントを受け付けていません

wordpressのXML-RPCレスポンスが欠ける

ちと、メモ的に。

IIS 7.0 上に WordPress 3.0 を入れた状態で、XML-RPC を使って投稿しようとすると、レスポンスが2バイト欠けます。

故に、

Response from server does not contain valid XML.

なるエラーが出ます。

XML-RPC.NET ライブラリを試しても、BlogWrite を試しても駄目なので、おそらく、IIS + PHP + wordpress の組み合わせが駄目です。


<?xml version=”1.0″?>
<methodResponse>
  <params>
    <param>
      <value>
        <array><data>
  <value><struct>
  <member><name>isAdmin</name><value><boolean>1</boolean></value></member>
  <member><name>url</name><value><string>http://localhost/wp/</string></value></member>
  <member><name>blogid</name><value><string>1</string></value></member>
  <member><name>blogName</name><value><string>local blog</string></value></member>
  <member><name>xmlrpc</name><value><string>http://localhost/wp/xmlrpc.php</string></value></member>
</struct></value>
</data></array>
      </value>
    </param>
  </params>
</methodRespons

こんな風に最後の2バイトが欠けます。おそらく、UTF-8 BOM の分だけ加算し忘れて、content-length が間違っているかと。

同じソースを動かしても、linux 上の wordpress は ok です。

ソース自体は、

.NET(C#)でXML-RPCを使ってブログに投稿する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1284

を参照。

エラーの回避方法は分からず。

環境としては、

  • windows 7
  • PHP 本家(MSのPHPではない)
  • WordPress 本家(MSのPHPではない)
  • IIS 7.0

ですね。他の組み合わせでは未定です。

追記 2010/09/14

解決法を見つけました。

wp-includes/class-IXR.php の 339 行目あたりに、XML-RPCのレスポンスを返しているので、


        // Create the XML
        $xml = <<<EOD
<methodResponse>
  <params>
    <param>
      <value>
        $resultxml
      </value>
    </param>
  </params>
</methodResponse>



EOD;
        // Send it
        $this->output($xml);
    }

のように、</methodResponse> の後ろに2バイト分、改行を増やしてやります。

本来はlengthを変えるところなのですが、乱暴ですが、これでIISでも動きます。

カテゴリー: Wordpress | 4件のコメント

wordpress のカテゴリ一覧をアメブロ風にする

wordpress を使って独自サイトを作ろうと思って、いくつか調べ。

どうやら、wordpress 3.0 からは、いくつかテンプレートが違っている模様で、と言いますか、PHP 初心者なものだから、何処から始めても良いということで。

Main Page – WordPress Codex 日本語版
http://wpdocs.sourceforge.jp/

カスタマイズするには、上記のサイトから始めればいいらしいです。

まぁ、この手のカスタムはコードを読んで諸々を進める訳ですが(他人様のコードのデバッグと同じですね…デバッグとは違うけど)、wordpress 3.0 から、ちょっと面白い仕組みが備わっているので紹介。

投稿したい記事を表示したり、一覧を表示したりするページをカスタムする場合、大抵はテーマのphpを直接編集すると思います。と言いますか、修正しちゃうのが「テーマ」ですよね。

けれど、wordpress 3.0 の標準で付いてくるテーマはこんな仕組みになっています。

cotegory.php を見ると

<001>


<?php
/**
 * The template for displaying Category Archive pages.
 *
 * @package WordPress
 * @subpackage Twenty_Ten
 * @since Twenty Ten 1.0
 */

get_header(); ?>

  <div id="container">
   <div id="content" role="main">

    <h1><?php
     printf( __( 'Category Archives: %s', 'twentyten' ), '<span>' . single_cat_title( '', false ) . '</span>' );
    ?></h1>
    <?php
     $category_description = category_description();
     if ( ! empty( $category_description ) )
      echo '<div>' . $category_description . '</div>';

    /* Run the loop for the category page to output the posts.
     * If you want to overload this in a child theme then include a file
     * called loop-category.php and that will be used instead.
     */
    get_template_part( 'loop', 'category' );
    ?>

   </div><!-- #content -->
  </div><!-- #container -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

な風に、get_template_part 関数なるものが用意されています。

これ、通常は、loop.php を呼び出すのですが、loop-category.php を用意すると、そっちの php ファイルを呼び出す、なかなか面白い仕組みです。

C# を知っていると、デリゲートに似ていると言えます。

ループの中身を後から、インジェクション(挿入)する仕組みですね。

これによって、便利なのは、

  • このテンプレートをバージョンアップしても、loop-category.php は上書きされない(自作だから)ので、そのままテンプレートをバージョンアップできる。
  • 他のテンプレートを適用しても、同じ仕組みであれば、loop-category.php を使い廻しできる。

という再利用性の問題がクリアできる点です。

PHP の場合、手軽にソースを書き換えられる分、それぞれのユーザー(プログラマ)がカスタムしているところを、どうやってバージョンアップするのか?という回答になっていますね。

C# な話だと、

  • インターフェースを作っておいて、DLLを動的にロード

な形になります。

さて、

この category-loop.php に至ったのは、カテゴリの一覧をカスタムしたかったからで、通常のカテゴリ一覧だと本文の一部とかが出て、ちょっと閲覧性が悪いんですよね。どうせならば、アメブロ風に一覧で出て欲しい(そのほうがクリックしやすいし)。

という訳で、作ってみたのがこれ。

<002>


<?php
 $cat_name = single_cat_title( '', false );
 $cat_id = get_cat_ID( $cat_name );
 $posts = get_posts("numberposts=1000&order=DESC&orderby=post_date&category=$cat_id");

 if ( $posts ) : ?>
 <table width="100%" cellpadding="0" cellspacing="0" border="0">
  <?php 
   $i = 1;
   foreach ( $posts as $post ) :  setup_postdata( $post );
  ?>
   <tr>
    <td><?php echo $i ?></td>
    <td>
     <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></td>
    <td><?php echo $post->post_date; ?></td>
    <td>コメント(<?php echo $post->comment_count; ?>)</td>
   </tr>
  <?php
   $i++;
   endforeach; ?>
 </table>
<?php endif; ?>

ページ送りが無いので、いまいちですが、ひとまずPHP初心者としてはOKかな、と

出来上がりは、こんな感じ。

20100912_01.jpg

スタイルシートを変えれば、もうちょっとマシになるかなと。

同様に、カレンダーで月を選択した場合は loop-archive.php を作ります。

<003>


<?php
 global $wpdb;

 $date = get_the_date();
 $year = intval(get_the_date('Y'));
 $month = intval(get_the_date('m'));
 $day = intval(get_the_date('d'));

if ( is_month() ) {

 $sdate = $year . "/" . $month . "/01";
 if ( $month < 12 ) {
  $edate = $year . "/" . ($month+1) . "/01";
 } else {
  $edate = $year+1 . "/" . 1 . "/01";
 }
 $sql = <<< HERE
select
  *
FROM
 $wpdb->posts  
WHERE
    post_status = 'publish'
and post_type = 'post'
and '$sdate' <= post_date and post_date < '$edate'
order by post_date desc
HERE;
} else {
 $sdate = $year . "/" . $month . "/" . $day;
 $sql = <<< HERE
select
  *
FROM
 $wpdb->posts  
WHERE
    post_status = 'publish'
and post_type = 'post'
and '$sdate' = cast(post_date as date)
HERE;

}

?>
<?php
  $posts = $wpdb->get_results( $sql );
 if ( $posts ) : ?>
 <table width="100%" cellpadding="0" cellspacing="0" border="0">
  <?php 
   $i = 1;
   foreach ( $posts as $post ) :  setup_postdata( $post );
  ?>
   <tr>
    <td><?php echo $i ?></td>
    <td>
     <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></td>
    <td><?php echo $post->post_date; ?></td>
    <td>コメント(<?php echo $post->comment_count; ?>)</td>
   </tr>
  <?php
   $i++;
   endforeach; ?>
 </table>
<?php endif; ?>

データベースを直接弄っているのは、それらしい関数がなかったので。

デザイナさんが改修すると、さすがに SQL 周りは触れないのでは?と思うので、プログラマが wordpress を弄るとこんな風に、という例として。

という訳で、table タグを使っているのは、ご愛嬌ということで。

カテゴリー: Wordpress | 2件のコメント

年賀状ソフトができましたよ

ここ1週間ほど、乃木坂に来ていますが、やっとこさ、年賀状ソフトが完成しました。

いえ、完成とは言っても、デザイナさんの画像の差し替えなんですけどね。

付属のCD-ROM/DVDに、年賀状ソフトがついています。

20100910_01.jpg

来年は、うさぎ年という訳で、うさぎな画像が満載です。

CD-ROMに入っている、背景の画像を選択して、自前の写真を差し込みすると、この通り

20100910_03.jpg

そのまま、はがきの裏面に印刷できます。

でもって、住所録も装備。簡易版ではありますが。

20100910_04.jpg

パソコンにあるフォントを使って、書き換えることもできます。

20100910_05.jpg

秀和システムさんから、9月末ごろに、

  • デジカメ年賀状
  • 世界一おしゃれな年賀状
  • そのまま使えるスペシャル年賀状
  • そのまま使える年賀状データ大全10000

で書店に並びます。

不具合、要望なんてのがある場合は、秀和システムさんにメールにて、あるいは、直接メールなどでどうぞ。

カテゴリー: ツール | 年賀状ソフトができましたよ はコメントを受け付けていません

提供するサービスを量産するということ

巷で話題になっているので、メモ的に。

私はこうやってWebサービスをリリースしてきました。|ホットココア社長日記 @egachan
http://blog.livedoor.jp/ikiradio/archives/51525122.html

たった2週間でWEBサービスを6つ立ち上げる究極の方法!|ホットココア社長日記 @egachan
http://blog.livedoor.jp/ikiradio/archives/51026443.html

実は、2年前の記事を見たことがあるんですよね。

Web サービスの大量生産…というか、2週間で出来てしまうのはどうかなぁ、と思っていたのですが、2年後の記事を見れば、「量」というのは、それなりに人を圧倒します。

いや、「継続は力なり」ということで、成功ってのは、やり続けることの先にしかない、ってことです。

# 4月に会社を作ったそうなので、これから、って感じではありますが(些細ながらエールということで)

ちなみに、無料のWEBサービスを公開する理由は、会社の場合は、

  • 技術アピール、広告塔の役割
    → WEB製作の請負や、コンサルティングなどで収入を得ます。
  • 広告収入
    → PVを稼いで、他社から広告収入を得ます。
  • 有料会員サイト
    → 一部は無料、有料になって月額で収入を得ます。

作る側としては、定額の収入が得られるので、有料会員サイトが有力候補なのですが、サイト自体からは収入を得ず、広告塔として使うのもベターかなと思っています。株式会社ホットココアの場合は、広告塔のパターン(と思う)。

ちなみに、

WEBサービスが量産できるようになったのは、ここ最近の話で、5年前ぐらいからOSSの普及や、公開API、レンタルサーバーが非常に安くなった、ところがあげられます。

プログラムでもWEBサービスでも量産して、公開して、の流れが良いところは、

  • フィードバックが得られる、あるいは、フィードバックが得られない。
    → 得られないのは、「駄目」ということで、早めに切り捨てられる。
  • あれこれと、悩まずに済む、あるいは、妄想せずにすむ。
    → 取らぬ狸、にならずに済みます。
  • 技術力が付く
    → 単純に作るときの体力が付きます。経験値が上がるので、作るのが早くなります。

WEBサイトを作る、プログラミングができる人の最大の利点は、作って試せるところにあります。先の記事にもありますが「口だけではなんにも動かない」(口だけのコンサルタントになりたい場合は必須な技術なんですが)。

実際、モノを作ってみると、どれだけその素晴らしいアイデアが「無様な」ものなのかが分かります。そういう「無様な」ものってのは、人から見るとそう見える訳で、客観的な視点を得られます(精神的なダメージも大きいけど)。

まぁ、そういうものに晒されて、耐えたものが、そこそこ残る「商品」なのかな、と。

カテゴリー: 雑談 | 2件のコメント

極めるという事を少し

ちびっと雑談レベルで。

コニカさん経由で知ったSALONさんなブログですが、

WEB系技術電脳日記
http://ameblo.jp/konica/
OC SALON POWER STATION
http://ameblo.jp/oc-salon/
J . C . A
http://ameblo.jp/duck-oc/

まだお会いしたことはないのですが、OverClock な仕事(なのかな?)をしばらく見ていて思ったことを。

オーバークロックって16MHzの頃ぐらいしか分からなくて、当時はちびっとでもクロック数を上げようとして発信器を変えたりなんぞがありました(私自身はやったことはないのですが)。最近は、2GHzとか格段に早くなったもので、昔のようにちびっと上げてる感じでは実用的には意味がないよなぁ、と思っていたものですが。

う~む。1か月ほど眺めていたのですが、なんか迫力が違う。つーか、オーバークロックという狭い範囲(失礼)でも極めていくと、世界に通用する、つーか、duck さんという世界一な方も近くにちらほら。

一般の人にはCPUとかGPUのオーバークロックなんて全然意味が無くて、全く興味のない話な訳ですが、そりゃあ、クラウドやらSiverlightやらiPhone/iPadやらのほうが、宣伝的に良いというか最新技術っぽいというか、そういう「目新しさ」があります。
が、そういう「目新しさ」とは別のところに、個人的な価値(大袈裟に言えば、個人の人生だったり、個人を巡る周辺の方々だったり)が歴然としてあるわけで。当然「目新しさ」という基準や、「社会的な宣伝」(社会的な貢献みたいなものも含めて)という基準もあろうというものですが、まぁ、それはそれ、これはこれ、なのかなぁ、と昨今思っています。

まあ、これは、私が会社を辞めているからだと思うし、自営業というスタイルだからと思うのですが。

「極める」というか、根本的に人は「自由」なところにあると思っています。「自らを由縁とす」という約仕方をすれば、最初の身の置き所が自分自身にあり、それが徐々に「不自由」になるごとに由縁の部分が外部に出てしまうという感じですね。
それで、自分の想うままにということろで、身勝手に見えたり、極めることに見えたり、はたまた破綻したりという現実があるわけですが、大衆という形のないもの、「有識者」という形のないもの、「最新技術」という拠り所がないもの、よりは、オーバークロックという一見よくわからない(いや、やっぱりよくわからんけど)もののほうが、地に足が付いているように見えるのが不思議なところです。

と、当たり前のことを考えてみました。

カテゴリー: 雑談 | 2件のコメント

WindowsからMacへssh接続する

基本は、Windowsからmac mini へ VNC 接続するんだけど、やっぱりコマンドラインがいいかな、と。

VNC接続ができていると、既にmac側で「リモート接続」が有効になっているので、teraterm で ssh がつながるはずなのだが、うまくつながらない … かと思ったら、こんな落とし穴が。

普通は TeraTerm を起動して、SSH で接続。

20100902_01.jpg

ユーザ名とパスワードを入力すればOKなはずなんですが…

20100902_02.jpg

何故か、時間が経った後に、エラーになってしまう。

20100902_03.jpg

で、色々探したものの、他の人はつながるみたいなんですよね。。。

何故、私の mac mini (mac os x 10.6.4)で繋がらないのかぁ、と思っていたのすが、試しに

「チャレンジレスポンス認証」でやると、あっさり

20100902_04.jpg

暫く経つと、パスワードを入れてる画面が出ます。

20100902_05.jpg

そして接続と。

20100902_06.jpg

何故、デフォルトがチャレンジレスポンスなのか分かりませんが、ひとまずこれでつながりました。

ので、めでたしめでたし。

■参考サイト

macにsshdを設定してみた – webとかmacとかいろいろ技術メモ
http://d.hatena.ne.jp/dice-t/20071115/1195187150

 

 

カテゴリー: 開発 | WindowsからMacへssh接続する はコメントを受け付けていません

役所風にEnterキーで次のテキストボックスへ移動

先日、子供の出生届に行ってきたわけですが、まだまだ古いパソコンを使っていましたお役所さん。出生届もインターネット越しでもいいんじゃない?と思ったり、思わなかったりしたのですが、ひょいと、パソコンの画面を見ると懐かしのDOS画面でありました。

役所関係や事務関係では、まだまだ強いですよね、この手のインターフェース。

そんな訳で「タブキーで次のフォーカスに移ればいいじゃん」と思っても「エンターキー(Enter Key)で次のフォーカスに移りたい」訳で、そこには、Silverlight とか、WPF とか、WEB やら jQuery やらの話は出てきません。ひたすら、今の業務にそろえたい訳です。

という訳で、UXってのが「ユーザー体験」ならば、かつてのDOS画面風を再現させたっていいじゃないと思いついたのがこの画面。

<001>

20100901_08.jpg

って、バックを「黒」にして、文字を「緑」にしただけなんですが、もうちょっと工夫が必要ですよね。

  • MS ゴシックのフォントでは字がつぶれるので、もっと適切な固定ピッチフォントで。
  • アルファベット&数字が、きれい過ぎる感じがするので、そのあたりも。

とか。

で、真っ先に実装したいのが Enter キーによるフォーカス移動です。
Enter キーのフォーカス移動は、落とし穴が多くって、少なくとも、

・複数行のテキストボックスが入ると破綻する。
・漢字の確定の Enter キーと、アルファベットの入力途中の Enter キーを区別する。
・1行のテキストボックスだと、Enter キーでビープ音が鳴る仕様。

があります。

複数行のテキストボックスの場合は、かつての画面ってこのパターンはなかったんですよ、考えてみれば。DOSで業務画面を作る場合は、テキストのスクロールとかもなくて、大抵の場合、複数行の入力なんてのもありません。

となれば、ちょっと、業務画面チックに Enter キーを変えていくのも良いかと。

{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

#if true
            // ひとつずつ登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);
#else
            // 全てのコントロールを登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);
#endif

        }

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }
    }

    /// <summary>
    /// Enterキーで移動させるためのクラス
    /// </summary>
    public class EnterKeyManager
    {
        private List<Control> m_lst = new List<Control>();
        private bool imeEnter = false;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public EnterKeyManager()
        {
        }

        // テキストボックスを追加
        public void Add(TextBox ctrl)
        {
            ctrl.PreviewKeyDown += new PreviewKeyDownEventHandler(ctrl_PreviewKeyDown);
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            ctrl.KeyPress += new KeyPressEventHandler(ctrl_KeyPress);
            m_lst.Add(ctrl);
        }
        // テキスト以外を追加
        public void Add(Control ctrl)
        {
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            m_lst.Add(ctrl);
        }

        // テキストボックスでEnterを押した時、BEEPが鳴るのを防ぐ
        void ctrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                e.Handled = true;
            }
        }

        // タブキー移動のハンドラ
        public delegate void EnterKeyEventHandler(object sender, bool b);
        // Declare the event.
        public event EnterKeyEventHandler ProcessTabKeyEvent;

        // Enterキーの処理
        void ctrl_KeyUp(object sender, KeyEventArgs e)
        {
            if (ProcessTabKeyEvent == null)
                return;

            if (e.KeyCode == Keys.Enter)
            {
                TextBox t = sender as TextBox;
                if (t == null)
                {
                    ProcessTabKeyEvent(sender, !e.Shift);
                }
                else
                {
                    if (e.Shift)
                    {
                        ProcessTabKeyEvent(sender, !e.Shift);
                        e.Handled = true;
                    }
                    else
                    {

                        if (imeEnter == true)
                        {
                            ProcessTabKeyEvent(sender, !e.Shift);
                            e.Handled = true;
                        }
                        imeEnter = false;
                    }
                }
            }
        }
        // 日本語の変換確定のEnterを区別する処理
        private void ctrl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            TextBox t = sender as TextBox;
            if (t != null)
            {
                if (e.KeyData == Keys.Enter)
                {
                    imeEnter = true;
                }
            }
        }

        // フォームから全てのコントロールを設定する
        public void SetForm( Form frm )
        {
            foreach (Control c in frm.Controls)
            {
                TextBox t = c as TextBox;
                if (t != null)
                {
                    this.Add(t);
                }
                else
                {
                    this.Add(c);
                }
            }
        }
    }
}

EnterKeyManager クラスってのを作ってしまいます。
このクラスに、Enter キーで移動したいコントロールを Add メソッドで登録していくか、面倒な場合は Form そのものを渡してしまうか。

ひとずつ登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);

フォームにあるコントロールを一括で登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);

イベントで、ProcessTabKeyEvent を登録しているのは、フォーカス移動のメソッド ProcessTabKey を呼び出すためなんですね。ProcessTabKey メソッドが protected になっているので、こんな風にしています。
リフレクションを使えば EnterKeyManager クラスに抑え込むことができるかもしれませんが、まあ、ひとまず。

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }

な感じで、イベントを受けたら呼び出してくださいということで。

エンターキーのフォーカス移動では、漢字の変換を確定したときの Enter キーと区別するのが結構面倒なので、晒しておきます。

電話番号入力とか、数字のみとか、フォントを固定ピッチにしてよりDOSらしくとか、ちょっと作ってみようかな、と思案中です。

■参考サイト

Enterキーを押した時に、まるでTabキーを押した時のように、次のコントロールにフォーカスを移す: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/enterliketab.html#section1

全ては時の中に… : 【VB.NET】Enterキーで次のコントロールにフォーカスを移す
http://blog.livedoor.jp/akf0/archives/51318097.html#

@IT:.NET TIPS Windowsアプリケーションで[Enter]キーによるフォーカス移動を行うには? – C# VB.NET Windowsフォーム
http://www.atmarkit.co.jp/fdotnet/dotnettips/231winentermove/winentermove.html

単一行テキストボックスでEnterやEscapeキーを押した時にビープ音が鳴らないようにする: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/tbsuppressbeep.html

カテゴリー: 開発 | 2件のコメント

.NET(C#/VB)で、アプリ設定を読み書き

従来、Windowsアプリケーションの設定は、レジストリを使ったり、*.iniファイルを使ったりしていたわけですが、最近は、xml が主流です。と言いますか、レジストリだったり xml だったりアプリケーション毎にばらばらです。

そんなモノだから、設定関係で誤射しそうな方も出て来ます。

なので、少し裏技ちっくですが、手軽にxmlから読み書きする方法を晒しておきます。

最初に画面はこんな感じ。

<001>

20100901_03.jpg

右のグリッドは、プロパティグリッド(PropertyGrid)と言ってお手軽にクラスのプロパティを変更できるものです。Visual Studio でも使われていて、この手の変更にぴったりなのです。

そんな感じで、xmlアクセスはこんな感じ。

using System.IO;
using System.Xml.Serialization;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // 初期値
        setting = new MySetting();
        this.propertyGrid1.SelectedObject = setting;
    }

    // アプリケーションの設定
    MySetting setting;

    // 保存
    private void button1_Click(object sender, EventArgs e)
    {
        setting.Save(“setring.xml”);
    }
    // 読み込み
    private void button2_Click(object sender, EventArgs e)
    {
        setting = setting.Load(“setring.xml”);
        // プロパティグリッドに再設定
        this.propertyGrid1.SelectedObject = setting;
    }
}
   
/// <summary>
/// 設定用のクラス
/// </summary>
public class MySetting
{
    // 設定を保存
    public void Save(string filename)
    {
        XmlSerializer xs = new XmlSerializer(this.GetType());
        FileStream fs = new FileStream( filename, FileMode.Create );
        xs.Serialize(fs, this);
    }
    // 設定を読み込み
    public MySetting Load(string filename)
    {
        XmlSerializer xs = new XmlSerializer(this.GetType());
        try
        {
            FileStream fs = new FileStream(filename, FileMode.Open);
            MySetting me = (MySetting)xs.Deserialize(fs);
            return me;
        }
        catch
        {
            // 最初の場合は初期値
            return new MySetting();
        }
    }
    // 以下 public で設定を羅列

    // 数値
    public int X { get; set; }
    public int Y { get; set; }
    // 文字列
    public string Version { get; set; }
    // 構造体
    public Point XY { get; set; }
    // 更新日時
    public DateTime UpdateDate { get; set; }
}

設定用のクラス(MySetting)を作っておきます。
設定の保存は、Saveメソッドで、シリアライズで出力。
設定の読み込みは、Loadメソッドで、シリアライズで入力。

設定自体は、public プロパティを作っておきて、何処からもアクセスできるようにします。こういう風に、構造体も使えるので結構便利。

シリアライズされたXMLファイルはこんな感じ

<?xml version=”1.0″?>
<MySetting xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema“>
  <X>100</X>
  <Y>200</Y>
  <Version>1.0.0</Version>
  <XY>
    <X>10</X>
    <Y>20</Y>
  </XY>
  <UpdateDate>2010-09-01T11:46:30</UpdateDate>
</MySetting>

このファイルを手書きで書き換えることもできるので、お手軽の設定の変更ができます。

参照先はこちら

@IT:.NET TIPS PropertyGridコントロールを利用するには? – C# VB.NET Windowsフォーム
http://www.atmarkit.co.jp/fdotnet/dotnettips/285propertygrid/propertygrid.html

PropertyGridコントロールの使い方: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/propertygrid.html#use

オブジェクトの内容をXMLファイルに保存、復元する: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/file/xmlserializer.html

 

カテゴリー: 開発 | 3件のコメント

DataSetを使ってMySQLを扱う場合の勘所

タイトルに「MySQL」とありますが、旧来のDataSet/DataTableを使う場合のコツ、と思ってください。
# SQL to LINQ や ADO.NET Entity Framework を使う場合は、もうちょっと別なスタイルもありです。

業務アプリケーションでデータベースを扱う場合、利用方法は次のパターンに分けられます。

<001>

20100831_04.jpg 

データベースは次の2種類

・更新系のテーブル
 → 頻繁に更新するデータ
 → 売上データ、月次データなど
・マスター系のテーブル
 → ほとんど更新しないデータ
 → 部門情報、会社名一覧など

これを操作する画面が次の2種類

・一般の画面
 → 主に更新用のテーブルを扱う画面
 → 一般ユーザーが使うので、利用しやすい画面にしないと駄目
・マスタ画面
 → 主にマスタ系のテーブルを扱う
 → 保守に利用するためなので、チープ画面でよい。SEが使う。

これで、DataSetを直接扱うと良いのが、図のなかで「D」(DataSet)となっているところです。

・一般画面から更新系DBへ
 → キャッシュとして、DataSetに保持しておく。
 → 部門の一覧をコンボボックスで表示とか。
・マスタ画面からマスタ系DBへ
 → グリッドやリストなどの自動バインド(DataSource)にDataSetを直接指定。
 → DataSetの内容を直接マスタに書き込んでしまう。

一般画面から更新系DBへの矢印は、SqlCommandを使ってちまちまと更新します。
ちまちま更新は、ストアドプロシージャにしてもOK。しなくてもOK。パラメータは必須(にすると良い)。

このパターンを、MVCに当てはめると(というか、ベースがMVCなのです。このパターン/考え方は2000年頃から使っている)、

<002>

20100831_01.jpg

画面のほうは、いわずもがなの「View」、
参照系のキャッシュ部分は、「Model」、
更新系は直接データベースを扱う(SqlCommandで)ので「Controller」に相当します。

デスクトップ系のアプリケーションを作る場合、VB6(.NETにあらず)の頃は、このデータベースを扱う部分がViewに分散してしまうので、実際の開発(多人数の開発)では、もうひと工夫必要です。

開発プロジェクトの特性として、全てベテランプログラマで揃えらえることはまれです。というか、オープンソースのプロジェクトぐらいしかないでしょう。業務の場合は必ず「新人」と「ベテラン(中堅)」がいます。
そうすると、新人と中堅の技術差があります。あって当然です。

なので、この技術差をうまく活かすために、次のように配置をします。

<003>

20100831_03.jpg

新人は画面側を担当します。これは、新人の弾くスキルでは、画面、SQLなどの両方をこなすのが難しいという点。長期に続いていたプロジェクトだと、データベース周りは既に社内にいる人間しかわからないという状態になっているので覚えることが多すぎるので、できるだけデータベースから遠くに置くためです。
なので、中堅、ベテランは、新人がデータベースを扱えるように「DAO(Data Access Object)」を作ります。このDAOは、O/Rマッピングでも良いし、単なる関数呼び出しでもよいし、手順書でも良いのです。役目としては「新人をデータベースから遠くに置く」ためです。新人は「データベース」を扱いたいのではなく、「データ」を扱いたいのですから。

DAO(Data Access Object)の利点は、このほかにも、

・開発中のデータベース構造が変わっても、DAOが吸収できる(可能性がある)。
・ワンクッションあるので、実行ログがとりやすい。
・ViewにデータアクセスのSQL文が分散するのを防ぐ。

というものがあります。

一例としては、

class DAO会計情報
{
 // マスターデータの参照として使う
 // 直接使えるように公開してしまう
 public DataTable ds部署一覧;
 public DataTable ds会社一覧;
 public DataTable ds取引先一覧;

 // 更新系はメソッドを用意する。
 public bool Update月次( … );
 public bool Update日報( … );
 // 情報を取得する場合とか
 public DataTable Get月次一覧( string 個人名 );
}

のようなクラスを用意しておいて、新人には、


list部署一覧.DataSource = 会計情報.ds部署一覧
list会社一覧.DataSource = 会計情報.ds会社一覧
dv取引先.DataSource = 会計情報.ds取引先一覧

で画面を設定させて、保存ボタンを押したときに、

if ( 会計情報.Update月次( … ) == false )
{
 // 何か失敗したので、エラーメッセージ
 return ;
}
// 更新に成功した


な感じで使って貰う、という形です。

適宜、DAOの種類は増やしてください。トランザクション系もDAOに押し込めると、画面からトランザクションを意識しなくてよくなるので便利です。

Update等の戻り値は、本来は例外がいいのでしょうが、bool値とかにするほうが経験的に間違いが少なくなります。新人の「慣れ」によって適宜作ると良いかと。

このDAOの使い方をするとですね、実はテストがしやすいのです。
DAO自体に実行ログを入れるのもそうですが、うまく作ってやるとテストデータをDAOに直接読み込ませることができます。
また、単体でDAOのテストが可能になるので(MVCの良い特徴として)、NUnitなどのUnitTestが使えます。

ええと、一応、欠点も書き並べておくと、こんな感じです。

・テーブルを変更した場合、DAOも書き換わるので、手間が掛かる。
 → 各画面にSQLが散らなくていいけど、DAOが一手に引き受けるので。
・画面系が早く終わって、DAOが出来ていないとテストができない。
 あるいは、DAOのインターフェースを決めないと、画面が作れない。
 → ひとまず、インターフェースだけ先に作って、仮ビルドしてリリースします。
 → なので、DAOを使う場合は、設計が勝負どころです。
・画面が複数社に分かれる時は、DAOが使いづらい。
 → DAOを作成専門の会社/人がいればいいのですが、請負で数社に分かれると大抵破綻します。
 → なので、「身を守るために」自社だけこっそりDAO形式を使う、というのがベターです。

先日のドットネットラボの懇親会でも愚痴りましたが、理想的には「DBA(データベース管理者)」が、データベースアクセス周りを作ればよいのですが、現実問題として日本のソフトウェア業界では無理です。大規模システムの場合、元請け会社がデータベース周りを扱うことが多く、画面やその他の割り振りを子会社/孫会社に振ります。なので、データベース周り(本来DAOの部分)と画面系の部分が、会社/契約として分離されてしまうため、「大手の新人SEがDBA」を担当するという事態が発生しますし、請負→発注元という要求の通りにくいラインが邪魔をしてしまいます。
という訳で、「DBA」を前提としているデータベース技術はちょっと疑問なのですなぁ、と。

ま、それは兎も角、現実的なラインを探さないといけないわけで、最近では、幸いなことにデータベース構造までも丸投げする場合が多いし、MySQLを使った小規模の開発ならば、この手法が使えます。
ので、お試しあれ。

カテゴリー: 開発, MySQL | 2件のコメント