WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

DetailsView 中の連動 DropDownList

by WebSurfer 2010年12月4日 16:23

GridView や DetailsView などのデータバインドコントロールを使ってレコードの更新や挿入を行う場合、データを DropDownList の一覧から選択してもらうことがあります。

DetailsView 中の連動 DropDownList

このとき、DropDownList の SelectedValue プロパティに '<%# Bind("xxx") %>' のようにデータバインドメソッドを設定すると、最初に更新画面を表示するときはオリジナルのデータで DropDownList のアイテムが選択されて表示され、異なるアイテムを選択して更新をかけるとそのアイテムの Value でデータベースを更新できます。

ただし、2 つの DropDownList を配置して、それを連動させる場合は以下のような問題があり、注意が必要です。

例えば、上の画像に示すように、DetailsView に 2 つの DropDownList を配置し、1 つめの DropDownList で飲み物というカテゴリーを選択すると、2 つめの DropDownList には飲み物に分類される商品が絞り込まれて表示されるケースを考えます。

2 つの DropDownList の SelectedValue プロパティに、それぞれ '<%# Bind("CategoryID") %>' および '<%# Bind("ProductID") %>' というようなデータバインドメソッドが設定してあるとします。

ReadOnly モードで表示された状態から[編集]ボタンをクリックして Edit モードに移った直後は、DropDownList に正しくアイテムが選択されて表示されますが、1 つめの DropDownList のアイテムの選択を変更すると、"Eval()、XPath()、および Bind() のようなデータバインド メソッドは、データバインドされたコントロールのコンテキストでのみ使用することができます。" というエラーになります。

(ArgumentOutOfRangeException で "項目一覧に存在しないため、'DropDownList2' に SelectedValue を指定することは無効です。" になるのかと思いましたがそうではなかったです。詳細は不明ですが、Page.GetDataItem メソッドでデータ バインディングコンテキストを取得できないのが原因らしいです。)

エラーを回避するには、2 つめの DropDownList の SelectedValue='<%# Bind("ProductID") %>' を削除すればよいです。

ただし、削除すると、オリジナルのデータが DropDownList で選択・表示されず、かつ、データベースの更新ができなくなります。

その問題の解決策は、DetailsView の DataBound イベントハンドラで DropDownList の SelectedValue を設定すること、および、SqlDataSource の Updating イベントハンドラで SqlParameter に直接 SelectedValue を代入することです。

以下に、DetailsView に 2 つの DropDownList を配置し、それらを連動させた場合のサンプルコードをアップしておきます。Products と Categories テーブルは Northwind サンプルデータベースのものです。Sales テーブルは自作でスキーマは以下の通りです。

CREATE TABLE [dbo].[Sales](
  [ID] [int] IDENTITY(1,1) NOT NULL,
  [CategoryID] [int] NOT NULL,
  [ProductID] [int] NOT NULL,
 CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED 
(
  [ID] ASC
)WITH (PAD_INDEX  = OFF ・・・中略・・・)
)

