WebSurfer's Home

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

多言語対応カスタムコンロトール

by WebSurfer 2010年12月6日 21:33

リソースファイルを用いて多言語対応させた Web カスタムコントロールの話です。

多言語対応カスタムコンロトール

Culture, UICulture の値として "auto" を設定した場合には、ASP.NET がリクエスト情報に含まれる Accept-Language ヘッダの内容から判断して、自動的にカルチャを特定してくれます。

上の画像は、IE8 で言語をフランス語(フランス) fr-FR に設定してページを要求した結果、サーバー側でカルチャが fr-FR と判断され、カスタムコントロールのリソースファイル Resource.fr-FR.resx に定義されたフランス語のリソース(今回の例では、文字列 Adresse e-mail, Enregister)が表示されたものです。

この例に使ったカスタムコントロールの構成は以下の通りです。リソースの基になるのが Resource.resx で、これはソリューションエクスプローラ上で手動で追加します。その下の Resource.Designer.cs は「厳密に型指定されたリソースクラス」というもので、Resource.resx を追加すると自動生成されます。

カスタムコントロールの構成

Resource.resx にはデフォルトのリソースを定義します。今回の例では、下の画像に示すように LabelText, ButtonText という名前の 2 つの文字列です。要求されたカルチャのリソースファイルがない場合(この例では en-US, fr-FR, ja-JP 以外が指定された場合)、Resource.resx に定義されたリソースが使われます。

デフォルトのリソース

Resource.Designer.cs には Resource という名前のクラスが定義され、その中にカルチャを設定する Culture 静的プロパティ、ローカライズされたリソースを取得する静的プロパティ(この例では Resource.resx で設定した LabelText, ButtonText と同じ名前のプロパティ)が定義されます。

ローカライズされたリソースは個別のリソースファイルを追加して定義します。例えば、フランス語(フランス)の場合は Resource.fr-FR.resx という名前のリソースファイルを追加し、以下の画像のように Resource.resx で設定した LabelText, ButtonText と同じ名前でフランス語の文字列を設定します。

フランス語(フランス)の場合の Resource.fr-FR.resx

今回の例に用いた MyServerControl.cs の内容は以下の通りです。以下のコードで、Resource というのが Resource.Designer.cs で定義される「厳密に型指定されたリソースクラス」です。

Resource.Culture 静的プロパティで現在のカルチャを設定し、設定されたカルチャのリソースファイルからローカライズされた文字列を、Resource.LabelText, Resource.ButtonText 静的プロパティを用いて取得しています。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.Globalization;

namespace MultiLanguageServerControl
{
  public class MyServerControl : WebControl
  {
    public virtual string LabelText
    {
      get
      {
        string s = (string)ViewState["LabelText"];
        if (s == null)
        {
          Resource.Culture = Thread.CurrentThread.CurrentUICulture;
          s = Resource.LabelText;
        }
        return s;
      }
      set
      {
        ViewState["LabelText"] = value;
      }
    }

    public virtual string ButtonText
    {
      get
      {
        string s = (string)ViewState["ButtonText"];
        if (s == null)
        {
          Resource.Culture = 
              Thread.CurrentThread.CurrentUICulture;
          s = Resource.ButtonText;
        }
        return s;
      }
      set
      {
        ViewState["ButtonText"] = value;
      }
    }

    protected override HtmlTextWriterTag TagKey
    {
      get
      {
        return HtmlTextWriterTag.Table;
      }
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
      StringBuilder sb = new StringBuilder();
      sb.AppendLine("<tr>");
      sb.AppendFormat("<td><span id=\"Label1\">{0}</span></td>", 
        LabelText);
      sb.Append("<td><input type=\"text\" id=\"TextBox1\" /></td>");
      sb.AppendFormat(
        "<td><input type=\"submit\" value=\"{0}\" id=\"Button1\" /></td>", 
        ButtonText);
      sb.AppendLine("</tr>");
      writer.Write(sb.ToString());
    }
  }
}

このソリューションをビルドすると、以下のような dll が生成されます。この MultiLanguageServerControl.dll と en-US, fr-FR, ja-JP フォルダを中身ごと Web アプリケーションの Bin フォルダにコピーします。

ソリューションをビルドした結果

aspx ページでは以下のように Culture, UICulture を "auto" に設定し、ブラウザの言語を希望の言語(今回の例では、ja-JP または en-US または fr-FR)に設定してページを要求すれば、当該リソースファイルからローカライズされた文字列が取得されます。例えば fr-FR とすれば、一番上の画像のように表示されます。(設定を忘れるとどうなるかは、この記事の下の方の「2016/6/17 追記」を見てください)

<%@ Page Language="C#" Culture="auto" UICulture="auto" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Threading" %>
<%@ Register Assembly="MultiLanguageServerControl" 
  Namespace="MultiLanguageServerControl" 
  TagPrefix="cc2" %>

<!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 Page_Load(object sender, EventArgs e)
  {
    CultureInfo ci = Thread.CurrentThread.CurrentUICulture;
    Label1.Text = "現在の CultureInfo: " + ci.ToString();
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:Label ID="Label1" runat="server" />
    <br /><br />
    <cc2:MyServerControl runat="server" />
  </div>
  </form>
</body>
</html>

aspx ページ本体の多言語化の話は別途・・・というより、@IT の記事 リソース・ファイル活用で国際化対応ページを構築するには? を見たほうが早いかも。

-------- 2016/6/17 追記 --------

Culture, UICulture を "auto" に設定すると、ASP.NET は、ブラウザから送信されてくる要求ヘッダに含まれる Accept-Language の設定を調べて、その要求を処理するスレッドのカルチャを Accept-Language に設定されているカルチャに書き換えるようです。

そして、実行時に、リソースマネージャが要求を処理しているスレッドのカルチャ情報を参照してローカライズされたリソースを検索し、UI に表示されるテキストを取得するという仕組みになっています。

Culture, UICulture を "auto" に設定するのを忘れるとブラウザの言語設定は無視されます。デフォルトではシステムのロケールに該当するカルチャがスレッドに設定されますので、例えば日本語 OS で xxx.ja-JP.resx というリソースがあれば、常にそれから UI に表示されるテキストを取得します。

Web サイトが日本語専用でサーバーも日本にあれば忘れても問題ないかもしれませんが、ホスティングサービス(Azure も含む)でサーバーが外国にある場合は Culture, UICulture を "auto" に設定するのを忘れると問題が出ると思います。

ロケール、カルチャ、Culture と UICulture の違いなどについては、記事「カルチャの基本とカルチャ情報」が参考になりましたので、忘れないようにリンクを張っておきます。

Tags: , ,

Web Custom Control

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

About this blog

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

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar