redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

(小ネタ)WindowsフォームのDataBindingに関するリンク集

Windowsフォームでデータバインディングを行う場合に、BindingSource、IDataErrorInfo、ErrorProvider、null値の制御についての有用なリンク集。

サイト

WindowsFormsでの単項データバインドまわり | tocsworld

IDataErrorInfo Interface (System.ComponentModel) | Microsoft Docs

双方向データバインドによる単体入力エラーチェック – とあるコンサルタントのつぶやき

書籍

ひと目でわかる Visual C# 2010 アプリケーション開発入門 日経BP社 (2010/11/8)

BindingSourceを使用したTextBoxのデータ入力時におけるメリット

以前にWindowsフォームで作成したアプリケーションを修正する機会があり、BindingSourceについて理解が深まったので、記録を残しておく。

「TextBoxに入力した値をバリデーションして、正しい値ならば紐づいたDBのレコードを更新する」というよくある処理を実装する場合、BindingSourceを使用してBindingを行うと以下のようなケースで便利だった。

バリデーションでエラーになったら、変更前の値を復元したい

バリデーション処理は、Validatingイベントを使用すると思うが、パラメータから取得できる値、TextBoxフィールドの値も変更後の値になっている。
このままでは変更前の値を取得できないため、変更前の値を格納するフィールドを用意すると思うが、実はBindingSourceを使っていると変更前のフィールドがいらなくなる。

それは、BindingSourceから名前付きDataRowを取得でき、それが入力前の値を持っているからだ。名前付きDataRowの取得、入力前の値の取得は、以下のように行う。

var dataRowView = bindingSource.Current as DataRowView;
var row = dataRowView?.Row as 名前付きDataRowクラス名;
if (row != null)
{
    originalText = row[nameof(row.プロパティ名), DataRowVersion.Original].ToString();
}
//originalTextを使用して変更前の値を代入する処理など

レコードを更新する時に、値が変更されている場合のみ更新したい

バリデーション後の更新では、Validatedイベントを使用すると思うが、値が変更されていないのに毎回DBに接続して更新するのもムダなので、値が変わった場合のみ更新をしたい。
DBから取得した値と比較する方法があるが、対象が1つの画面からしか更新されない場合、取得のために毎回DBに接続すると、DB接続回数が増えてしまう。
上記の変更前の値を使用して、入力値と比較する事もできるが、実はBindingSourceを使っているともっと簡単な方法がある。

それは、BindingSourceから取得できる名前付きDataRowが、変更情報を持っているからだ。変更されたかどうかの判定は以下のように行う。

//rowは、名前付きDataRowクラス名のインスタンス。取得方法は上記と一緒。
if (row.RowState == DataRowState.Modified)
{
  //データが変更された場合に行う処理(DB更新処理など)
}

以上。

NPOIでExcelのセルの値を取得する(関数も対応)

NPOIを使用してExcelを読み込む処理を作成したので、後から見返せるように気づいたことをメモしておく。

確認したバージョン:.NET Framework 4.6、NPOI 2.3.0

Excelのセルの値を取得する場合は、以下のようにまずICellインスタンスを取得する。

//sheetは、ISheetインターフェイスのインスタンス
ICell cell = sheet.GetRow(行番号).GetCell(列番号);

数値や文字列を取得する

ICellインターフェイスで宣言されているプロパティから値を取得することが出来る。セルが空の場合も対応している。

ICellインターフェイス

やりたい事 プロパティ セルが空の場合の返り値
数値を取得する NumericCellValue double型の0
文字列を取得する StringCellValue string型の""(空文字)

関数の結果を取得する

NumericCellValueプロパティや、StringCellValueプロパティは、セルの値が関数の場合、関数を評価した結果を返してくれる。

ICellインターフェイス

やりたい事 プロパティ 関数の場合の返り値
数値を取得する NumericCellValue 関数を評価した結果の数値
文字列を取得する StringCellValue 関数を評価した結果の文字列

関数を評価した結果を取得するのに、IFormulaEvaluatorインターフェイスを使用する方法もある。
Evaluateメソッドに対象セルのICellインスタンスを渡して実行し、CellValueインスタンスを取得する

//workbookは、IWorkbookインターフェイスのインスタンス
IFormulaEvaluator evaluator = workbook.GetCreationHelper().CreateFormulaEvaluator();
//cellは、ICellインターフェイスのインスタンス(値を取得したいセル)
CellValue cellValue = evaluator.Evaluate(cell);

CellValueインスタンスに関数の評価結果が入るので、プロパティから値を取得することが出来る。
セルの値が空の場合は、CellValueインスタンスにnullが入るため、プロパティを参照すると例外が発生する。

CellValueクラス

やりたい事 プロパティ セルが空の場合の返り値
数値を取得する NumberValue NullReferenceExceptionが発生
文字列を取得する StringValue NullReferenceExceptionが発生

CellValueクラスでは、関数の評価結果のデータ型とプロパティが異なっていても例外にはならない。

CellValueクラス

関数を評価した結果 プロパティ 返り値
数値 NumberValue 数値
数値 StringValue null
文字列 NumberValue double型の0
文字列 StringValue 文字列

関数を評価した結果のデータ型が、条件によって変わるセルの値を取得する

ICellインターフェイスのプロパティでは、関数の評価結果とプロパティの型が異なると例外が発生するため使えない。

ICellインターフェイス

関数を評価した結果 プロパティ 返り値
数値 StringCellValue InvalidOperationExceptionが発生
文字列 NumericCellValue InvalidOperationExceptionが発生

関数を評価した結果の型が条件によって変わる場合は、CellValueクラスを使用する。
CellValueクラスのCellTypeプロパティにはデータ型が格納されているため、データ型で分岐して処理が出来る。

//cellValueは、CellValueクラスのインスタンス
var value = string.Empty;
if (cellValue.CellType == CellType.String) {
    value = cellValue.StringValue;
}

以上。

jQueryのfloatTheadプラグインを使用したテーブルを印刷する方法

少し前ですが、レコード数の多いテーブルを表示した時に、スクロールでExcelみたいに先頭行を固定して表示したい時に、jQueryのfloatTheadプラグインを使用しました。*1

さらにfloatTheadプラグインを使用したテーブルを印刷したいという要件が出た時に、そのままでは印刷レイアウトが崩れてしまったので、対処方法を調べました。

作者のGitHubのissueページに載っていました。

Support for printing tables · Issue #68 · mkoryak/floatThead · GitHub

内容を大まかにまとめると、 メディアクエリを使用してブラウザ表示か印刷かを判別し、 印刷の場合はtable要素のfloatThead('destroy')を呼び出し、 画面表示に戻ったら再度table要素のfloatThead()を呼び出す。 という感じです。

以上

Hyper-V で Vagrant

この間、Hyper-Vで仮想環境を構築しているので、せっかくだからVagrantも使ってみることにした。

動作確認環境は以下の通り

実際にやってみたところ、特につまずく箇所もなく、起動に成功した。ファイアウォールの設定はしていないため、フォルダ共有が出来なかったくらい。既定のスイッチ周りはどうなるかが気になっていたが、接続しているようだ。

行ったことをメモしておく。

  1. Vagrant のインストール
  2. Vagrant Box の取得(Box は hashicorp/precise64 を使用)
  3. Vagrant テスト用のフォルダを作成して移動
  4. vagrant init 実行
  5. vagrant up 実行(provider として、Hyper-V を指定)
  6. vagrant ssh で接続
  7. vagrant halt で停止

Vagrant のインストール

Vagrant公式サイトで、Windows 64-bitをダウンロードして実行した。

www.vagrantup.com

Vagrant Box の取得

Hyper-Vな点だけ注意して、以下のコマンドを実行すると、Vagrant Box の取得が出来た。

vagrant box add hashicorp/precise64 --provider=hyperv

Vagrant テスト用のフォルダを作成して移動、vagrant init 実行

Vagrant テスト用のフォルダを作成して移動し、以下のコマンドを実行した。

vagrant init hashicorp/precise64

vagrant up 実行(provider として、hyperv を指定)

Vagrant Boxと同様にprovider にHyper-V を指定した。仮想マシンの本体は、vagrant upを実行したフォルダに作られる.vagrantフォルダ以下に保存された。

vagrant up --provider=hyperv

