次の方法で共有


DataList の編集インターフェイスをカスタマイズする (C#)

作成者: Scott Mitchell

PDF のダウンロード

このチュートリアルでは、DropDownList と CheckBox を含む、DataList のより豊富な編集インターフェイスを作成します。

はじめに

DataList の EditItemTemplate 内のマークアップと Web コントロールは、その編集可能なインターフェイスを定義します。 これまでに説明したすべての編集可能な DataList の例では、編集可能なインターフェイスは TextBox Web コントロールで構成されています。 前のチュートリアルでは、検証コントロールを追加することで編集時のユーザー エクスペリエンスを改善しました。

EditItemTemplate をさらに拡張して、DropDownList、RadioButtonList、Calendar など、TextBox 以外の Web コントロールを含めることもできます。 TextBox と同様に、編集インターフェイスをカスタマイズして他の Web コントロールを含める場合は、以下の手順を使います。

  1. Web コントロールを EditItemTemplate に追加します。
  2. databinding 構文を使って、対応するデータ フィールド値を適切なプロパティに割り当てます。
  3. UpdateCommand イベント ハンドラーで、プログラムによって Web コントロール値にアクセスし、それを適切な BLL メソッドに渡します。

このチュートリアルでは、DropDownList と CheckBox を含む、DataList のより豊富な編集インターフェイスを作成します。 特に、製品情報を一覧表示し、製品名、仕入先、カテゴリ、生産中止状態を更新できるようにする DataList を作成します (図 1 を参照)。

編集インターフェイスには、テキストボックス、2つのドロップダウンリスト、チェックボックスが含まれています。

図 1: 編集インターフェイスには、TextBox、2 つの DropDownList、CheckBox が含まれています (クリックするとフルサイズの画像が表示されます)

手順 1: 製品情報の表示

DataList の編集可能なインターフェイスを作成する前に、まず読み取り専用インターフェイスを構築する必要があります。 まず、EditDeleteDataList フォルダーから CustomizedUI.aspx ページを開き、デザイナーから DataList をページに追加して、その ID プロパティを Products に設定します。 DataList のスマート タグから、新しい ObjectDataSource を作成します。 この新しい ObjectDataSource ProductsDataSource に名前を付け、ProductsBLL クラスの GetProducts メソッドからデータを取得するように構成します。 以前の編集可能な DataList チュートリアルと同様に、ビジネス ロジック レイヤーに直接移動して、編集した製品の情報を更新します。 そのため、[UPDATE]、[INSERT]、[DELETE] タブのドロップダウン リストを (None) に設定します。

UPDATE、INSERT、およびDELETEタブのドロップダウンリストを(なし)に設定します。

図 2: [UPDATE]、[INSERT]、[DELETE] タブのドロップダウン リストを (None) に設定します (クリックするとフルサイズの画像が表示されます)

ObjectDataSource を構成すると、Visual Studio によって、返された各データ フィールドの名前と値を一覧表示する DataList の既定の ItemTemplate が作成されます。 テンプレートの <h4> 要素に製品名がカテゴリ名、仕入先名、価格、生産中止状態と共に一覧表示されるように、ItemTemplate を変更します。 さらに、[Edit] ボタンを追加し、その CommandName プロパティが Edit に設定されていることを確認します。 ItemTemplate の宣言型マークアップは次のとおりです。

<ItemTemplate>
    <h4>
        <asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Eval("ProductName") %>' />
    </h4>
    <table border="0">
        <tr>
            <td class="ProductPropertyLabel">Category:</td>
            <td class="ProductPropertyValue">
                <asp:Label ID="CategoryNameLabel" runat="server"
                    Text='<%# Eval("CategoryName") %>' />
            </td>
            <td class="ProductPropertyLabel">Supplier:</td>
            <td class="ProductPropertyValue">
                <asp:Label ID="SupplierNameLabel" runat="server"
                    Text='<%# Eval("SupplierName") %>' />
            </td>
        </tr>
        <tr>
            <td class="ProductPropertyLabel">Discontinued:</td>
            <td class="ProductPropertyValue">
                <asp:Label ID="DiscontinuedLabel" runat="server"
                    Text='<%# Eval("Discontinued") %>' />
            </td>
            <td class="ProductPropertyLabel">Price:</td>
            <td class="ProductPropertyValue">
                <asp:Label ID="UnitPriceLabel" runat="server"
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' />
            </td>
        </tr>
        <tr>
            <td colspan="4">
                <asp:Button runat="Server" ID="EditButton"
                    Text="Edit" CommandName="Edit" />
            </td>
        </tr>
    </table>
    <br />
</ItemTemplate>

上記のマークアップは、製品名に <h4> 見出しを使い、残りのフィールドに 4 列の <table> を使って製品情報をレイアウトします。 Styles.css で定義されている ProductPropertyLabel および ProductPropertyValue CSS クラスについては、前のチュートリアルで説明しました。 図 3 は、ブラウザーで見たときのこれまでの進捗を示しています。

各製品の名前、サプライヤー、カテゴリ、販売終了ステータス、価格が表示されます

図 3: 各製品の名前、仕入先、カテゴリ、生産中止状態、価格が表示されます (クリックするとフルサイズの画像が表示されます)

手順 2: Web コントロールの編集インターフェイスへの追加

カスタマイズされた DataList 編集インターフェイスを構築する最初の手順は、必要な Web コントロールを EditItemTemplate に追加することです。 特に、DropDownList がカテゴリ用と、もう 1 つを仕入先用に、CheckBox が生産中止状態用に必要です。 この例では製品の価格は編集できないため、引き続き Label Web コントロールを使って価格を表示できます。

編集インターフェイスをカスタマイズするには、DataList のスマート タグから [テンプレートの編集] リンクをクリックし、ドロップダウン リストから EditItemTemplate オプションを選びます。 DropDownList を EditItemTemplate に追加し、その IDCategories に設定します。

カテゴリのドロップダウンリストを追加する

図 4: カテゴリの DropDownList を追加します (クリックするとフルサイズの画像が表示されます)

次に、DropDownList のスマート タグから、[データ ソースの選択] オプションを選び、CategoriesDataSource という名前の新しい ObjectDataSource を作成します。 この ObjectDataSource を、CategoriesBLL クラスの GetCategories() メソッドを使うように構成します (図 5 を参照)。 次に、DropDownList のデータ ソース構成ウィザードで、各 ListItemTextValue プロパティに使うデータ フィールドの入力を求められます。 図 6 に示すように、DropDownList に CategoryName データ フィールドを表示させ、値として CategoryID を使います。

CategoriesDataSource という名前の新しい ObjectDataSource を作成します。

図 5: CategoriesDataSource という名前の新しい ObjectDataSource を作成します (クリックするとフルサイズの画像が表示されます)

DropDownListの表示フィールドと値フィールドを構成する

図 6: DropDownList の表示フィールドと値フィールドを構成します (クリックするとフルサイズの画像が表示されます)

この一連の手順を繰り返して、仕入先の DropDownList を作成します。 この DropDownList の IDSuppliers に設定し、その ObjectDataSource に SuppliersDataSource という名前を付けます。

2 つの DropDownList を追加した後、生産中止状態を示す CheckBox と製品名を示す TextBox を追加します。 CheckBox と TextBox の ID をそれぞれ DiscontinuedProductName に設定します。 RequiredFieldValidator を追加して、ユーザーが製品名の値を確実に指定できるようにします。

最後に、[Update] ボタンと [Cancel] ボタンを追加します。 これら 2 つのボタンでは、CommandName プロパティをそれぞれ Update と Cancel に設定することが必要であることに注意してください。

編集インターフェイスを好きなようにレイアウトします。 次の宣言構文とスクリーン ショットが示すように、読み取り専用インターフェイスから同じ 4 列の <table> レイアウトを使うことにしました。

<EditItemTemplate>
    <h4>
        <asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Eval("ProductName") %>' />
    </h4>
    <table border="0">
        <tr>
            <td class="ProductPropertyLabel">Name:</td>
            <td colspan="3" class="ProductPropertyValue">
                <asp:TextBox runat="server" ID="ProductName" Width="90%" />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1"
                    ControlToValidate="ProductName"
                    ErrorMessage="You must enter a name for the product."
                    runat="server">*</asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td class="ProductPropertyLabel">Category:</td>
            <td class="ProductPropertyValue">
                <asp:DropDownList ID="Categories" runat="server"
                    DataSourceID="CategoriesDataSource"
                    DataTextField="CategoryName" DataValueField="CategoryID" />
            </td>
            <td class="ProductPropertyLabel">Supplier:</td>
            <td class="ProductPropertyValue">
                <asp:DropDownList ID="Suppliers" DataTextField="CompanyName"
                    DataSourceID="SuppliersDataSource"
                    DataValueField="SupplierID" runat="server" />
            </td>
        </tr>
        <tr>
            <td class="ProductPropertyLabel">Discontinued:</td>
            <td class="ProductPropertyValue">
                <asp:CheckBox runat="server" id="Discontinued" />
            </td>
            <td class="ProductPropertyLabel">Price:</td>
            <td class="ProductPropertyValue">
                <asp:Label ID="UnitPriceLabel" runat="server"
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' />
            </td>
        </tr>
        <tr>
            <td colspan="4">
                <asp:Button runat="Server" ID="UpdateButton" CommandName="Update"
                    Text="Update" />
                 
                <asp:Button runat="Server" ID="CancelButton" CommandName="Cancel"
                    Text="Cancel" CausesValidation="False" />
            </td>
        </tr>
    </table>
    <br />
    <asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
        TypeName="CategoriesBLL">
    </asp:ObjectDataSource>
    <asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetSuppliers"
        TypeName="SuppliersBLL">
    </asp:ObjectDataSource>
</EditItemTemplate>

編集インターフェースは読み取り専用インターフェースのようにレイアウトされています

図 7: 編集インターフェイスが読み取り専用インターフェイスと同じようにレイアウトされています (クリックするとフルサイズの画像が表示されます)

手順 3: EditCommand と CancelCommand イベント ハンドラーの作成

現在、EditItemTemplate には databinding 構文がありません (ItemTemplate から文字どおりにコピーされた UnitPriceLabel を除く)。 databinding 構文はすぐに追加しますが、最初に DataList の EditCommandCancelCommand イベントのイベント ハンドラーを作成します。 EditCommand イベント ハンドラーの役割は、[Edit] ボタンがクリックされた DataList 項目の編集インターフェイスをレンダリングすることであり、一方、CancelCommand のジョブは DataList を編集前の状態に戻すことであることを思い出してください。

これら 2 つのイベント ハンドラーを作成し、次のコードを使います。

protected void Products_EditCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property and rebind the data
    Products.EditItemIndex = e.Item.ItemIndex;
    Products.DataBind();
}
protected void Products_CancelCommand(object source, DataListCommandEventArgs e)
{
    // Return to DataList to its pre-editing state
    Products.EditItemIndex = -1;
    Products.DataBind();
}

