- PR -

Page派生クラスで実装したValidatorsがデータグリッドに適用されない

1
投稿者投稿内容
どら
会議室デビュー日: 2005/08/25
投稿数: 5
投稿日時: 2005-08-25 06:57
こんにちは、いつも参考にさせていただいております。

以下のTipsを参考に、Page派生クラスの中で、Validatorsをカスタマイズして
一元管理をさせています。

http://www.atmarkit.co.jp/fdotnet/dotnettips/295pagevalidate2/pagevalidate2.html

普通にPageの中に配置した検証コンロトールは一元管理元の検証コントロールを利用して
くれていますが、DataGrid内に配置した配置した検証コントロールは、一元管理元の
検証コントロールを利用してくれない現象が発生しております。
(検証コントロール自体は有効になっていますが、一元管理元の検証コントロールを
利用してくれないのです)

DataGrid内で、Page派生クラスで作成した一元管理元の検証コントロールを有効に
するのにはどうしたらよいのでしょうか?
ご教示お願いします。

【開発環境】
ASP.NET、.NetFrameWork1.1、WebMatrix



[ メッセージ編集済み 編集者: どら 編集日時 2005-08-25 06:59 ]
にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2005-08-25 07:32
「一元管理元の検証コントロール」というのがよくわかりませんが、
[ASP.NET]検証コントロールのエラー・メッセージを一元管理するには?を(基底フォームはともかく)そのまま適用するのであれば、動的に生成されたものには適用されないおそれがあります。理由として、このコードは Form_Load の先頭で、(複数回適用されるのを避けるため)ポストバック以外のときに行っているのですが、この時点ではまだ動的な要素が生成されていない可能性があるからです。単純に DataBind() を呼ぶ順序という問題もあるのですが、ポストバック結果に基づいて DataBind() する場合(ページングなどを用いていたら確実にそうなりますね)にはこのやり方のままではどうにもなりません。

メッセージ置換の処理は動的に生成した後で行うか、もしくは動的に生成したものに対しては個別に行う必要があると思います。
ただし、ポストバックを考慮すると、
・検証コントロールの EnableViewState=false として毎回適用する
・適用前のメッセージには目印をつけ、それがあるもののみに適用する
・動的に生成したものに対しては個別に行う
を思いつきました。
どら
会議室デビュー日: 2005/08/25
投稿数: 5
投稿日時: 2005-08-25 08:02
にしざき様

早速のご返答ありがとうございます。

説明不足で申し訳ありません。
データグリットに、「編集」ボタンを表示し、
EditItemTemplateの中にVaridatorを配置している状況です。
ページング機能も利用しております。

にしざき様のご指摘通り、
[ASP.NET]検証コントロールのエラー・メッセージを一元管理するには?
のソースをそのまま適用しております。
そしてこれでは、ポストバック以外の時にしか検証コントロールの書き換えを
行っておりませんので一応、「If Not Page.isPostBack Then」
のIf文をコメントアウトして実行してみましたが、やはりデータグリット内のValidatorには
適用されませんでした。

また、
>・検証コントロールの EnableViewState=false として毎回適用する
も実行してみましたが、残念ながら適用されませんでした。

>・適用前のメッセージには目印をつけ、それがあるもののみに適用する
>・動的に生成したものに対しては個別に行う

の2つの点についても、トライしてみたいのですが、具体的にどうしたらよいのか
わかりません(すみません、まだまだ素人なもので)

恐縮ですが、できましたら具体的にどうしたらよいのかヒントをいただけると
助かります。よろしくお願い致します。

[ メッセージ編集済み 編集者: どら 編集日時 2005-08-25 08:05 ]

[ メッセージ編集済み 編集者: どら 編集日時 2005-08-25 08:06 ]
にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2005-08-25 08:55
以下、実際には試していないことを予め注意しておきます。