aspx ページのコードは以下の通りです。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  protected void DetailsView1_DataBound(object sender, EventArgs e)
  {
    // DropDownList2 の SelectedValue プロパテ
    // ィに '<%# Bind("ProductID") %>' を設定
    // しない代わりに以下のようにする。

    if (DetailsView1.CurrentMode == DetailsViewMode.Edit)
    {
      DropDownList ddl =
        (DropDownList)DetailsView1.FindControl("DropDownList2");
      ddl.SelectedValue =
        ((DataRowView)DetailsView1.DataItem)["ProductID"].ToString();
    }
        
    // Insert モードでは DetailsView1.DataItem が
    // null なので SelectedValue の設定はできない。
    // と言うより、そもそも Insert モードでは設定
    // する意味はない。
  }
    
  protected void SqlDataSource1_Updating(object sender, 
    SqlDataSourceCommandEventArgs e)
  {
    // SelectedValue='<%# Bind("ProductID") %>'
    // としていないので、以下のようにパラメータ
    // に直接 SelectedValue を代入する。
    DropDownList ddl = 
      (DropDownList)DetailsView1.FindControl("DropDownList2");
    e.Command.Parameters["@ProductID"].Value = ddl.SelectedValue;
  }

  protected void SqlDataSource1_Inserting(object sender, 
    SqlDataSourceCommandEventArgs e)
  {
    DropDownList ddl =
      (DropDownList)DetailsView1.FindControl("DropDownList3");
    e.Command.Parameters["@CategoryID"].Value = ddl.SelectedValue;
    ddl = (DropDownList)DetailsView1.FindControl("DropDownList4");
    e.Command.Parameters["@ProductID"].Value = ddl.SelectedValue;
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      DeleteCommand="DELETE FROM [Sales] WHERE ([ID] = @ID)" 
      InsertCommand="INSERT INTO [Sales] ([CategoryID], [ProductID]) 
        VALUES (@CategoryID, @ProductID)" 
      SelectCommand= "SELECT s.ID, s.CategoryID, s.ProductID, c.CategoryName, p.ProductName 
        FROM Sales AS s 
        INNER JOIN Categories AS c ON s.CategoryID = c.CategoryID 
        INNER JOIN Products AS p ON s.ProductID = p.ProductID" 
      UpdateCommand="UPDATE [Sales] 
        SET [CategoryID] = @CategoryID, [ProductID] = @ProductID 
        WHERE ([ID] = @ID)" 
      OnUpdating="SqlDataSource1_Updating" 
      OnInserting="SqlDataSource1_Inserting">
      <DeleteParameters>
        <asp:Parameter Name="ID" Type="Int32" />
      </DeleteParameters>
      <InsertParameters>
        <asp:Parameter Name="CategoryID" Type="Int32" />
        <asp:Parameter Name="ProductID" Type="Int32" />
      </InsertParameters>
      <UpdateParameters>
        <asp:Parameter Name="CategoryID" Type="Int32" />
        <asp:Parameter Name="ProductID" Type="Int32" />
        <asp:Parameter Name="ID" Type="Int32" />
      </UpdateParameters>
    </asp:SqlDataSource>
    <asp:DetailsView ID="DetailsView1" 
      runat="server" AllowPaging="True" 
      AutoGenerateRows="False" 
      DataKeyNames="ID" 
      DataSourceID="SqlDataSource1" 
      EnableModelValidation="True" 
      OnDataBound="DetailsView1_DataBound">
      <Fields>
        <asp:BoundField DataField="ID" 
          HeaderText="ID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="ID" />

        <asp:TemplateField HeaderText="CategoryName" 
          SortExpression="CategoryName">
          <EditItemTemplate>
            <asp:SqlDataSource ID="SqlDataSource2" 
              runat="server" 
              ConnectionString="<%$ ConnectionStrings:Northwind %>" 
              SelectCommand="SELECT [CategoryID], [CategoryName] 
                FROM [Categories]">
            </asp:SqlDataSource>
            <asp:DropDownList ID="DropDownList1" 
              runat="server" 
              DataSourceID="SqlDataSource2" 
              DataTextField="CategoryName" 
              DataValueField="CategoryID" 
              AutoPostBack="True"
              SelectedValue='<%# Bind("CategoryID") %>'>
            </asp:DropDownList>
          </EditItemTemplate>
          <InsertItemTemplate>
            <asp:SqlDataSource ID="SqlDataSource4" 
              runat="server" 
              ConnectionString="<%$ ConnectionStrings:Northwind %>" 
              SelectCommand="SELECT [CategoryID], [CategoryName] 
                FROM [Categories]">
            </asp:SqlDataSource>
            <asp:DropDownList ID="DropDownList3" 
              runat="server" 
              DataSourceID="SqlDataSource4" 
              DataTextField="CategoryName" 
              DataValueField="CategoryID" 
              AutoPostBack="True">
            </asp:DropDownList>
          </InsertItemTemplate>
          <ItemTemplate>
            <asp:Label ID="Label1" 
              runat="server" 
              Text='<%# Bind("CategoryName") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="ProductName" 
          SortExpression="ProductName">
          <EditItemTemplate>
            <asp:SqlDataSource ID="SqlDataSource3" 
              runat="server" 
              ConnectionString="<%$ ConnectionStrings:Northwind %>" 
              SelectCommand="SELECT [ProductID], [ProductName] 
                FROM [Products] 
                WHERE ([CategoryID] = @CategoryID)">
              <SelectParameters>
                <asp:ControlParameter 
                  ControlID="DropDownList1" 
                  Name="CategoryID" 
                  PropertyName="SelectedValue" 
                  Type="Int32" />
              </SelectParameters>
            </asp:SqlDataSource>

            <%-- SelectedValue='<%# Bind("ProductID") %>' 
                 と設定するのは NG --%>
            <asp:DropDownList ID="DropDownList2" 
              runat="server" 
              DataSourceID="SqlDataSource3" 
              DataTextField="ProductName" 
              DataValueField="ProductID">
            </asp:DropDownList>
          </EditItemTemplate>
          <InsertItemTemplate>
            <asp:SqlDataSource ID="SqlDataSource5" 
              runat="server" 
              ConnectionString="<%$ ConnectionStrings:Northwind %>" 
              SelectCommand="SELECT [ProductID], [ProductName] 
                FROM [Products] 
                WHERE ([CategoryID] = @CategoryID)">
              <SelectParameters>
                <asp:ControlParameter 
                  ControlID="DropDownList3" 
                  Name="CategoryID" 
                  PropertyName="SelectedValue" 
                  Type="Int32" />
              </SelectParameters>
            </asp:SqlDataSource>
            <asp:DropDownList ID="DropDownList4" 
              runat="server" 
              DataSourceID="SqlDataSource5" 
              DataTextField="ProductName" 
              DataValueField="ProductID">
            </asp:DropDownList>
          </InsertItemTemplate>
          <ItemTemplate>
            <asp:Label ID="Label2" 
              runat="server" 
              Text='<%# Bind("ProductName") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:CommandField 
          ShowDeleteButton="True" 
          ShowEditButton="True" 
          ShowInsertButton="True" />
      </Fields>
    </asp:DetailsView>
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

Chart (ASP.NET Web Forms 用)

by WebSurfer 2010年11月27日 18:41

ASP.NET Web Forms アプリでグラフを表示するのに使う Microsoft 製の Chart コントロールについて調べたことで、備忘録として残しておいたほうがよさそうなことを書いておきます。

Chart コントロールを使ったグラフ

グラフを表示する仕組みは一般的な画像の場合と同じで、html タグの img 要素を用います。

異なるのは、プログラムで指定された内容・形式のグラフの画像(デフォルトで png 形式)を作成し、src 属性に画像データの取得方法を指定して img 要素をレンダリングすることを、Chart コントロールが動的に行う点です。

その後は一般的な静的画像を表示する場合と同じで、ブラウザが src 属性に指定された方法で画像をサーバーに要求し、サーバーから応答として受けた画像を img 要素の位置に表示します。

src 属性に指定される画像の取得方法には、以下に述べる 3 つのオプションがあります。

  1. HTTP ハンドラ: Chart コントロールが自動的に HTTP ハンドラを定義し、それを src 属性に指定して img 要素に含めてブラウザに送ります。画像データは、サーバーの特定のフォルダ、メモリまたは Session に一時的に保存されます。ブラウザから画像データの要求を受けると、HTTP ハンドラがそれを取得してブラウザに送信します。
  2. 静的ファイル: Web サーバーのファイルシステム下にあるフォルダに静的画像ファイルを作って保存します。img 要素の src 属性にその画像のパス/ファイル名を指定してブラウザに送ります。
  3. バイナリデータ: Chart コントロールが生成したバイナリ画像データを直接応答として返す aspx ページを作成し、それを img 要素の src に指定します。

HTTP ハンドラを用いる方法がデフォルトですので、それについて書いておきます。なお、HTTP ハンドラを用いる方法がベストというわけではなく、3 つのオプションには一長一短があるので、ケースバイケースで決めるべきだそうです。

詳しくは、Using Microsoft's Chart Controls In An ASP.NET Application: Rendering the Chart を参照してください。

Visual Studio で Chart コントロールを ASP.NET ページにドラッグ&ドロップすると、web.config にデフォルトで ChartImageHandler という名前の HTTP ハンドラが定義されます。.NET 4 の場合は以下のようになります。

<system.web>
  <httpHandlers>
    <add path="ChartImg.axd"
      verb="GET,HEAD,POST"
      type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler,
        System.Web.DataVisualization,
        Version=4.0.0.0, 
        Culture=neutral,
        PublicKeyToken=31bf3856ad364e35"
        validate="false" />
  </httpHandlers>
 ・・・中略・・・
</system.web>
<system.webServer>
 ・・・中略・・・
  <handlers>
    <remove name="ChartImageHandler" />
    <add name="ChartImageHandler" 
      preCondition="integratedMode" 
      verb="GET,HEAD,POST"
      path="ChartImg.axd" 
      type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler,
        System.Web.DataVisualization,
        Version=4.0.0.0, 
        Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35" />
  </handlers>
</system.webServer>

上記のように system.web 要素内と system.webServer 要素内の両方で HTTP ハンドラが定義されますので、IIS のアプリケーションプールのマネージパイプラインモードが Integrated mode の場合はエラーになります。対処方法は、先の記事 IIS7 Integrated mode での BlogEngine の実行 で述べたとおりです。

ただし、.NET 3.5 では <validation validateIntegratedModeConfiguration="false"/> がデフォルトの web.config に定義されているので何もしなくてもエラーは出ないはずです。.NET 4 の場合はそれが定義されていませんので対応が必要になります。

さらに、web.config には、一時的に画像データを保存する方法、場所等が定義されます。デフォルトで以下のようになるはずです。

<appSettings>
  <add key="ChartImageHandler" 
    value="storage=file;timeout=20;dir=c:\TempImageFiles\;" />
</appSettings>

value 属性のパラメーターの詳しい説明は MSDN ライブラリの イメージ ファイルの管理 を参照してください。重要な(と個人的に思う)パラメータのみ以下に説明します。

パラメーター storage は画像データを保存する方法を指定するもので、file, memory, session の 3 つのオプションがあります。読んで字のごとく、それぞれ、サーバーの特定のフォルダ(デフォルト)、実行中のプロセスのメモリ空間、セッション変数になります。

パラメーター dir は、storage=file の場合の、イメージ保存場所の絶対ディレクトリパス(上記の例では c:\TempImageFiles)です。web ファームの場合は、ネットワークパスを使用して共有ファイルサーバーのフォルダとすることができます。

なお、当然ですが、IIS のワーカープロセスにはイメージ保存場所の絶対ディレクトリに対する読み取り/書き込み権限を与える必要があります。

dir の代わりに url というパラメータを使って、アプリケーションルート下のフォルダを指定することも可能です。c:\TempImageFiles などとできない、レンタル共有サーバーの場合この方法が使えます。ただし、他のユーザーもアクセスできてしまう場所に保存するのは好ましくなさそうです。そもそも、HTTP ハンドラを用いる目的は、ユーザーが直接アクセスできない場所に画像を保存するためですので。

その他、ASP.NET ページの @ Register ディレクティブ、または web.config 内で pages の controls の add 要素に、Chart コントロールを指定する tagPrefix、namespace、および assembly の各属性を定義する必要があります。これは Visual Studio で Chart コントロールをドラッグ&ドロップすると、自動的にコードが生成されるはずです。

HTTP ハンドラーを使用する場合は Chart.ImageStorageMode プロパティを UseHttpHandler に設定しますが、これはデフォルトでそうなっています。上に述べた「静的ファイル」のオプションを選択した場合は、UseImageLocation に設定する必要があります。

以上の設定をして、グラフを作る Chart コントロールを含んだページを要求すると、以下のような img 要素がレンダリングされ、ブラウザに送信されるはずです。

<img id="Chart1" 
  src="/ChartImg.axd?i=chart_0_0.png&g=6d177535e0d24eb8b9a60872279889e8" 
  alt="" 
  style="height:300px;width:600px;border-width:0px;" />

ブラウザが src 属性に指定されたページをサーバーに要求すると、サーバーは HTTP ハンドラを使って画像データを取得してブラウザに返し、それを受けたブラウザは img 要素の位置に画像を表示します。

参考に、上に表示したグラフを作ったコードをアップしておきます。内容は @IT の記事「チャート・コントロールで積み上げ棒グラフを作成するには?」そのものです。

<%@ Page Language="C#" %>

<%@ Register Assembly="System.Web.DataVisualization, 
    Version=4.0.0.0, Culture=neutral, 
    PublicKeyToken=31bf3856ad364e35"
  Namespace="System.Web.UI.DataVisualization.Charting" 
  TagPrefix="asp" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <%-- .NET 3.5 のときは無くても OK だった N プレフィックスが何故か必要 --%>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:MyDB %>" 
      SelectCommand="SELECT 
      Month, 
      SUM(CASE WHEN Name = N'三吉' THEN Sales ELSE 0 END) AS 三吉, 
      SUM(CASE WHEN Name = N'春日' THEN Sales ELSE 0 END) AS 春日, 
      SUM(CASE WHEN Name = N'東雲' THEN Sales ELSE 0 END) AS 東雲, 
      SUM(CASE WHEN Name = N'府中' THEN Sales ELSE 0 END) AS 府中, 
      SUM(CASE WHEN Name = N'広島' THEN Sales ELSE 0 END) AS 広島 
       FROM Shop GROUP BY Month">
    </asp:SqlDataSource>
    <asp:Chart ID="Chart1" 
      runat="server" 
      DataSourceID="SqlDataSource1" 
      Width="600px">
      <Legends>
        <asp:Legend DockedToChartArea="ChartArea1" 
          IsDockedInsideChartArea="False" 
          Name="Legend1">
       </asp:Legend>
      </Legends>
      <Series>
        <asp:Series Name="三吉" 
          ChartType="StackedColumn" 
          CustomProperties="DrawingStyle=Cylinder" 
          IsValueShownAsLabel="True" 
          Label="#PERCENT{P1}" 
          Legend="Legend1" 
          XValueMember="Month" 
          YValueMembers="三吉">
        </asp:Series>
        <asp:Series Name="春日" 
          ChartArea="ChartArea1" 
          ChartType="StackedColumn" 
          CustomProperties="DrawingStyle=Cylinder" 
          IsValueShownAsLabel="True" 
          Label="#PERCENT{P1}" 
          Legend="Legend1" 
          XValueMember="Month" 
          YValueMembers="春日">
        </asp:Series>
        <asp:Series Name="東雲" 
          ChartArea="ChartArea1" 
          ChartType="StackedColumn" 
          CustomProperties="DrawingStyle=Cylinder" 
          IsValueShownAsLabel="True" 
          Label="#PERCENT{P1}" 
          Legend="Legend1" 
          XValueMember="Month" 
          YValueMembers="東雲">
        </asp:Series>
        <asp:Series Name="府中" 
          ChartArea="ChartArea1" 
          ChartType="StackedColumn" 
          CustomProperties="DrawingStyle=Cylinder" 
          IsValueShownAsLabel="True" 
          Label="#PERCENT{P1}" 
          Legend="Legend1" 
          XValueMember="Month" 
          YValueMembers="府中">
        </asp:Series>
        <asp:Series Name="広島" 
          ChartArea="ChartArea1" 
          ChartType="StackedColumn" 
          CustomProperties="DrawingStyle=Cylinder" 
          IsValueShownAsLabel="True" 
          Label="#PERCENT{P1}" 
          Legend="Legend1" 
          XValueMember="Month" 
          YValueMembers="広島">
          <EmptyPointStyle IsVisibleInLegend="False" />
        </asp:Series>
      </Series>
      <ChartAreas>
        <asp:ChartArea Name="ChartArea1">
          <AxisY Title="売上高">
          </AxisY>
          <AxisX Title="売上月">
          </AxisX>
        </asp:ChartArea>
      </ChartAreas>
    </asp:Chart>
  </div>
  </form>
</body>
</html>

Tags:

ASP.NET

SqlDataSource とトランザクション

by WebSurfer 2010年11月16日 22:52

SqlDataSource + DetailsView による更新が成功したら、変更されたフィールド名、更新前/後の値、変更日時をログとして SQL Server データベースに残す処置をトランザクションを切って行う方法です。

更新前/後の値の取得と、SqlDataSorce コントロールによる UPDATE 操作と ADO.NET のコードによる INSERT 操作のトランザクションをどのように設定するかがポイントだと思います。

まず、更新前/後の値ですが、これらは DetailsView.ItemUpdating イベントのハンドラにおいて、引数の DetailsViewUpdateEventArgs オブジェクトから Keys, OldValues, NewValues プロパティによって取得できます。

トランザクションの開始および SqlTranscation オブジェクトの取得、SqlCommand.Transaction プロパティのへの SqlTranscation オブジェクトの設定は、SqlDataSource.Updating イベントで行います。イベントハンドラの引数 SqlDataSourceCommandEventArgs から SqlConnection, SqlCommand オブジェクトへの参照を取得できますので、それらを用いて設定します。

ログを残すための INSERT 操作は、SqlDataSource.Updated イベントのハンドラで行います。イベントハンドラの引数 SqlDataSourceStatusEventArgs オブジェクトの Exception, AffectedRows プロパティを用いて、UPDATE 操作で例外が発生しなかったことと更新が行われたことが判定できます。

例外の発生がなく更新が行われたと判定されたら、ログを残すための操作(データベースへの INSERT 操作)を行います。INSERT 操作は、更新されたフィールドが複数の場合、同じ数だけ行うことになります。 INSERT 操作の途中で失敗した場合は、SqlDataSource による UPDATE 操作まで巻き戻すことになります。

そのために、引数 SqlDataSourceStatusEventArgs オブジェクトから、SqlDataSource が UPDATE 操作に用いた SqlConnection, SqlCommand, SqlTransaction オブジェクトへの参照を取得し、それらを用いて、SqlDataSource が行う UPDATE 操作と同じコネクション/トランザクションで INSERT 操作を行うように設定します。

サンプルコードは以下のとおりです。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  IOrderedDictionary keys;
  IOrderedDictionary oldValues;
  IOrderedDictionary newValues;
    
  protected void SqlDataSource2_Updating(object sender, 
    SqlDataSourceCommandEventArgs e)
  {
    SqlCommand command = (SqlCommand)e.Command;
    SqlConnection connection = command.Connection;
    connection.Open();
    SqlTransaction tx = connection.BeginTransaction();
    command.Transaction = tx;
  }
    
  protected void SqlDataSource2_Updated(object sender, 
    SqlDataSourceStatusEventArgs e)
  {
    SqlCommand command = (SqlCommand)e.Command;
    SqlConnection connection = command.Connection;
    SqlTransaction tx = command.Transaction;
    if (e.Exception == null && e.AffectedRows == 1)
    {
      string insertQuery = 
        "INSERT INTO History " + 
        "(FieldName, NewValue, OldValue, DateAndTime) " +
        "VALUES (@FieldName, @NewValue, @OldValue, @DateAndTime)";
      SqlCommand sqlCom = 
       new SqlCommand(insertQuery, (SqlConnection)connection);
      sqlCom.Transaction = (SqlTransaction)tx;
      sqlCom.Parameters.Add("@FieldName", SqlDbType.NVarChar);
      sqlCom.Parameters.Add("@NewValue", SqlDbType.NVarChar);
      sqlCom.Parameters.Add("@OldValue", SqlDbType.NVarChar);
      sqlCom.Parameters.Add("@DateAndTime", SqlDbType.DateTime);
      try
      {
        foreach (DictionaryEntry entry in oldValues)
        {
          if ((string)entry.Value != 
            (string)newValues[entry.Key])
          {
            sqlCom.Parameters["@FieldName"].Value = 
              (string)entry.Key;
            if (newValues[entry.Key] == null)
            {
              sqlCom.Parameters["@NewValue"].Value = DBNull.Value;
            }
            else
            {
              sqlCom.Parameters["@NewValue"].Value = 
                (string)newValues[entry.Key];
            }
            if (entry.Value == null)
            {
              sqlCom.Parameters["@OldValue"].Value = DBNull.Value;
            }
            else
            {
              sqlCom.Parameters["@OldValue"].Value = 
                (string)entry.Value;
            }
            sqlCom.Parameters["@DateAndTime"].Value = DateTime.Now;
            sqlCom.ExecuteNonQuery();
          }
        }
        tx.Commit();
      }
      catch (Exception)
      {
        if (tx != null)
        {
          tx.Rollback();
        }
        throw;
      }
      finally
      {
        connection.Close();
      }            
    }
    else
    {
      if (tx != null)
      {
        tx.Rollback();
      }
      connection.Close();
    }

    DropDownList1.DataBind();
  }

  protected void DetailsView1_ItemUpdating(object sender, 
    DetailsViewUpdateEventArgs e)
  {
    keys = e.Keys;
    oldValues = e.OldValues;
    newValues = e.NewValues;
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:MyDB %>" 
      SelectCommand="SELECT [id], [name] FROM [table]">
    </asp:SqlDataSource>
    <asp:DropDownList ID="DropDownList1" 
      runat="server" 
      DataSourceID="SqlDataSource1" 
      DataTextField="name" 
      DataValueField="id" 
      AutoPostBack="True">
    </asp:DropDownList>
    <hr />
    <asp:SqlDataSource ID="SqlDataSource2" runat="server" 
      ConnectionString="<%$ ConnectionStrings:MyDB %>" 
      SelectCommand=
        "SELECT [id], [name], [price], [memo] 
        FROM [table] 
        WHERE ([id] = @id)"             
      UpdateCommand=
        "UPDATE [table] 
        SET [name] = @name, [price] = @price, [memo] = @memo 
        WHERE [id] = @original_id" 
      OnUpdated="SqlDataSource2_Updated" 
      OnUpdating="SqlDataSource2_Updating" 
      OldValuesParameterFormatString="original_{0}">
      <SelectParameters>
        <asp:ControlParameter ControlID="DropDownList1" 
          Name="id" 
          PropertyName="SelectedValue" 
          Type="Int32" />
      </SelectParameters>
      <UpdateParameters>
        <asp:Parameter Name="name" Type="String" />
        <asp:Parameter Name="price" Type="Decimal" />
        <asp:Parameter Name="memo" Type="String" />
        <asp:Parameter Name="original_id" Type="Int32" />
      </UpdateParameters>
    </asp:SqlDataSource>
    <asp:DetailsView ID="DetailsView1" 
      runat="server" 
      AutoGenerateRows="False" 
      DataKeyNames="id" 
      DataSourceID="SqlDataSource2" 
      OnItemUpdating="DetailsView1_ItemUpdating" 
      EnableModelValidation="True">
      <Fields>
        <asp:BoundField DataField="id" 
          HeaderText="id" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="id" />
        <asp:BoundField DataField="name" 
          HeaderText="name" 
          SortExpression="name" />
        <asp:BoundField DataField="price" 
          HeaderText="price" 
          SortExpression="price" />
        <asp:BoundField DataField="memo" 
          HeaderText="memo" 
          SortExpression="memo" />
        <asp:CommandField ShowEditButton="True" />
      </Fields>
    </asp:DetailsView>    
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar