ラベル .netプログラム の投稿を表示しています。 すべての投稿を表示
ラベル .netプログラム の投稿を表示しています。 すべての投稿を表示

2010年5月22日土曜日

英字ドキュメント読み支援ツール その6

昨日は、疲れてて更新が出来なかったので、本日になってしまいました。
ちょっと飛ばしすぎたかも。

で、今回は、英字ドキュメント読み支援ツールの最終回、アプリケーションの配布です。
(ExpressEditionでは使えないかも、ですが。)

クリックワンスだけです。
インストーラーの方法はいろいろ調べたんだけどやりたいことが出来なかった。
 やりたいこと:代替文字列|DataDirectory|をユーザのアプリケーションデータフォルダに変更すること
 理由:プログラムと同じフォルダにmdfファイルを格納するとUVCの機能により読み込み専用の扱いになってしまう。なので、mdfのインストール先を変更したい。プログラムで使っているSQL Serverのファイル接続に|DataDirectory|を利用しているので、インストール時にこの差し先を変えたいが、、、

クリックワンスについてのみ(覚書としてインストーラの方も記述しておきます。)
こちらは、殆ど設定が要らなくて、ソリューションエクスプローラーから[WindowsFormsApplication44]を右クリック→プロパティを選ぶと出てくる画面の一番下のタブの[発行]が全てです。


最短の手順でおこなうなら、発行場所のフォルダ場所をc:\temp\publishに変えて、[今すぐ発行]ボタンを押すと、c:\temp\publish\setup.exeができる。これを実行すると、インストールできて、スタートメニューに登録される。アンインストールは、プログラムの追加と削除から実行。

少しだけ、インストール設定変更の説明。
[アプリケーションファイル]ボタンでは、インストールするファイルの一覧が出てきます。



(もし配布するなら、認証が面倒なmdfファイルを使うよりモバイルの方の、sdfファイルを使ったほうが良かったかもですね。)

[更新]ボタンでは、発行したものが変わったときに、アプリケーション起動のタイミングで自動更新を行うかの設定。デフォルトでは更新はチェックしない、です。(更新する場合はこのボタンを使います。)
[オプション]ボタンでは、インストール情報のいろんな設定ができるけどすることは無いでしょう。(Webサーバ以外に配布するようにしているんだけど、発行のたびに、ブラウザを立ち上げてページが存在しないという表示されるのがうっとうしいというのなら、オプション設定でブラウザを立ち上げない設定ができるとおもいます。)


以上がクリックワンスです。




続いて、覚書で、インストーラの作成。※これではmdfへの書き込みのところで落ちちゃいますが。。。


こちらはちょっと面倒。
まず、セットアッププロジェクトを追加します。
VisualStudioのメインメニューより、[ファイル]→[新しいプロジェクト]で、表示される「新しいプロジェクト」ダイアログで、[その他のプロジェクト]から[セットアップと配置]のグループから、[セットアッププロジェクト]を選びます。下の方で、[新しいソリューションを作成する]から[ソリューションに追加]に変更して、OKボタン。


セットアッププロジェクトのプロパティウィンドウでは、セットアップの情報を記載できます。
(サブフォルダ名は何にするか?とかプログラムの追加と削除画面に出すメッセージとかアイコンとか、、、)


また、ソリューションエクスプローラで、セットアッププロジェクトを選んだ状態にすると、ソリューションエクスプローラのタイトルバーの直下のツールボタンで、以下のボタンが表示されます。(ボタンの上にマウスカーソルを移動するとボタン名がバルーン表示されます。)
・ファイルシステムエディタ、
・レジストリエディタ、
・ファイルの種類エディタ、
・ユーザインタフェースエディタ
・カスタム動作エディタ
・起動条件エディタ

上のボタンを押すと、対応したエディタが表示されるので、変更が必要な場合はエディタで編集。
今回の場合だと、使うのはファイルシステムエディタだけです。

[アプリケーションフォルダ]を右クリック→[追加]→[プロジェクト出力]を選んで、[プライマリ出力]を追加します。
追加した[プライマリ出力]を右クリック、[...ショートカットを作成]を選択。作成されたショートカットを、ユーザのプログラムメニューにドラッグ&ドロップします。
[アプリケーションフォルダ]を右クリック→[追加]→[ファイル]を選んで、Icon1.ico、Database1.mdf,Database1.ldfのファイルを追加します。




こんな感じで、Setupのビルドをするとsetup.exeと~.msiが出来る。手動でインストールする場合は、どちらをクリックしても同じ。

※上で言ったとおり、セットアッププロジェクトで作成したほうは、ちゃんと動きません。

なんか、こんな感じで終わるのも変な感じですが、一応終了。

次回からは、asp.netでのwebページの練習として、掲示版プログラムを題材にして、
キャッシュ(キャッシュオブジェクトではなく、ページ出力キャッシュの方)
をメインでやってみます。

余裕があれば、これのWindowsフォームクライアントでSQL Server2005のクエリ通知を
利用して、プッシュ型のもの、(更新があるか問い合わせるものではなく。。)を作ってみたいと思います。
今度は、かなりゆったりのペースで。。。


以上です。

2010年5月20日木曜日

英字ドキュメント読み支援ツール その5

今回は、通知領域でのアイコンと右クリックメニューと、大量データ保存に耐えられるストレージを作ります。
まずは、前回の終了時のところから


通知領域でのアイコン表示をさせます。Form1のデザイナ画面で、
ツールボックスの[コモンコントロール]からNotifyIconをダブルクリック。
ソリューションエクスプローラのWindowsFormsApplication44で右クリック→追加→新しい項目で、アイコンファイル"Icon.ico"を追加。
notifyIcon1のプロパティで、Iconをクリック...をクリックして、ファイル選択で、先ほど追加したIcon.icoを指定。
こんな感じ



続いて右クリックで表示するメニューを追加します。
ツールボックスの[メニューとツールバー]より、COntextMenuStripをダブルクリック
[Windows表示]のメニューを追加、追加メニューの(name)プロパティをShowWindowToolStripMenuItemとする。


notifyIcon1をクリックしプロパティContextMenuStripにさっき追加したcontextMenuStrip1を指定する。

実行すると、左下通知領域にアイコンがでて、これを右クリックするとメニューが表示されることを確認。




続いて、ストレージの件。
まずは、プロジェクトアイテムを追加。
【ウィンドウ追加】
ソリューションエクスプローラで、WindowsFormsApplication44を右クリック→追加→Windowsフォームをクリックし、そのまま追加ボタンを押して、Forms3.csを追加。
【ストレージ追加】
ソリューションエクスプローラで、WindowsFormsApplication44を右クリック→追加→新しい項目をクリックし、サービスベースのデータベースをクリック、Database1.mdfと表示されている状態で、追加ボタンをクリック。直後に表示されるデータソース構成ウィザードではすぐにキャンセルボタンを押す。
続いて、サーバエクスプローラを表示。今の状態はこんな感じ。



続いて、格納領域の構造を作成。
サーバエクスプローラで、「データ接続」→「Database1.mdf」の左の+ボタンをクリックして現れるフォルダ一覧より[テーブル]を右クリックし、新しいテーブルの追加をクリック。以下の4列を追加
1列目:列名:Id,データ型:int,NULLを許容しない、IDENTITYの指定:はい、右クリック→主キーの設定
2列目:列名:OriginalText,データ型:varchar(MAX),NULLを許容しない
3列目:列名:TranslateText,データ型:nvarchar(MAX),NULLを許容する
4列目;列名:PageNum,データ型:int,NULLを許容する
5列目:列名:Paragraph,データ型:int,NULLを許容する。
ここまで打ち込んだら[Ctrl]+Sで、テーブル名をTranslationDataとする。


次に、このテーブル(ファイル上のDB構造)に対応するデータテーブル(インメモリのDB構造であるデータセット上のテーブル)を作成する。
データソースタブをクリックする。


続いて、ソリューションエクスプローラからデータソースにしたいもの(Database1.mdf)をクリック。


データソースウィンドウに現れた「新しいデータソースの追加」リンクをクリック。
表示されるダイアログ「データソース構成ウィザード」で、データベース選択のまま[次へ]→データ接続をDatabase1.mdfのまま[次へ]→接続文字列はそのままにして[次へ]→データベースオブジェクトの選択で、テーブルのTranslationDataにチェックを入れて[完了]
これで、データソースにDatabase1DataSetが表示され、ソリューションエクスプローラに、Database1DataSet.xsdが追加される。

続いてDBデータ編集のWindowsフォーム用に先ほど追加したForm3.csを利用します。
デザイナでForm3.csを編集し、ウィンドウサイズを横に伸ばす。
以下の画面の状態から、



データソースの[TranslationData]をドラッグして、Form3にドロップして、こんな感じにします。


続いて、translationDataDataGridViewの大きさ、配置を変更して、
その下部に2つのTextBoxを配置し大きさを調整。(ともにmultilineをtrueに変更)
左のTextBoxのTabIndexの値+1を右のTextBoxのTabIndexの値に設定。


この後、
データソースのOriginalTextをドラッグして、左側のTextBoxにドロップ。
データソースのTranslateTextをドラッグして、右側のTextBoxにドロップ。
それぞれのTextBoxの(DataBinding)にtranslationDataBindingSourceでそれぞれの列がアサインされていることを確認。

最後にForm3の表示をさせる部分を作りこむ。
Form1のデザインに戻って、contextMenuStip1を選択、メニューの[Windows表示]をダブルクリックして、以下のコードを記述。
private void ShowWindowToolStripMenuItem_Click(object sender, EventArgs e)
{
new Form3().Show();
}

で、実行。
NotifyIconを右クリック、メニューよりWindows表示をクリックすると現れるデータ登録画面で、
新規データ登録する場合は、+ボタン。既存行を変更する場合は、その行をクリック。
で、グリッドビューでは入れにくい改行はテキストボックスを使って編集。
行削除は赤色のバッテンマーク。
これらは、すべてオンメモリ上の操作なので、DB(ファイル)に書き出すには、フロッピーディスクマークをクリック。(これで、次開いたときにも、保存したデータが表示される。)


マイクロソフトのWebサービスの翻訳APIを使ってみても面白そうだけど、これは70-529の範囲だと思うので今回はパス。
で、次回は、最後に、今回のもののインストーラを作ってみます。

2010年5月19日水曜日

英字ドキュメント読み支援ツール その4

今回のお題は、メインメニュー、カスタムダイアログ、設定外部ファイル化、ユーザ設定永続化、ユーザ設定のリセット。
まず、設定外部ファイル化から。以下の画面から、



ソリューションエクスプローラのプロジェクトアイコンを右クリック→プロパティでプロジェクトのプロパティを開く。次に、設定タブをクリック。
設定で、
名前/型/スコープ/値を
Splitter1Distance/int/ユーザー/600
Splitter2Distance/int/ユーザー/800
Web1Url/string/ユーザー/PDFファイルパス
Web2Url/string/ユーザー/翻訳ページ1Url
Web3Url/string/ユーザー/翻訳ページ2Url

を設定した後、[Ctrl]+Sで保存(上のタブの*マーク(編集中)を外す。)


で、ユーザー設定が完了。
次はプログラムでこの設定を使います。

Form1の青いタイトルバーをダブルクリックして、Loadイベントハンドラを記述。ここで、ユーザ設定を利用して設定することにします。

private void Form1_Load(object sender, EventArgs e)
{
splitContainer1.SplitterDistance = Properties.Settings.Default.Splitter1Distance;
splitContainer2.SplitterDistance = Properties.Settings.Default.Splitter2Distance;
webBrowser1.Url = new Uri(Properties.Settings.Default.Web1Url);
webBrowser2.Url = new Uri(Properties.Settings.Default.Web2Url);
webBrowser3.Url = new Uri(Properties.Settings.Default.Web3Url);
}

後は、先回デザイナー画面で設定したWebBrower1,2,3のUrlを空にして実行してもそれなりに表示されることを確認。


続いて、メインメニューを追加。


Form1の青いタイトルバーをクリックし、Form1を選択した状態で、
ツールボックス→メニューとツールバー→MenuStripダブルクリック。


もし、WebBrower1の垂直スクロールバーの上の△がメニューに被っていたら、ドキュメントアウトラインを使って、以下の画面のように、SplitContainer2を、menuStrip1の上にくるようにドラッグ&ドロップ操作する。



メニューに「設定」を追加


プロパティウィンドウで、コントロール名(name)が「設定ToolStripMenuItem」と変な感じになっているので、「SettingMenuItem」に変更。



次に、設定ダイアログを作成します。

ソリューションエクスプローラのWindowsフォームプロジェクト(WindowsFormsApplication44)を右クリック→追加→Windowフォームをクリックする。



そのままFowm2.csを追加する。

Form2のウィンドウを引き延ばして、TextBoxを3つボタンを3つつける。
button1.Textを「設定初期化」button2.Textを「保存」、button3.Textを「キャンセル」にする。



Form2の青いタイトルバーをダブルクリックし、以下のコードを追加。

private void Form2_Load(object sender, EventArgs e)
{
textBox1.Text = Properties.Settings.Default.Web1Url;
textBox2.Text = Properties.Settings.Default.Web2Url;
textBox3.Text = Properties.Settings.Default.Web3Url;
}

「設定初期化」ボタンをダブルクリックして、以下のコードを追加。
private void button1_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Reset();
textBox1.Text = Properties.Settings.Default.Web1Url;
textBox2.Text = Properties.Settings.Default.Web2Url;
textBox3.Text = Properties.Settings.Default.Web3Url;
DialogResult = DialogResult.OK;
}

