WebSurfer's Home

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

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

UpdatePanel 内の TextBox に focus

by WebSurfer 2010年11月21日 17:22

IE を使った場合、UpdatePanel 内に配置した TextBox に、ボタンクリックで非同期ポストバックした後、JavaScript でフォーカスを当てても無視されるという問題があります。

UpdatePanel 内の TextBox に focus

上の画像は以下のコードで描いたものです。UpdatePanel の外のボタンを操作した場合は TextBox にフォーカスを当てられますが、UpdatePanel の中のボタンを操作した場合は無視されます。

ちなみに、Firefox 3.6.12, Chrome 7.0.517.44, Opera 10.63, Safari 5.0.3 は、UpdatePanel の中/外どちらのボタンを操作しても期待通り TextBox にフォーカスが当たります。

解決策は、IE8 の場合のみですが、$('#TextBox1').focus().focus(); のように focus を 2 回かけることによって、UpdatePanel の中のボタンを操作した場合でもフォーカスが当たるようになります。ただし、IETester で試した限り、IE6, IE7 ではうまくいきません。IE6, IE7 の場合の解決策を検討中です。

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

<!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 FocusTextBox1_Click(object sender, EventArgs e)
  {
    ScriptManager.RegisterHiddenField(Page, "Focus", "TextBox1");
  }

  protected void FocusTextBox2_Click(object sender, EventArgs e)
  {
    ScriptManager.RegisterHiddenField(Page, "Focus", "TextBox2");
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>Focus TextBox in ControlPanel</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <script type="text/javascript">
  <!--
    $(function () {
      var manager = Sys.WebForms.PageRequestManager.getInstance();
      manager.add_pageLoaded(OnPageLoaded);
    });

    function OnPageLoaded(sender, args) {
      var target = $('#Focus').val();
      if (target == 'TextBox1') {
        $('#TextBox1').focus();
      }
      else if (target == 'TextBox2') {
        $('#TextBox2').focus();
      }
    }
  //-->
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server">
  </asp:ScriptManager>
  <h3>Focus TextBox in ControlPanel</h3>    
  <asp:Button ID="Button1" 
    runat="server" 
    Text="Focus TextBox1" 
    OnClick="FocusTextBox1_Click" />
  <asp:Button ID="Button2" 
    runat="server" 
    Text="Focus TextBox2" 
    OnClick="FocusTextBox2_Click" />
  <div style="border: solid 1px Silver; padding: 2px 5px;">
    UpdatePanel<hr />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
      <ContentTemplate>
        TextBox1: 
        <asp:TextBox ID="TextBox1" runat="server" />
        <asp:Button ID="Button3" 
          runat="server" 
          Text="Focus TextBox1" 
          OnClick="FocusTextBox1_Click" />
        <br />
        TextBox2: 
        <asp:TextBox ID="TextBox2" runat="server" />
        <asp:Button ID="Button4" 
          runat="server" 
          Text="Focus TextBox2" 
          OnClick="FocusTextBox2_Click" />
      </ContentTemplate>
    </asp:UpdatePanel>
  </div>
  </form>
</body>
</html>

------------ 2010/4/24 追記 ------------

この記事で紹介したコードを実際に動かして試せるよう 実験室 にアップしました。興味のある方は試してみてください。

Tags: , ,

AJAX

IETester

by WebSurfer 2010年11月20日 16:36

IE5.5, IE6, IE7, IE8 での動作が検証できるという IETester というツールをインストールしてみました。

IETester

DEBUGBAR という会社(?)の IETester のページ からダウンロードできます。この記事を書いている時点での最新版は v0.4.6 です。上の画像のように、日本語にも対応しています。

ご存知のように、IE はアップグレードしてしまうと、その PC ではアップグレードしたバージョンしか使えません。IETester を使うと、同一 PC 上で IE5.5, IE6, IE7, IE8 での動作が検証できるのが便利です。

ただし、完全に下位バージョンの動作を再現できるというわけではなさそうです。例えば、自分のブログの SyntaxHighlighter の表示が、IE8 では正常に表示されるものの、IE6 では一部崩れるところがあるのですが、IETester では IE8 と同様に正常に表示されます。

でも、使えそうな感じです。

Tags:

DevelopmentTools

About this blog

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

Calendar

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

View posts in large calendar