質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.84%

  • VB.NET

    832questions

    Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

  • ASP.NET

    456questions

    ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

  • .NET Framework 4.0

    58questions

    Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。

動的に生成した表の中に動的にチェックボックスを配置したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 372

meesa

score 4

前提・実現したいこと

ASP.NETでWEBアプリケーションを開発しています。
画面上に表を配置し、DBから取得した値を表示させようとしています。
セルには、DBから取得した値(数値0~9)や、「申請種類」という条件に応じて、
文字列か、チェックボックスを表示させたいです。

こういった場合に、なるべく可読性の高い、シンプルなソースで実現するための手法として、
どのような方法が考えられるか、教えていただきたいです。

自分で考えた方法は、

  1. GridViewを使用して表を生成
  2. チェックボックスを表示する可能性があるセルについては、TemplateFieldにし、
    ラベルとチェックボックスを配置
  3. RowDataBoundイベントで、ラベルとチェックボックスの表示非表示に切り替えを行う

というものです。

表示したい表のイメージは以下になります。
表示行数の想定は最大でも10行程度で、実際には2~5行がほとんどです。

・DBの値

管理No. ユーザー名 申請項目1 申請項目2 申請項目3
001 ユーザー1 1 0 1
001 ユーザー2 2 1 3
001 ユーザー3 1 2 2
002 ユーザー4 0 8 8

・画面表示結果(管理No単位で画面表示)
管理No.:001
申請種類:申請1

ユーザー名 申請項目1 申請項目2 申請項目3
ユーザー1 申請不可
ユーザー2 申請済
ユーザー3

※黒い四角はチェック済みのチェックボックスだと思ってください。

申請種類とDBの値の組み合わせ、その表示結果は、項目1の場合、
申請1かつ0:申請不可
申請2かつ0:チェックボックス(OFF)
申請1かつ1:チェックボックス(OFF)
申請2かつ1:申請対象外
申請1かつ2:チェックボックス(ON)
申請2かつ2:申請1申請中

項目2の場合、
申請1かつ0:申請不可
申請2かつ0:チェックボックス(OFF)
申請1かつ1:チェックボックス(OFF)
申請2かつ1:申請対象外(理由A)
申請1かつ2:チェックボックス(OFF)
申請2かつ2:申請対象外(理由B)
申請1かつ3:チェックボックス(ON)
申請2かつ3:申請1申請中

・・・のように、項目ごとに、DBが同じ値であっても意味が異なる場合があります。
また、DBの値7~9は、申請2の場合にチェックボックスを表示し、申請1では文字列を表示する
ために使用されています。(下記ソースでは省略しています)

該当のソースコード

Private Sub GV_User_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GV_User.RowDataBound

        If e.Row.RowType = DataControlRowType.DataRow Then
            Select Case e.Row.Cells(2).Text
               Case "0"
          If DemType = 1 then
                    '申請種類1の場合、チェックボックスを表示せず、申請不可の文字を表示
                    e.Row.FindControl("lbl1").Visible = True
                    CType(e.Row.FindControl("lbl1"), Label).Text = "申請不可"
                    e.Row.FindControl("ckb1").Visible = False
                  Else
                    '申請1ではない場合、チェックボックス(オフ)を表示
                    e.Row.FindControl("lbl1").Visible = False
                    e.Row.FindControl("ckb1").Visible = True
                    CType(e.Row.FindControl("ckb1"),CheckBox).Checked = False
                  End If
               Case "1"
          If DemType = 1 then
                    'チェックボックス(オフ)を表示
                    e.Row.FindControl("lbl1").Visible = False
                    e.Row.FindControl("ckb1").Visible = True
                    CType(e.Row.FindControl("ckb1"),CheckBox).Checked = False
                  Else
                    '申請1ではない場合、チェックボックスを表示せず、申請対象外の文字を表示
                    e.Row.FindControl("lbl1").Visible = True
                    CType(e.Row.FindControl("lbl1"), Label).Text = "申請対象外"
                    e.Row.FindControl("ckb1").Visible = False
                  End If
               Case "2"
          If DemType = 1 then
                    '申請種類1の場合、チェックボックス(オン)を表示
                    e.Row.FindControl("lbl1").Visible = False
                    e.Row.FindControl("ckb1").Visible = True
                    CType(e.Row.FindControl("ckb1"),CheckBox).Checked = True
                  Else
                    '申請1ではない場合、チェックボックスを表示せず、申請1申請中の文字を表示
                    e.Row.FindControl("lbl1").Visible = True
                    CType(e.Row.FindControl("lbl1"), Label).Text = "申請1申請中"
                    e.Row.FindControl("ckb1").Visible = False
                  End If

         '以下略(値7~9の場合の場合の分岐処理)
        End Select

        '以下略(申請項目数分繰り返し)
        End If
    End Sub

試したこと

上記ソースはGridViewのRowDataBound処理の内容になります。
(実ソースそのままは出すことが出来ないため、簡略化しています)
一応、このソースで目的の動作をすることは確認できているのですが、うまく共通化や簡略化が
出来ず、RowDataBoundイベントが大変長くなってしまっています。(350行ほど)

また、上記表の列「申請項目」に該当するものが、全部で6列あります。
項目ごと分岐数や表示文字列が異なったりするため、共通関数にうまく落とし込めません。
そもそも、チェックボックスやラベルの表示/非表示を切り替える、という
やり方が、一般的なのかどうかもわかりません。

もっとスマートな書き方や、一般的にはこうするんじゃない?という情報があれば、
教えていただきたいです。

GridViewにもこだわりませんので、ご意見やアイディア、ヒントを伺えれば助かります。

補足情報(言語/FW/ツール等のバージョンなど)

asp.net(VB)
.NetFramework 4.0
Visual Studio 2010

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2017/12/26 21:04

    DataGridView? ASP.NET の話ですよね? 「実際のソースはSelect分岐が約10個あり、それがもう5項目分あります」とはどういうことですか? もっと具体的に書いてください。

    キャンセル

  • meesa

    2017/12/26 21:28

    大変失礼しました。GridViewの間違いです。Select分岐については、質問内の表記を修正しました。分岐条件が約10個ある、という意味です。また、項目数は表の列数で、全部で6項目分同じような分岐でセル内の表示内容を修正する必要がありました。

    キャンセル

  • SurferOnWww

    2017/12/26 21:55 編集

    それではエスパーではない自分には分かりません。「分岐条件が約10個」をもっと詳しく、ここに書いてあること以外は第三者は知り得ないということを理解していただいて、ここを読めば分かるように書いてください。データソースがどうなっているのかから分からないと少なくとも自分には何の提案もできません。

    キャンセル

回答 2

checkベストアンサー

+1

せっかく説明していただいたのに何ですが、判定ロジックが理解できませんので、判定ロジックの改善案の提案はできません。(350 行を短くするための提案や判定ロジックのコードを読みやすくするための提案はできませんという意味です)

代わりに、もっと基本的な改善案、プレゼンテーション層、ビジネスロジック層、データ層という 3 層構造に分けることを提案します。

3 層構造がどういうものかについては以下の記事の図1を見てください。

第1回 ASP.NETによる3階層Webアプリ「ITブック」構築
http://www.atmarkit.co.jp/fdotnet/chushin/kaizowebui_01/kaizowebui01_01.html

今の質問者さんのコードは、判定ロジックが ASPX ページのコードビハインドに含まれている、即ち、プレゼンテーション層(ASPX ページ)とビジネスロジック層(判定ロジック)が一緒になっていて 2 層構造になっています。

これを 3 層構造にする、即ち、GridView の RowDataBound イベントのハンドラに判定ロジックを含めるのではなく、別にクラスファイルを作ってそれに含めるようにします。そうすれば、少なくとも ASPX ページのコードの可読性や全体の保守性はかなり上がると思います。

具体的には、クラスファイルに、DB から生データの取得 ⇒ それをベースに各列に何を表示するかを判定 ⇒ 判定結果を戻り値として返す・・・というメソッド(即ち、ビジネスロジック)を実装します。

メソッドの戻り値は、先の質問者さんのスレッド https://teratail.com/questions/101809 で私が例として書いた List<T> 型にするのが良いと思います。

T は例えば(あくまで例えばです)以下のようにし、Application1 ~ 6 には判定ロジックで生データを判定した結果("applied", "N/A", "check", "unckeck" など)を格納します。

public class Result
{
    public string ControlNumber { get; set; }
    public string UserName { get; set; }
    public string Application1 { get; set; }
    public string Application2 { get; set; }
    public string Application3 { get; set; }
    public string Application4 { get; set; }
    public string Application5 { get; set; }
    public string Application6 { get; set; }
}

ASPX ページには GridView と ObjectDataSource を実装し、クラスファイルに実装したメソッドを ObjectDataSource の SelectMethod に設定すれば、判定結果(上の例で言うと "applied", "N/A", "check", "unckeck")が表示できます。

ChackBox にする必要はなくて、結果を文字列として表示できれば良いのであればそれだけで済むはずです。

どうしても CheckBox と Label を切り替えて表示したいということであれば、GridView の RowDataBound イベントのハンドラで処置するなどもう一工夫必要ですが、ASPX ページのコードの可読性は格段に上がるはずです。

【追記】

サンプルを作ったのでアップしておきます。Result クラスは上のものから簡略化しました。.aspx のコードで、GridView1 が文字列で表示、GridView2 が CheckBox と Label を切り替えて表示するようにしています。

ビジネスロジック

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

public class Result
{
    public string Name { get; set; }
    public string App1 { get; set; }
    public string App2 { get; set; }
    public string App3 { get; set; }
}

public class BusinessLogic
{
    public List<Result> GetResults()
    {
        List<Result> results = new List<Result>()
        {
            new Result() { Name = "ユーザー1", App1 = "チェック未", App2 = "申請不可", App3 = "チェック未" },
            new Result() { Name = "ユーザー2", App1 = "チェック済", App2 = "チェック未", App3 = "申請済" },
            new Result() { Name = "ユーザー3", App1 = "チェック未", App2 = "チェック済", App3 = "チェック済" }
        };

        return results;
    }
}

.aspx 

<%@ Page Language="C#" AutoEventWireup="true" 
    CodeFile="0022-GridViewCheckBox.aspx.cs" 
    Inherits="_0022_GridViewCheckBox" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ObjectDataSource ID="ObjectDataSource1" 
            runat="server" SelectMethod="GetResults" 
            TypeName="BusinessLogic">
        </asp:ObjectDataSource>

        <asp:GridView ID="GridView1" runat="server" 
            AutoGenerateColumns="False" 
            DataSourceID="ObjectDataSource1">
            <Columns>
                <asp:BoundField DataField="Name" HeaderText="ユーザー名" />
                <asp:BoundField DataField="App1" HeaderText="申請項目1" />
                <asp:BoundField DataField="App2" HeaderText="申請項目2" />
                <asp:BoundField DataField="App3" HeaderText="申請項目3" />
            </Columns>

        </asp:GridView>

        <asp:GridView ID="GridView2" runat="server" 
            AutoGenerateColumns="False" 
            DataSourceID="ObjectDataSource1">
            <Columns>
                <asp:BoundField DataField="Name" HeaderText="ユーザー名" />
                <asp:TemplateField HeaderText="申請項目1">
                    <ItemTemplate>
                        <asp:CheckBox ID="CheckBox1" runat="server" 
                            Visible='<%# CheckBoxVisible((string)Eval("App1")) %>'
                            Checked='<%# IsChecked((string)Eval("App1")) %>' />
                        <asp:Label ID="Label1" runat="server" Text='<%# Eval("App1") %>'
                            Visible='<%# LabelVisible((string)Eval("App1")) %>'>
                        </asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="申請項目2">
                    <ItemTemplate>
                        <asp:CheckBox ID="CheckBox2" runat="server"
                            Visible='<%# CheckBoxVisible((string)Eval("App2")) %>'
                            Checked='<%# IsChecked((string)Eval("App2")) %>' />
                        <asp:Label ID="Label2" runat="server" Text='<%# Eval("App2") %>'
                            Visible='<%# LabelVisible((string)Eval("App2")) %>'>
                        </asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="申請項目3">
                    <ItemTemplate>
                        <asp:CheckBox ID="CheckBox3" runat="server"
                            Visible='<%# CheckBoxVisible((string)Eval("App3")) %>'
                            Checked='<%# IsChecked((string)Eval("App3")) %>' />
                        <asp:Label ID="Label3" runat="server" Text='<%# Eval("App3") %>'
                            Visible='<%# LabelVisible((string)Eval("App3")) %>'>
                        </asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>

        </asp:GridView>
    </form>
</body>
</html>

.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _0022_GridViewCheckBox : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected bool LabelVisible(string str)
    {
        if (str == "チェック未" || str == "チェック済")
        {
            return false;
        }
        return true;
    }

    protected bool CheckBoxVisible(string str)
    {
        if (str == "チェック未" || str == "チェック済")
        {
            return true;
        }
        return false;
    }

    protected bool IsChecked(string str)
    {
        if (str == "チェック未")
        {
            return false;
        }

        if (str == "チェック済")
        {
            return true;
        }

        return false;
    }    
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/28 14:54

    判定はビジネスロジック化して分離、ラベルとチェックボックスの表示切替は小さな共通化メソッド化と、SurferOnWwwさんとkenshirouさんから頂いた回答を元に実装することに致しました。

    サンプルもご提示いただいたので、SurferOnWwwさんをベストアンサーとさせていただきました。
    お二人ともありがとうございました。

    キャンセル

+1

これは直接の回答ではありません。

6項目分で異なる分岐があるのであれば、
それはコードとして書かなければなりません。

ただし、どちらかというと方法論になりますが、

チェックボックスを出すか、テキスト(ラベルを出すか)

という処理であれば、共通化できるのではないかと思います。

例えば、共通化のメソッドの引数として、
・ラベル・チェックボックスの識別子("1"なら"lbl1"と"chk1"が対象、等)
・チェックボックス表示か、ラベル表示かの区分
(例えばBooleanで、Trueならチェックボックス表示、Falseならラベル表示、等)
・チェックボックス表示の場合、デフォルトのチェック(Boolean)
・ラベル表示の場合のラベル内容(String)

を用意し、各分岐で上記メソッドを呼び出して対応すれば、分岐処理の部分がスッキリする
(少なくとも、Case文内の3行は1行になる)のではないかと思いますが、
如何でしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/27 18:40

    おっしゃるとおりの方法で共通化することで、一つ一つの分岐の中の記述はかなりスッキリさせることが出来そうです! 早速試してみます。

    キャンセル

  • 2017/12/28 09:40

    質問内容が編集されたので、以下の提案がうまく適用できるかどうか不明ですが、
    もし、申請種類とDB値でその対処法が決まるのであれば、申請種類とDB値に応じた情報
    (例えば上記で説明した共通化メソッドの引数のような情報)を、何らかのテーブル
    (DBで管理してもいいし、外部設定ファイルを用意してもいいです)に用意すれば、
    このテーブルを参照することにより、Case文の分岐も不要になります。
    もし、この方法が使えるのであれば、メンテナンス性も良くなると思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • VB.NET

    832questions

    Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

  • ASP.NET

    456questions

    ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

  • .NET Framework 4.0

    58questions

    Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。