これら 2 つのイベント ハンドラーが配置された状態で、[Edit] ボタンをクリックすると編集インターフェイスが表示され、[Cancel] ボタンをクリックすると、編集した項目が読み取り専用モードに戻ります。 図 8 は、Chef Anton の Gumbo Mix の [Edit] ボタンをクリックした後の DataList を示しています。 編集インターフェイスに databinding 構文をまだ追加していないため、ProductName TextBox は空白、Discontinued CheckBox はオフになっており、最初の項目は CategoriesSuppliers DropDownList から選ばれています。

EditCommand および CancelCommand イベント ハンドラーが追加され、[編集] ボタンが選択された後、DataList EditItemTemplate を示すスクリーンショット。

図 8: [Edit] ボタンをクリックすると編集インターフェイスが表示されます (クリックするとフルサイズの画像が表示されます)

手順 4: DataBinding 構文を編集インターフェイスに追加する

編集インターフェイスに現在の製品の値を表示させるには、databinding 構文を使って、データ フィールドの値を適切な Web コントロールの値に割り当てる必要があります。 databinding 構文は、デザイナーで [テンプレートの編集] 画面に移動し、Web コントロールのスマート タグから [DataBindings の編集] リンクを選ぶことで適用できます。 または、databinding 構文を宣言型マークアップに直接追加することもできます。