「保存」ボタンをダブルクリックして、以下のコードを追加。
private void button2_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Web1Url = textBox1.Text;
Properties.Settings.Default.Web2Url = textBox2.Text;
Properties.Settings.Default.Web3Url = textBox3.Text;
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
}

「キャンセル」ボタンをダブルクリックして、以下のコードを追加。
private void button3_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}

最後に、form2のパブリックプロパティに、以下のようにテキストボックスの内容を取れるようにします。
(今回は、スレッドを使わないので、スレッドセーフのようにはしません。)
public string GetUrl1
{
get { return textBox1.Text; }
}
public string GetUrl2
{
get { return textBox2.Text; }
}
public string GetUrl3
{
get { return textBox3.Text; }
}


続いて、Form1のメニューの「設定ボタン」を押すことにより、Form2を表示するようにします。
まず、以下のように、Form1のプライベートなインスタンス変数を追加します。
private Form2 form2;

Form1_Load()イベントハンドラに、以下を追加します。

form2=new Form2();


で、メニューの「設定」をダブルクリックして、クリックイベントハンドラを作成。
以下のようにします。
private void SettingMenuItem_Click(object sender, EventArgs e)
{
DialogResult dr = form2.ShowDialog();
if (dr == DialogResult.OK)
{
webBrowser1.Url = new Uri(form2.GetUrl1);
webBrowser2.Url = new Uri(form2.GetUrl2);
webBrowser3.Url = new Uri(form2.GetUrl3);
}
}

最後に、プログラム終了直前に、SplitterContainerの分離帯の位置を保存します。
Form1のプロパティウィンドウで、雷マークをクリックし、FormClosingの文字(以下の画像の反転している部分)をクリックする。


以下のイベントハンドラを追加する。
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Properties.Settings.Default.Splitter1Distance = splitContainer1.SplitterDistance;
Properties.Settings.Default.Splitter2Distance = splitContainer2.SplitterDistance;
Properties.Settings.Default.Save();
}


今日はここまで。
次回は、大量データ保存に対応したものを使って、翻訳結果の保存を行います。

保存先に、SQL Server データベースファイル(...mdfファイル)を利用します。
感覚的には、SQL Serverというよりも、Accessといった感じの使い方です。
時間があれば、通知領域にアイコン(NotifyIcon)を出して、アイコン右クリックでContentsMenuStripを表示して、翻訳結果保存ページまでつなげてみます。(時間がなければ回を分けるかもしれないけど。)

2010年5月18日火曜日

英字ドキュメント読み支援ツール その3

今回は、ドキュメントアウトラインの使い方。

前回の状態(以下の画面)から開始



ここで、ツールボックスのSplitContainerをダブルクリック。


で、どこのコンテナに張り付いたかが良くわからない。コントロールのドラッグアンドドロップでの配置は、平面上であれば直感的だけど、親子関係があると操作しずらい。こういう場合に、Visual Studioでは、「ドキュメントアウトライン」が用意されています。
「ドキュメントアウトライン」タブが無い場合は、メニューより[表示(V)]→[ドキュメントアウトライン]を選択してください。そうするとウィンドウがこんな感じになります。



ドキュメントアウトラインで、splitContainer1をドラッグアンドドロップで、splitContainer2.Panel1の配下に移動させ、splitContainer2.Panel2に、WebBrowerを配置。

プロパティウィンドウで、
splitContainer2.OrientationをHorizontal
splitContainer2.SplitterDistanceを244
WebBrower3.Urlをhttp://www.microsofttranslator.com/Default.aspx
とするとこんな感じになる。




実行結果はこんな感じ。




今日は、これで終わり。
次回は、.configファイル(設定ファイル)、メインメニュー、カスタムダイアログ、設定外部ファイル化、ユーザ設定永続化、ユーザ設定のリセットを実装します。

2010年5月17日月曜日

英字ドキュメント読み支援ツール その2

今回は、前回作成したものに機能追加します。
最初は、クリップボードにコピーした文字列の文字化け訂正。
self pacedのpdfは、シングルクォート、ダブルクォートの文字があると半角カタカナの”チ”に置き換えてしまうので、都合が悪い。また、practice Testの方は、クォート+1文字を全角の漢字1文字に置き換えてしまう。

なので、クリップボードを見て、テキストが入ってきたら、"チ"などを置換するプログラムを追加します。

定期的(0.5秒毎)にクリップボードを変更する動きを作ってみます。
以下の画面から。


ツールボックスのコンポーネントカテゴリからTimerをダブルクリックして、Timerコンポネントを追加します。


Timerが選ばれている状態でF4を押下し、プロパティウィンドウにフォーカスを移動し、
timer1の設定を以下のように変更します。
EnableをTrueに
Intervalを500に




この後、画面下部のタイマーアイコンをダブルクリックして0.5秒毎に処理するイベントハンドラの記述に移ります。



プライベートのブール型のインスタンス変数 isChangingを追加しつつこんなコードを書きます。



で、実行してみて、箇条書きの文字、シングルクォートがちゃんと変更されていることを確認。




次に、左画面で、[Ctrl]+Cを押したら、右画面にフォーカスが移動するように変更。

デザイン画面から、右側のwebBrowerコントロールをクリック。プロパティウィンドウで、雷アイコンをクリック。



ここで、PreviewKeyDownをダブルクリックし、イベントハンドラを記述。




これで、一回右側のブラウザの左側のテキストボックスにフォーカスを当てれば、左側のブラウザで[Ctrl]+Cを押すたびに、フォーカスが右側のブラウザの左側のテキストボックスに移動する。


次回は、機械翻訳のセカンドオピニオンを得るように作り変えます。
「ドキュメントアウトライン」を駆使しながら、splitContainerをもう一枚加えて、画面上部を現行どおり、画面下部を横長の領域で、マイクロソフトの翻訳ページを表示することにします。

2010年5月16日日曜日

英字ドキュメント読み支援ツール その1

久々のプログラムねた。(いやぁ、最近.netのMCP試験受けたから。。。)

MCPを受けるのに、英語のpdfを読んでたんだけど、これがあったら便利かなって言うツールを作ってみます。

徐々に作りこんでいきますので数回に分けて書きます。

まずは、環境作り。
Self Pacedのpdf,版によっては、コピペ禁止になっているものがあるため、acrobat readerでは全く読み込めないので、別ツールを使います。
私が使ったのは、brava! readerこいつを、ieでも使えるように再設定します。

で、プログラム開始。
visual studioで、メニューより[File]→[新しいプロジェクト]で、以下のダイアログを開いて、

C#のWindows フォーム アプリケーションを選択。

以下の画面から、


ツールボックスのコンテナから、Split Containerをダブルクリックしてform1に適用。
form1の中央よりに縦に境界線ができて、左側にPanel1,右側にPanel2が表示される。
次に、ツールボックスのコモンコントロールから、WebBrowserをドラッグしてPanel1とPanel2のそれぞれにドロップ。こんな感じになる。



F4キーでプロパティウィンドウにフォーカスを移動し、以下のプロパティを変更。
Form1.WindowState → Maximized
splitContainer1.SplitterDistance → 120
(解像度が1400x900ならこれでよさそう。そうでなければ試行錯誤で設定)
webBrower1.Url → pdfファイルパスを指定。(C:にあるのなら、C:\...\...pdfを指定)
webBrower2.Url → http://www.excite.co.jp/world/

で、実行結果はこんな感じ。



あとは、左側で英文を読みながら、難しそうな文章は、範囲選択 → [Ctrl]+C → 右画面のテキストボックスをクリック → [Ctrl]+a → [Del] → [Ctrl]+v → [Ctrl]+[Enter]で翻訳。


機械翻訳について、エキサイトと、googleとマイクロソフトのものを使ってみたんだけど私の感覚では、翻訳性能は、こんな感じ。
エキサイト >> マイクロソフト >>>>> google
翻訳性能ではgoogleは引き離されているような感じです。(※1)


簡単ですが、今回はここまで。次回は、コピペの際にクォート文字の文字化けの修正をすること(ClipBoardWatcherクラスを作るのは大変なので、0.5秒毎にクリップボードの文字を置換する方法を取ります)と、キーボードコピー操作をしたときに、フォーカスを右画面に移すこと(をすることにより、上の操作の)「 右画面のテキストボックスをクリック 」を端折ることを目的とします。



※1:ま、エキサイトでも、下のように奇訳をしてくれますが。。。
The PrintPage event is the main event involved in printing documents. を、「PrintPage出来事は印刷ドキュメントにかかわるメーンエベントです。」とか、
An event is raised.を、「出来事は高くしています。」とか、
Validating XML with XmlReaderを、「XmlReaderとXMLを有効にします。」とか、
9-11を、「9-11テロ」とか、
following,obect,handler,constructorを、たまに「↓この」とか、「物」とか、「操作者」とか、「建設者」とか、
print jobを、「印刷仕事」とか、
A printed documentを、「印刷された記録」とか、
applications run in the intranetを、「アプリケーションはイントラネットに立候補します。」とか、
The MDI parent form を、「MDI原型」とか、

2010年1月10日日曜日

ASP.NETでのstatic変数の初期化と利用

先週、職場でASP.NETについての質問を受けましたが、よく分らなかったので週末調べてみました。
質問内容は、(Webサーバは1台でスケールアウトしないものとして)ASP.NETアプリ全体で利用する変数を使う場合に、static変数を使って、Application_Startで初期化する使い方で問題ないか?というもの。

これを調べるに当たって、「.NET エンタープライズWebアプリケーション開発大全Vol.3」とMSDNを利用しました。

まず、Vol.3のP.131
>プロセスリサイクリングやフェイルオーバ時、システム再起動時、アプリケーションリスタート時などにはデータが消失する。
とあります。「など」という言葉が非常に気持ち悪いので、データが消失するのは上記以外に無いものと仮定します。


で、フェイルオーバ時、システム再起動時は判るとして、プロセスリサイクリングとアプリケーションリスタートっていうのが
それぞれ、P.188と、201に書いてある。
プロセスリサイクルとは、プロセス単位で、新プロセスを立ち上げて次回以降の要求を新プロセス側で処理するもので、旧プロセスは(受付処理が終わるか、直ちに)落とされるというもの。
それに対して、アプリケーションリスタートでは、同じプロセスの中に新たなアプリケーションドメインを立てて旧アプリケーションドメインでは受付しなくなるというもの。

なので、プロセスリサイクルとアプリケーションリスタートの違いは、新プロセスを起すか起こさないかの違いで、新アプリケーションドメインを立てるのは違いが無いと読み取れる。

で、Application_Startはいつ呼ばれるかというと、
http://msdn.microsoft.com/ja-jp/library/ms178473(VS.80).aspx
で、

ASP.NET アプリケーションの最初のリソース (ページなど) が要求されたときに呼び出されます。Application_Start メソッドは、アプリケーションのライフ サイクル中に一度だけ呼び出されます。このメソッドを使用してデータのキャッシュへの読み込み、静的な値の初期化などのスタートアップ タスクを実行できます。

とあります。

で、結論(アプリケーションドメインでアセンブリをロードした段階ではリソースがまだ要求されていないので、)アプリケーションリスタートでもワーカープロセスリサイクリング時でもどちらでもその後のリクエスト1個目のときにApplication_Startは呼ばれていそうです。

2009年12月27日日曜日

年賀状フォントエクスプローラ