>・適用前のメッセージには目印をつけ、それがあるもののみに適用する
の場合。
前提として、DataGrid の 〜Template に書かれた要素が生成されるのは、DataBind() を実行した時点なので、その後で行う必要があります。
特に、ページングなどを行う際には、イベント処理中に DataBind() を実行しているでしょうから、その点に関して注意が必要です。
コントロール実行の有効期間などを参考にタイミングを考えると、たとえば プリレンダリング ステージで行うことが考えられます。
この場合、元記事の Page.Load イベントのかわりに Page.PreRender イベントを用いるか、もしくは Page.OnPreRender イベントをオーバライドすることになります。
後者の例では、
コード:
protected override OnPreRender(EventArgs e){
  base.OnPreRender(e);

  foreach (BaseValidator valid in Page.Validators) {
    // 複数回処理しないように、先頭に@がついたもののみ処理
    if (valid.ErrorMessage.Length == 0 || valid.ErrorMessage[0] != '@')
      continue;
    string message = valid.ErrorMessage.Substring(1);
    // 以下は元々の掲載コードどおりだが、右辺の valid.ErrorMessage のかわりに
    // message を用いる
    ...
  }
}


これでいいんじゃないかと思うのですが。

>・動的に生成したものに対しては個別に行う
こちらの場合、その他の部分は大概は従来どおりなのですが、まずは Page_Load 部分
コード:
private void Page_Load(Object sender, EventArgs e){
  // ページ内の検証コントロールを順番に走査。
  // もともと設定されていたErrorMessage属性(項目名)や
  // そのほかのパラメータから、
  // それぞれの検証型に応じたメッセージを動的に生成する
  if (!Page.IsPostBack) {
    foreach (BaseValidator valid in Page.Validators) {
      ReplaceMessage(valid);
    }
  }
}

private void ReplaceMessage(BaseValidator valid) {
  // 元のforeach 内を書く
  ...
}

// 配下の validator を探して処理する
private void FindAndReplaceValidator(control container) {
  foreach (Control control in container.Controls) {
    // 配下の validator を探して処理する
    FindAndReplaceValidator(control);
    BaseValidator valid = control as BaseValidator;
    if (valid != null)
      ReplaceMessage(valid);
  }
}


で、最後に DataGrid.ItemDataBound イベントで、
コード:
private void DataGrid_ItemDataBound(object sender, DataGridItemEventArgs e) {
  FindAndReplaceValidator(e.Item);
}


でいいんじゃないかと思います。
どら
会議室デビュー日: 2005/08/25
投稿数: 5
投稿日時: 2005-08-25 11:07
にしざき様

わざわざコードまで書いていただきありがとうございます。

>・適用前のメッセージには目印をつけ、それがあるもののみに適用する

の方法で、期待通りの動作になりました。
(Page に直接配置しているValidatorsで2回目以降メッセージが複数表示するという現象がおきましたが、EnableViewState="False"を追加したところ1回のみのメッセージ表示になりました)

ところで、実は、「適用前のメッセージには目印をつける」ということをせずに、

[ASP.NET]検証コントロールのエラーメッセージを一元管理するには?

のソースをPage → Page.OnPreRenderのイベントのオーバライドに変更するだけで実現できました。
(If Not Page.IsPostPack Then のみ削除し、
コード:
protected override OnPreRender(EventArgs e){
  base.OnPreRender(e);


部分のみを適用させていただきました。

なぜそれだけでできたのか、理解できていないところが勉強不足なのですが…。
本当にどうもありがとうございました。
にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2005-08-25 11:46
>なぜそれだけでできたのか
原因は、それだけではなく

>EnableViewState="False"を追加した
のためです。このせいで、変換した ErrorMessage が(他のプロパティもですが) ViewState に保存されず、毎回元の値に戻っています。

したがって、OnPreRender で全て処理しても問題がないということになります。
1

スキルアップ/キャリアアップ(JOB@IT)