ProductName データ フィールド値を ProductName TextBox の Text プロパティに、CategoryID および SupplierID データ フィールド値を Categories および Suppliers DropDownList の SelectedValue プロパティに、Discontinued データ フィールドの値を Discontinued CheckBox の Checked プロパティに割り当てます。 デザイナーを通じて、または直接、宣言的マークアップを使ってこれらの変更を行った後、ブラウザーでページに再度アクセスし、Chef Anton の Gumbo Mix の [Edit] ボタンをクリックします。 図 9 に示すように、databinding 構文により、現在の値が TextBox、DropDownList、CheckBox に追加されています。

DataBinding 構文が追加され、編集ボタンが選択された後、DataList EditItemTemplate を示すスクリーンショット。

図 9: [Edit] ボタンをクリックすると編集インターフェイスが表示されます (クリックするとフルサイズの画像が表示されます)

手順 5: ユーザーの変更を UpdateCommand イベント ハンドラーに保存する

ユーザーが製品を編集して [Update] ボタンをクリックすると、ポストバックが発生し、DataList の UpdateCommand イベントが発生します。 イベント ハンドラーでは、EditItemTemplate の Web コントロールから値を読み取り、BLL とインターフェイスをとってデータベース内の製品を更新する必要があります。 前のチュートリアルで説明したように、更新された製品の ProductID には、DataKeys コレクションを通じてアクセスできます。 ユーザー入力フィールドには、次のコードに示すように、FindControl("controlID") を使ってプログラムで Web コントロールを参照することによってアクセスします。

protected void Products_UpdateCommand(object source, DataListCommandEventArgs e)
{
    // Make sure the page is valid...
    if (!Page.IsValid)
        return;
    // Read in the ProductID from the DataKeys collection
    int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
    // Read in the product name and price values
    TextBox productName = (TextBox)e.Item.FindControl("ProductName");
    DropDownList categories = (DropDownList)e.Item.FindControl("Categories");
    DropDownList suppliers = (DropDownList)e.Item.FindControl("Suppliers");
    CheckBox discontinued = (CheckBox)e.Item.FindControl("Discontinued");
    string productNameValue = null;
    if (productName.Text.Trim().Length > 0)
        productNameValue = productName.Text.Trim();
    int categoryIDValue = Convert.ToInt32(categories.SelectedValue);
    int supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);
    bool discontinuedValue = discontinued.Checked;
    // Call the ProductsBLL's UpdateProduct method...
    ProductsBLL productsAPI = new ProductsBLL();
    productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue,
                              discontinuedValue, productID);
    // Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1;
    Products.DataBind();
}

このコードは、まず Page.IsValid プロパティを参照して、ページ上のすべての検証コントロールが有効であることを確認します。 Page.IsValidTrue の場合、編集された商品の ProductID 値が DataKeys コレクションから読み取られ、EditItemTemplate 内のデータ入力 Web コントロールがプログラムによって参照されます。 次に、これらの Web コントロールの値が変数に読み取られてから、適切な UpdateProduct オーバーロードに渡されます。 データ更新後、DataList は編集前の状態に戻ります。

Note

コードとこの例に焦点を当てるため、BLL レベルと DAL レベルの例外を処理するチュートリアルで追加された例外処理ロジックは省略しました。 このチュートリアルを完了した後、演習としてこの機能を追加します。

手順 6: NULL CategoryID と SupplierID 値の処理

Northwind データベースでは、Products テーブルの CategoryID 列と SupplierID 列に NULL 値を使用できます。 ただし、編集インターフェイスは、現在、NULL 値に対応していません。 CategoryID 列または SupplierID 列のいずれかに NULL 値を持つ製品を編集しようとすると、ArgumentOutOfRangeException が次のようなエラー メッセージで表示されます: "'Categories' に、項目の一覧に存在しないため無効な SelectedValue があります。"また、現時点では、製品のカテゴリまたは仕入先の値を NULL 以外の値から NULL 値に変更する方法はありません。

カテゴリと仕入先の DropDownList の NULL 値をサポートするには、追加の ListItem を追加する必要があります。 この ListItemText 値として (None) を使うことを選びましたが、必要に応じて他の値 (空の文字列など) に変更できます。 最後に、確実に DropDownLists AppendDataBoundItemsTrue に設定してください。これを忘れると、DropDownList にバインドされたカテゴリと仕入先によって、静的に追加された ListItem が上書きされます。

これらの変更を行った後、DataList の EditItemTemplate 内の DropDownList のマークアップは次のようになります。

<asp:DropDownList ID="Categories" DataSourceID="CategoriesDataSource"
    DataTextField="CategoryName" DataValueField="CategoryID" runat="server"
    SelectedValue='<%# Eval("CategoryID") %>' AppendDataBoundItems="True">
    <asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>
...
<asp:DropDownList ID="Suppliers" DataSourceID="SuppliersDataSource"
    DataTextField="CompanyName" DataValueField="SupplierID" runat="server"
    SelectedValue='<%# Eval("SupplierID") %>' AppendDataBoundItems="True">
    <asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>

Note

静的 ListItem は、デザイナーを通じて、または直接、宣言構文を使って DropDownList に追加できます。 データベースの NULL 値を表す DropDownList 項目を追加する場合は、必ず宣言構文を使って ListItem を追加します。 デザイナーで ListItem コレクション エディターを使う場合、空の文字列が割り当てられた場合、生成された宣言構文では Value 設定が完全に省略され、<asp:ListItem>(None)</asp:ListItem> のような宣言型マークアップが作成されます。 これは無害に見えるかもしれませんが、Value が欠落しているため、DropDownList では代わりに Text プロパティ値が使われます。 つまり、この NULL ListItem が選択されると、値 (なし) が製品データ フィールド (このチュートリアルでは CategoryIDまたは SupplierID) に割り当てられようとし、例外が発生します。 Value=""を明示的に設定すると、 NULL ListItem が選択されたときに製品データ フィールドに NULL の値が割り当てられます。

少し時間を取って、ブラウザーで進捗を確認してみます。 製品を編集するときは、CategoriesSuppliers の両方の DropDownList で、(None) オプションが DropDownList の先頭にあることに注意してください。

カテゴリとサプライヤーのドロップダウンリストには(なし)オプションが含まれています

図 10: CategoriesSuppliers DropDownList には (None) オプションが含まれています (クリックするとフルサイズの画像が表示されます)

(None) オプションをデータベースの NULL 値として保存するには、UpdateCommand イベント ハンドラーに戻る必要があります。 DropDownList の SelectedValue が空の文字列でない場合にのみ、categoryIDValue 変数と supplierIDValue 変数を Null 許容の整数に変更し、Nothing 以外の値を割り当てます。

int? categoryIDValue = null;
if (!string.IsNullOrEmpty(categories.SelectedValue))
    categoryIDValue = Convert.ToInt32(categories.SelectedValue);
int? supplierIDValue = null;
if (!string.IsNullOrEmpty(suppliers.SelectedValue))
    supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);

この変更により、ユーザーがいずれかドロップダウン リストから (None) オプションを選んだ場合、データベース値 NULL に対応する値 NothingUpdateProduct BLL メソッドに渡されます。

まとめ

このチュートリアルでは、TextBox、2 つの DropDownList、CheckBox という 3 つの異なる入力 Web コントロールと検証コントロールを含む、より複雑な DataList 編集インターフェイスを作成する方法について説明しました。 編集インターフェイスを構築する場合、使う Web コントロールに関係なく手順は同じです。まず、Web コントロールを DataList の EditItemTemplate に追加します。databinding 構文を使って、対応するデータ フィールド値を適切な Web コントロール プロパティに割り当てます。そして、UpdateCommand イベント ハンドラーで、プログラムで Web コントロールとその適切なプロパティにアクセスし、その値を BLL に渡します。

編集インターフェイスを作成するときは、それが TextBox だけで構成されている場合でも、さまざまな Web コントロールのコレクションでも、データベースの NULL 値を正しく処理するようにします。 NULL を考慮する場合、編集インターフェイスで既存の NULL 値を適切に表示するだけでなく、値を NULL としてマークする手段を提供することが不可欠です。 DataList の DropDownList の場合、通常は、Value プロパティが空の文字列 (Value="") に明示的に設定されている静的 ListItem を追加し、UpdateCommand イベント ハンドラーに少しコードを追加して、NULL``ListItem が選ばれたかどうかを判断します。

プログラミングに満足!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.comの創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の著書は Sams Teach Yourself ASP.NET 2.0 in 24 Hoursです。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Dennis Patterson、David Suru、Randy Schmidt でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 mitchell@4GuysFromRolla.comに行をドロップしてください。