Form1.csがここから。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication8
{
public partial class NewYearCardFontExplorer : Form
{
public NewYearCardFontExplorer()
{
InitializeComponent();
}


private void Form1_Load(object sender, EventArgs e)
{
System.Drawing.Text.InstalledFontCollection ifc=new System.Drawing.Text.InstalledFontCollection();
List lstFontFamily = new List();
foreach (FontFamily tmpFontFamily in ifc.Families)
if (tmpFontFamily.IsStyleAvailable(FontStyle.Regular)) lstFontFamily.Add(tmpFontFamily);
comboBoxFont.DataSource = lstFontFamily;
comboBoxFont.DisplayMember = "Name";
comboBoxFont.DropDownStyle = ComboBoxStyle.DropDownList;
trackBarFontSize.Value = 12;
labelFontSize.Text = trackBarFontSize.Value.ToString();
textBoxInputText.Text = "謹賀新年\nあけまして おめでとうございます ことしもよろしくおねがいします。\n Merry Cristmas and Happy New Year";
comboBoxHorizontal.DataSource = Enum.GetNames(typeof(StringAlignment));
comboBoxHorizontal.DropDownStyle = ComboBoxStyle.DropDownList;
comboBoxVertical.DataSource = Enum.GetNames(typeof(StringAlignment));
comboBoxVertical.DropDownStyle = ComboBoxStyle.DropDownList;

listBoxFontStyle.DataSource = Enum.GetValues(typeof(FontStyle));
listBoxFontStyle.SelectionMode = SelectionMode.MultiExtended;
}

private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
pictureBox1.Refresh();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
StringFormat sf = new StringFormat();
sf.LineAlignment = (StringAlignment)Enum.Parse(typeof(StringAlignment), (string)comboBoxVertical.SelectedItem);
sf.Alignment = (StringAlignment)Enum.Parse(typeof(StringAlignment), (string)comboBoxHorizontal.SelectedItem);
FontStyle fs = 0;
foreach (FontStyle tfs in listBoxFontStyle.SelectedItems)
{
fs |= tfs;
}
Font font=new Font((comboBoxFont.SelectedItem as FontFamily).Name, trackBarFontSize.Value,fs);
RectangleF rectangleF = new RectangleF(e.Graphics.ClipBounds.X+50, e.Graphics.ClipBounds.Y+50, e.Graphics.ClipBounds.Width-50, e.Graphics.ClipBounds.Height-50);

//まずは黒字で書く。
if (checkBoxDefaultDrawString.Checked)
{

e.Graphics.DrawString(textBoxInputText.Text,
font,
Brushes.Black, rectangleF, sf);
}


//その上に1文字づつ書く。
if (checkBoxEachCharacter.Checked)
{
DrawEachCharacter(e.Graphics, textBoxInputText.Text, font, null, rectangleF, sf);
}
}

private void trackBarFontSize_Scroll(object sender, EventArgs e)
{
labelFontSize.Text=trackBarFontSize.Value.ToString();
pictureBox1.Refresh();
}
private void DrawEachCharacter(Graphics graphics, string str, Font font, Brush brush, RectangleF rectangleF, StringFormat stringFormat)
{
Brush[] brushes = { Brushes.Red, Brushes.Green, Brushes.Blue };

//文字補正のため、左寄せ上寄せのテキストで1文字目を表示する位置を取得する。
Rectangle r_firstCharacter;
{
CharacterRange[] cr_firstCharacter = { new CharacterRange(0, 1) };
StringFormat sf_firstCharacter = new StringFormat(stringFormat);
sf_firstCharacter.LineAlignment = StringAlignment.Near;
sf_firstCharacter.Alignment = StringAlignment.Near;
sf_firstCharacter.SetMeasurableCharacterRanges(cr_firstCharacter);
Region[] mcr_firstCharacter = graphics.MeasureCharacterRanges(str, font, rectangleF, sf_firstCharacter);
r_firstCharacter = Rectangle.Round(mcr_firstCharacter[0].GetBounds(graphics));
}


for (int i = 0; i < str.Length; i++)
{
CharacterRange[] cr = { new CharacterRange(i, 1) };
StringFormat tsf = new StringFormat(stringFormat);
tsf.SetMeasurableCharacterRanges(cr);
Region[] mcr = graphics.MeasureCharacterRanges(str, font, rectangleF, tsf);
Rectangle r = Rectangle.Round(mcr[0].GetBounds(graphics));
if (r.Left == 0 && r.Top == 0 && i != 0)
{
//1文字目でもないのに、(0,0)に文字を描画しようとするのは、
//おかしい。ただし、制御文字等で、(0,0)の描画はあり得るので
//ループを続ける。
continue;
}
Point WritePoint = new Point(r.Left - (r_firstCharacter.X - Convert.ToInt32(rectangleF.X)), r.Top - (r_firstCharacter.Top - Convert.ToInt32(rectangleF.Top)));
graphics.DrawString(textBoxInputText.Text.Substring(i, 1), font,
brush ?? brushes[i % brushes.Length], WritePoint);

}

}

}
}
Form1.csがここまで。

補正もこのぐらいが限界かなぁ。
アンダーラインとか、打ち消し線とか文字をかぶる物は、1文字ごとにやると難しい。




ちなみに
Form1.Designer.csがここから。
namespace WindowsFormsApplication8
{
partial class NewYearCardFontExplorer
{
///
/// 必要なデザイナ変数です。
///

private System.ComponentModel.IContainer components = null;

///
/// 使用中のリソースをすべてクリーンアップします。
///

/// マネージ リソースが破棄される場合 true、破棄されない場合は false です。
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows フォーム デザイナで生成されたコード

///
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
///

private void InitializeComponent()
{
this.comboBoxFont = new System.Windows.Forms.ComboBox();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.comboBoxHorizontal = new System.Windows.Forms.ComboBox();
this.label4 = new System.Windows.Forms.Label();
this.comboBoxVertical = new System.Windows.Forms.ComboBox();
this.label5 = new System.Windows.Forms.Label();
this.trackBarFontSize = new System.Windows.Forms.TrackBar();
this.labelFontSize = new System.Windows.Forms.Label();
this.textBoxInputText = new System.Windows.Forms.TextBox();
this.checkBoxDefaultDrawString = new System.Windows.Forms.CheckBox();
this.checkBoxEachCharacter = new System.Windows.Forms.CheckBox();
this.listBoxFontStyle = new System.Windows.Forms.ListBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.trackBarFontSize)).BeginInit();
this.SuspendLayout();
//
// comboBoxFont
//
this.comboBoxFont.FormattingEnabled = true;
this.comboBoxFont.Location = new System.Drawing.Point(98, 12);
this.comboBoxFont.Name = "comboBoxFont";
this.comboBoxFont.Size = new System.Drawing.Size(121, 20);
this.comboBoxFont.TabIndex = 0;
this.comboBoxFont.SelectedIndexChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(14, 220);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(497, 196);
this.pictureBox1.TabIndex = 1;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 20);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(50, 12);
this.label1.TabIndex = 2;
this.label1.Text = "フォント名";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 53);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(67, 12);
this.label2.TabIndex = 2;
this.label2.Text = "フォントサイズ";
//
// comboBoxHorizontal
//
this.comboBoxHorizontal.FormattingEnabled = true;
this.comboBoxHorizontal.Location = new System.Drawing.Point(287, 13);
this.comboBoxHorizontal.Name = "comboBoxHorizontal";
this.comboBoxHorizontal.Size = new System.Drawing.Size(81, 20);
this.comboBoxHorizontal.TabIndex = 0;
this.comboBoxHorizontal.SelectedIndexChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(231, 17);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(53, 12);
this.label4.TabIndex = 2;
this.label4.Text = "水平方向";
//
// comboBoxVertical
//
this.comboBoxVertical.FormattingEnabled = true;
this.comboBoxVertical.Location = new System.Drawing.Point(430, 11);
this.comboBoxVertical.Name = "comboBoxVertical";
this.comboBoxVertical.Size = new System.Drawing.Size(81, 20);
this.comboBoxVertical.TabIndex = 0;
this.comboBoxVertical.SelectedIndexChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(374, 15);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(53, 12);
this.label5.TabIndex = 2;
this.label5.Text = "垂直方向";
//
// trackBarFontSize
//
this.trackBarFontSize.Location = new System.Drawing.Point(98, 53);
this.trackBarFontSize.Maximum = 100;
this.trackBarFontSize.Minimum = 1;
this.trackBarFontSize.Name = "trackBarFontSize";
this.trackBarFontSize.Size = new System.Drawing.Size(367, 42);
this.trackBarFontSize.TabIndex = 4;
this.trackBarFontSize.Value = 1;
this.trackBarFontSize.Scroll += new System.EventHandler(this.trackBarFontSize_Scroll);
//
// labelFontSize
//
this.labelFontSize.AutoSize = true;
this.labelFontSize.Location = new System.Drawing.Point(476, 53);
this.labelFontSize.Name = "labelFontSize";
this.labelFontSize.Size = new System.Drawing.Size(0, 12);
this.labelFontSize.TabIndex = 5;
//
// textBoxInputText
//
this.textBoxInputText.Location = new System.Drawing.Point(14, 90);
this.textBoxInputText.Multiline = true;
this.textBoxInputText.Name = "textBoxInputText";
this.textBoxInputText.Size = new System.Drawing.Size(451, 113);
this.textBoxInputText.TabIndex = 6;
this.textBoxInputText.TextChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// checkBoxDefaultDrawString
//
this.checkBoxDefaultDrawString.AutoSize = true;
this.checkBoxDefaultDrawString.Location = new System.Drawing.Point(518, 14);
this.checkBoxDefaultDrawString.Name = "checkBoxDefaultDrawString";
this.checkBoxDefaultDrawString.Size = new System.Drawing.Size(116, 16);
this.checkBoxDefaultDrawString.TabIndex = 7;
this.checkBoxDefaultDrawString.Text = "デフォルト文字表示";
this.checkBoxDefaultDrawString.UseVisualStyleBackColor = true;
this.checkBoxDefaultDrawString.CheckedChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// checkBoxEachCharacter
//
this.checkBoxEachCharacter.AutoSize = true;
this.checkBoxEachCharacter.Checked = true;
this.checkBoxEachCharacter.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBoxEachCharacter.Location = new System.Drawing.Point(518, 37);
this.checkBoxEachCharacter.Name = "checkBoxEachCharacter";
this.checkBoxEachCharacter.Size = new System.Drawing.Size(96, 16);
this.checkBoxEachCharacter.TabIndex = 8;
this.checkBoxEachCharacter.Text = "一文字毎描画";
this.checkBoxEachCharacter.UseVisualStyleBackColor = true;
this.checkBoxEachCharacter.CheckedChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// listBoxFontStyle
//
this.listBoxFontStyle.FormattingEnabled = true;
this.listBoxFontStyle.ItemHeight = 12;
this.listBoxFontStyle.Location = new System.Drawing.Point(478, 90);
this.listBoxFontStyle.Name = "listBoxFontStyle";
this.listBoxFontStyle.Size = new System.Drawing.Size(120, 88);
this.listBoxFontStyle.TabIndex = 9;
this.listBoxFontStyle.SelectedIndexChanged += new System.EventHandler(this.comboBox_SelectedIndexChanged);
//
// NewYearCardFontExplorer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(636, 428);
this.Controls.Add(this.listBoxFontStyle);
this.Controls.Add(this.checkBoxEachCharacter);
this.Controls.Add(this.checkBoxDefaultDrawString);
this.Controls.Add(this.textBoxInputText);
this.Controls.Add(this.labelFontSize);
this.Controls.Add(this.trackBarFontSize);
this.Controls.Add(this.label2);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.comboBoxVertical);
this.Controls.Add(this.label1);
this.Controls.Add(this.comboBoxHorizontal);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.comboBoxFont);
this.Name = "NewYearCardFontExplorer";
this.Text = "NewYearCardFontExplorer";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.trackBarFontSize)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.ComboBox comboBoxFont;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ComboBox comboBoxHorizontal;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox comboBoxVertical;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TrackBar trackBarFontSize;
private System.Windows.Forms.Label labelFontSize;
private System.Windows.Forms.TextBox textBoxInputText;
private System.Windows.Forms.CheckBox checkBoxDefaultDrawString;
private System.Windows.Forms.CheckBox checkBoxEachCharacter;
private System.Windows.Forms.ListBox listBoxFontStyle;

}
}