vagrant ssh で接続、vagrant halt でサーバ停止

正常に動作した。vagrant status コマンドで停止したのも確認できた。

その他

初期設定では、個人フォルダ配下の.vagrant.dフォルダにBoxファイルが配置されるので、以下を参考にして配置場所を変更した。

vagrantのboxフォルダ変更手順メモ - Qiita

以上

IISのApplicationPollIdentityとWindows認証によるDBアクセスで発生したエラー

新年あけましておめでとうございます。今年もよろしくお願いします。

さて、ASP.NET MVC の権限関係では、いくつか記事を書いた。

redwarrior.hateblo.jp

redwarrior.hateblo.jp

上記を参考にすれば、躓かずに構築できると思ってたが、あまり見たことのないエラーに遭遇したのでエラー内容と解決策を記録しておく。

実行環境(ただし、今回はあまりバージョンは関係ないと思う)

設定や前提条件

  • IIS上に複数サイトを作成して、ドメイン名によってサイトへの振り分けを行っている
  • サイトではなくアプリケーションで、Windows認証を有効にしている
  • アプリケーションプールはApplicationPollIdentityを使用。アプリケーションプールユーザにDBアクセスの許可を設定している
  • アプリケーションからDBへのアクセスは、Windows認証

遭遇したエラーメッセージ

System.Data.Entity.Core.EntityException: 基になるプロバイダーが Open で失敗しました。 ---> System.Data.SqlClient.SqlException: ログインできませんでした。このログインは信頼されていないドメインからのログインなので、統合認証では使用できません。

あまり見たことが無いエラーなので、DBアクセス許可の設定をやり直したり、Windows Serverの再起動をしてもらったりしたが、変化なし。
エラーメッセージで検索しても、めぼしい情報は見つからず。
落ち着いて考えるとメッセージは、(権限による)アクセス許可の問題ではないと思いたち、今までと違う所を探した。

そうすると、DBの接続文字列が違っていた。今まではサーバー名を設定していたが、今回はDNSに設定したドメイン名を使用していた。接続文字列をサーバ名に戻すと、エラーが発生しなくなった。

対処方法

Data Sourceにサーバー名を指定する。

以上。

2018年にもっとも読まれた記事ランキング

しばやん( id:shiba-yan )さんが作った「2018 年の人気記事ランキング生成」を使わせてもらい、記事ランキングを作成してみました。

ランキング自体は、右下の注目記事と大差ないですね。ランキングにしめる2015年、2016年の記事の割合が相変わらず高いです。 ブログを始めたのが、2015年で当初は色々とネタがあったという事でしょうか。

  1. (小ネタ)WindowsフォームでShowDialogメソッド、Showメソッド、Closeメソッド、Disposeメソッドの動作を理解する。

  2. ASP.NET MVC でテキストボックスとラベルに別の書式を使用する

  3. (小ネタ)改行文字を削除する

  4. 「TortoiseGitでユーザー名・パスワードを記憶する」をやってみた。

  5. .NETでログファイルのローテーションに日付を使用する

  6. Web Deployの整理

  7. Entity Framework でSQLを実行する

  8. (小ネタ)Entity Framework でタイムアウトの設定方法まとめ

  9. C#でJavaDoc風のAPIリファレンスを作成する方法

  10. IIS上で動くASP.NET (MVC)アプリケーションの権限について

  11. (小ネタ)Visual Studio 2015 のバージョンがv14なわけ。(Visual Studio 2013 はv12です)

  12. ASP.NET MVC で備考入力欄を作成する方法のまとめ

  13. Visual Studio 2015は、Professionalでもユニットテスト機能(MSTest)が充実している

  14. (小ネタ).NET Frameworkの本体と、targeting packは別物

  15. バリデーションのメッセージを変更する

  16. WindowsサービスとしてインストールしたJenkinsのアンインストール方法

  17. 環境ごとに設定を変更する(DBへの接続文字列)

  18. ストアドプロシージャからNLogを使用してログを出力する

  19. TFS 2015でプロジェクトを.NET Framework 4.6にダウングレードしてビルドする

  20. (小ネタ)C#でデフォルト引数に今日の日付や現在時刻を指定する

来年も地道に続けていこうと思います。