Form1.Designer.csがここまで。

2009年12月18日金曜日

なんだって!!!

.netで色つきDrawStringとして、TextureBrushとMeasureCharacterRangeを使って版画形式(=プリントごっこ形式)で実現しようと思っていたけど、文字の左や上の部分が少し欠けるときがある。
さっぱりわからなかったが、
http://www.microsoft.com/japan/msdn/archive/community/gdn/ShowPost-24735.htm
や、

http://dobon.net/vb/dotnet/graphics/measurestring.htmlをみると、思わぬことが、、、
>>文字列を描画したときの大きさを取得するには、Graphics.MeasureStringメソッドを使います。しかしMeasureStringメソッドはグリフの突出に備えて前後に余白を入れますので、Graphics.DrawStringメソッドで文字列を描画したとき、これよりも通常は狭い範囲に表示されます。

なんだってーーー。文字の大きさをとろうとしただけで、表示位置が変わるの???
MeasureStringと描画に関係しているところは、、、


stringFormat.SetMeasurableCharacterRanges(characterRanges);


http://msdn.microsoft.com/ja-jp/library/system.drawing.stringformat.setmeasurablecharacterranges.aspx
これの例外条件が問題になってくるかも。


だけど、、マイクロソフトの掲示板の方、

exsample(e.Graphics, "WWWWWWWWWWWWWWW", new Font("Century", 32));
とやると、やっぱりずれる。難しいです。

2009年12月16日水曜日

DrawString

で、色がえをしようとして、版画(=プリントごっこ)のように、TextureBrushを使って、文字を書いてみたけどなんか文字がにじむ。
MeasureCharacterRangesを使って、インクを置く場所に、FillRectangleを使ってみたけど、、、
さらに工夫が居るのかな?

FillRectangleの長方形指定の部分に、RectangleFを指定しているが、これを、上下左右に0.5ドットずつ拡張してみようか?それとも
DrawRectangleで、幅1のペンで塗ってみようか?
ひょっとしたら、FillRectangleに指定したものが、RectangleFでは無くRectangleF.Round()したものだったりしたおちだとうれしいんだけど。

2009年12月1日火曜日

.netのシステムリソース監視

.netframeworkでシステムリソースを確認するのなら、
http://msdn.microsoft.com/ja-jp/library/system.diagnostics.performancecounter(VS.71).aspx
と、
http://msdn.microsoft.com/ja-jp/library/system.management.managementobjectsearcher(VS.71).aspx
ぐらいかな?

2009年10月25日日曜日

ページディレクティブ

前のプロジェクトで作ったASP.NETのページ、ポストバック時に、前回のブラウザ位置を覚えて再現するために、javascriptを使っていたっけ。
でも、ページディレクティブのMaintainScrollPositionOnPostbackを使えばよかったんじゃなかろうか?

2009年9月23日水曜日

このブログのアクセス解析結果を見てみると

http://remindbook.blogspot.com/2009/05/aspnet.htmlが、このブログで一番多く見られている。
ページビューでは、他の記事をトリプルスコアで圧倒しています。
で、この記事。
平日は平均10ページビュー/日なのに対して、休日は、1ページビュー/日。仕事でしか見てないんだねぇ。
続いて検索ワード。上位3つは、「別ウインドウで開く asp.net」、「asp.net showmodaldialog」、「asp.net ポップアップ モーダル」でした。

asp.netで別ウィンドウを開く要件で皆さん苦労されているようですね。

でも、モーダルダイアログで設計したものの、お客様要求でモードレスダイアログに戻すときに、セッション管理とか、むちゃくちゃ苦労しますので、ブラウザを使うwebアプリケーションの構造上、別ウィンドウ化(ウィンドウポップアップ化)は禁止です、、、、と宣言したいものです。

でも、当然そんなことは言えなくて、お客さんの中には、Webアプリケーションの構造を無視して、処理の途中に警告ダイアログを出して、ユーザ確認を促してって言うことも。。。

Webアプリケーションなら、
1.ボタンを押す→2.ブラウザ側javascriptを動かす→3.サーバ側で処理する→4.ブラウザに返事を返す。
っていう流れなのに、3.の処理の途中でダイアログっていう無茶を言う。
設計者も断ればいいのに、実現できますって答えちゃって。。。
結局、
http://remindbook.blogspot.com/2009/05/aspnet_29.html
のようなことをしなきゃならない。この辺をフレームワーク側で吸収してくれるであろう、VisualStudio2010,.netFramework4.0/asp.net4.0に期待かな。

2009年9月8日火曜日

なんてこったい

昨日リリースしたバッチプログラムがおかしくなった。
ログからは、int64型の値をint32型の変数に格納できないとのメッセージが。
で、前回のソースファイルを見比べたら、~Designer.csの型が1箇所おかしい。前回リリースしたバージョンの~Designer.csでは、BigInt,Int64型のパラメータ引渡しになってるのに、今回のものはInt,Int32型になってた。
で、元となる~.xsdファイルでは、パラメタライズドクエリのパラメータの1つが、、、、Int32型になってた。
考えられるのは、~Designer.csファイルを手で修正したこと。

~Desinger.csは、VisualStudio2005が自動生成するファイルで、手で触っちゃいけないファイルなのです。また、~.xsdを更新すると~Designer.csが再生成されるのです。
で、今回~.xsdでSQL文をちょっと直したら、別のSQL文の方でで問題が発覚。しかもビルド時エラーじゃなく実行時エラーなので困ったものです。

あ~あ、前任者のトラップに引っかかっちゃった。

で、今回は、~.xsdの受け渡しパラメータを変更して、対応完了。

でも、なんだったんでしょうねぇ?

2009年6月6日土曜日

カスタムコントロールにascxファイルを作る理由がわからない。

asp.netのWebControlのカスタマイズで、ユーザコントロールっていうものとカスタムコントロールっていうのがあって(他にもあるかもしれないがとりあえずここではこの2つ)両方を開発することがあったのですが、ソースを見てみると、どちらもascxファイルを作ってあった。ただユーザコントロールは派生元がUserControlなのに対し、カスタムコントロールの派生元がLabelなどに置き換わっていました。
なので、ソリューションエクスプローラにascxが表示されるのだけれど、本来のユーザコントロールと違って、カスタムコントロールの場合はソリューションエクスプローラからドラッグ&ドロップでページに配置する使い方はできない。(UserControlから派生していないので)
で、もうちょっと調べてみたらascxのファイルは使っていないみたい。
なんでカスタムコントロールにascxを使ったのかと開発者に聞いてみたら、Webパーツだからとのこと。
使ってもいないファイルなのに(ascxファイルなので使っているaspxと同じように)本番環境に入れてしまうのだけれど、別に有ったからといって問題にならないからいいのかな?
カスタムコントロールのクラスライブラリ化する際にascxのファイルが問題になりそうだけど、今回のものはカスタムコントロールのクラスライブラリ化をしないみたいだし、こちらも問題ないか。

でも、やっぱりなんでascxファイルを作ったか、そのメリットも全然わからない。なんでだろう?

2009年6月5日金曜日

ユーザーコントロールについて

複数のドロップダウンリストがあるユーザコントロールで、親ドロップダウンリスト選択時に子ドロップダウンリストが更新されるユーザコントロールがありました。(ex:県と市町村のドロップダウンがあって、最初は県の一覧のドロップダウンリストのみ選択可能で、県を特定するその県下の市町村がドロップダウンリストにセットされて、市町村ドロップダウンリストが利用可能になるような動きで、県と市町村は親子関係のテーブルでDBに定義されている。)

で、これの親のドロップダウンリストに対するプロパティsetの反映をどうするかで問題になりました。


ASP.NET2.0の動きだと、以下の順番に処理が動きます。

1.aspxページのPage_Load()

2.ascxユーザコントロールのPage_Load()

3.ボタンイベント処理。


DBから読み込み県のドロップダウンリストに県名一覧をセットする処理を、2でにやらせるとなると、非ポストバックのページ読み込み時(aspxのPage_Load())で、県のプロパティセットをしたときには、県のドロップダウンリストがまだできていない状態なので、ドロップダウンのSelectedValueにセットするというのは何かおかしな感じがする。
でも、2.の時点で、県のプロパティの値を見てSelectedValueをセットした場合は、1の処理でプロパティセットをした場合はうまくいくけど、3のボタンイベント処理で、プロパティセットした値は、ドロップダウンリストに反映されなくなる。


で、本当は、1.の前に動くであろう、ユーザコントロール内のドロップダウンリストのInitイベントで、IsPostBackがfalseのときだけ県名のドロップダウンリストに値を詰め込んでおけば、プロパティセット時には、ドロップダウンリストが出来上がっているのでプロパティセット時にドロップダウンリストのSelectedValueに値を詰め込めばよかっただけのような気がします。

つまり、


1.県のドロップダウンリストのInitイベントにてIsPostBackがfalseのときのみ県名一覧をセットする。
2.市のドロップダウンリストのInitイベントでは、選択不可とする。
3.県のプロパティがセットされた場合は、県のドロップダウンリストのSelectedValueをセットし、市のドロップダウンリストは、選択された県の市名一覧をセットする。(県のプロパティに""がセットされた時は、市のドロップダウンリストを空にして選択不可とする。)
4.市のプロパティをセットされた時は、市のドロップダウンリストのSelectedValueをセットする。

でもこの方法はとらなくなりそう。

2009年6月2日火曜日

複数の一行入力テキストボックスと直後のボタン

asp.netの話。
ページに複数の一行入力のテキストボックスとボタンを2つ配置すると。。
テキストボックスの入力中にEnterキーを押すと、テキストボックスの後で一番近い場所に配置したボタンクリックイベント処理が動く。
テキストボックスが1つだけだったときは、page_load処理だけが動くのに、テキストボックスが2つ以上あるとpage_load()とbutton_click()が動いてしまう。
。。。何かの嫌がらせなのだろうか?

2009年5月30日土曜日

asp.net更新ボタン無効化

昨日の続き。昨日はhiddenfieldを使った、なんでもpostback制御だったんだけど、あのやり方だと、更新ボタンを押されたときに破綻しそう。なので、それだけを回避する措置を。
こんな感じの実装にしてみた。

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DateTime dt = System.DateTime.Now;
Session["TimeStamp"] = dt;
ViewState["TimeStamp"] = dt;
}
if (IsPostBack)
{
DateTime dt1 = (DateTime)Session["TimeStamp"];
DateTime dt2 = (DateTime)ViewState["TimeStamp"];
if (dt1 != dt2)
{
Button1.Text = "不正";
}
else
{
Button1.Text = "正常";
}
DateTime dt = System.DateTime.Now;
Session["TimeStamp"] = dt;
ViewState["TimeStamp"] = dt;
}
}

やっていることは、セッション(サーバ側)とビューステート(HiddenField制御のようなクライアント側)と両方で同一タイムスタンプを持たせ、ポストバック時に、これが前回の情報と同じことを確認することで更新ボタンを押されたかどうかをチェックしているということです。

更新ボタンを押すということは、前回の送信情報と同じ情報をサーバ側に渡すことです。なので更新ボタンを押したときにサーバに渡す(クライアント側からのビューステートの)タイムスタンプがセッションで保持している情報と食い違うので、上のプログラムではボタン表示名が「不正」となります。なお、サーバとのやり取りが発生するタイミングでタイムスタンプを最新化しているので、サーバに送るデータで、サーバで一回も処理していないものに限り、ボタン名が正常となります。

2009年5月29日金曜日

asp.netスパゲッティー

なんか無茶苦茶な感じがする。
asp.netの開発では、ボタン押下イベントは、処理が終わってからブラウザ側に制御が戻るんだけど、今回のはちょっと特殊な動きをしなければならない。
更新ボタンイベント→DBチェック→処理続行要否確認ダイアログ(はい/いいえ)→「はい」の場合にDB更新
という処理があって、これの実現方法が思いつかなかった。
で、プログラマに確認してみたところ、以下のようにやるとのこと。
1.ボタンイベントの処理では、DBチェックとダイアログ表示までを実施。
2.ダイアログにOKを押した場合、HIDDENタグに状態を記入してsubmitを行う。
3.ページロードのポストバック時の処理で、HIDDENタグの状態によって処理を変更。
というわけで、お化けのような馬鹿でっかいhiddenタグのif文だらけのPage_Load()になりそうだし、[F5]キーインによる、前回のデータ再送信なんかやられた日にはえらいことになる。なんでこんな仕様を許しちゃってるんだろう。


ちなみにプログラムはこんな感じ。

protected void Button2_Click(object sender, EventArgs e)
{
string scr="<script language='javascript'>window.onload = function() { if (window.confirm('メッセージ')) { document.getElementById('HiddenField1').value='1';form1.submit(); } }</script>";
Page.ClientScript.RegisterClientScriptBlock(GetType(), "startup", scr);
}
で、Page_Loadではこんな感じ。
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
if (HiddenField1.Value == "1")
{
HiddenField1.Value = "0";
//DB更新
}
}
}

でもそういやぁ、
...showModalDialog();
location.href=location.href;
というプログラムがあったっけ、これは、ModalDialog処理後に、自ページを再読み込みさせたかったんだけど、hrefを使った画面遷移は、非ポストバック処理だし、ViewStateや当画面で入力した内容が消えてしまいそう。上のプログラムのようなsubmit()処理に変更せねば。。。

2009年5月23日土曜日

asp.netのカスタムコントロールをVisual Stuidoのデザイナで編集する方法


流れとしては、
1.ASP.NETサーバーコントロールを含むアセンブリ(exe,dll)を作成する
2.Visual Studioのツールボックスで、右クリック→アイテムの選択で、参照ボタンを押して1.で作成したアセンブリを選択。
→ツールボックスに歯車アイコンでカスタムコントロールが表示される。
3.上の(2.の)操作によって出てきた、歯車アイコンをaspxやascxに張り付ける。

ふつうは、コントロール用のアセンブリと利用するWebプロジェクトはアセンブリを分けますが、一緒でもちょっとは動くみたい。
でも、Webプロジェクトとカスタムコントロールのアセンブリが一緒だと、デザイン時のレンダーとか、プロパティセットが正しく表示できないみたい。
(コントロールの描画エラー-Label4 ハンドルされていない例外が発生しました。'SANITIZE'をプロパティ'DisplayMode'で設定できませんでした。みたいな表示となる。)
アセンブリを分けてれば、こんなエラーは出ないんだけど。。。しょうがないのかなぁ。



ま、しょうがないとして、
今回は、カスタムのLabelコントロールを元にカスタムコントロールを作成します。Labelコントロールに2個プロパティを追加します。
1個は、表示方法(そのまま表示/サニタイズ表示/タグ抜き表示)もう1個は、改行文字変換(改行文字をBR変換するかどうか)です。


カスタムラベルのソースはこんな感じ。
各メタデータの意味は、以下のURLを参考になります。
http://msdn.microsoft.com/ja-jp/library/ms178658(VS.80).aspx


----ここからMyCustomControl.cs------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebControlTest.WebParts
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:Label runat=server></{0}:Label>")]
public class Label : System.Web.UI.WebControls.Label
{
/// <summary>
/// 文字列の変換指定列挙子
/// </summary>
public enum TranslateString
{
NONE,
SANITIZE,
DELETE_TAG
}

/// <summary>
/// 改行変換の列挙子
/// </summary>
public enum TranslateNewLine
{
NONE,
BR_TRANSLATION
}

private TranslateString displayMode=TranslateString.NONE;
private TranslateNewLine newLineMode=TranslateNewLine.NONE;

[Bindable(true)]
[Category("Appearance")]
[Description("文字変換")]
[DefaultValue("NONE")]
[Localizable(true)]
public TranslateString DisplayMode
{
get { return displayMode; }
set { displayMode = value; }
}

[Bindable(true)]
[Category("Appearance")]
[Description("改行モード変換")]
[DefaultValue("NONE")]
[Localizable(true)]
public TranslateNewLine NewLineMode
{
get { return newLineMode; }
set { newLineMode = value; }
}

protected override void RenderContents(HtmlTextWriter output)
{
string outputText = Text;
switch (displayMode)
{
case TranslateString.SANITIZE:
outputText = System.Web.HttpUtility.HtmlEncode(outputText);
break;
case TranslateString.DELETE_TAG:
outputText = System.Text.RegularExpressions.Regex.Replace(outputText, "<[^>]*>", "");
break;
default:
break;
}
switch (newLineMode)
{
case TranslateNewLine.BR_TRANSLATION:
outputText = outputText.Replace("\r\n", "<br>").Replace("\r", "<br>").Replace("\n", "<br>");
break;
}
output.Write(outputText);
}
}
}
----ここまでMyCustomControl.cs------