WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

XML ファイルを DataGridView に表示

by WebSurfer 26. April 2019 12:14

XML ファイルからデータを取得して Windows Forms アプリの DataGridView に表示し、それをユーザーが編集して結果を XML ファイルに書き戻すサンプルを書きます。

XML ファイルを DataGridView に表示

ASP.NET Web Forms アプリの場合は先の記事「XML ファイルの更新操作」に書きましたのでそちらを見てください。

アプリの基本的な構成は、DataGridView ⇔ BindingSource ⇔ DataSet ⇔ XML ファイルとしています。

DataSet.ReadXml メソッドで XML ファイルからデータを DataSet に読み込み、BindingSource 経由で DataGridView に表示。ユーザーが DataGridView に表示されたデータを編集後(編集結果は DataSet に反映されます)、ボタンクリックで DataSet.WriteXml メソッドにより編集結果を XML ファイルに書き戻すという操作を行います。

Windows Forms アプリの場合、ASP.NET Web Froms アプリとは違って、DataSet や DataGridView などすべてのインスタンスをユーザーの PC メモリ上に保持できますので、上記の操作が可能になります。

コードは、表示・編集・更新を行うためのごく基本的な部分だけですが、以下の通りです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form6 : Form
    {
        private DataGridView dataGridView1;
        private BindingSource bindingSource1;
        private DataSet dataset1;
        private string dir;
        private string file;

        public Form6()
        {
            InitializeComponent();            
        }

        private void Form6_Load(object sender, EventArgs e)
        {
            this.dataGridView1 = new DataGridView();
            this.dataGridView1.Dock = DockStyle.Fill;
            this.bindingSource1 = new BindingSource();
            this.dataGridView1.DataSource = this.bindingSource1;
            this.Controls.Add(this.dataGridView1);

            this.dataset1 = new DataSet();
            this.dir = @"XML ファイルのあるフォルダ";
            this.file = "XML ファイル";
            this.dataset1.ReadXml(dir + file);

            this.bindingSource1.DataSource = dataset1.Tables[0];
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Validate();
            this.bindingSource1.EndEdit();
            this.dataset1.WriteXml(dir + file, 
                                   XmlWriteMode.WriteSchema);
            this.dataset1.AcceptChanges();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.bindingSource1.RemoveCurrent();
        }
    }
}

XML ファイルはスキーマ付きにしています。その結果、DataTable の各列の DataType はスキーマに応じて型が設定され、例えば bool 型の場合はチェックボックスが表示されます。

DataSet.WriteXml で DELETE 操作を行うためには DataTable の当該行の DataRow.RowState プロパティを DataRowSate.Deleted に設定する必要があります。それを BindingSource.RemoveCurrent メソッドで行っています。

Tags: , , , ,

.NET Framework

jQuery Ajax で xml 形式のデータ受け取り

by WebSurfer 17. July 2012 21:37

jQuery Ajax で Web サービスを呼び出し、xml 形式のデータを受け取る場合の話です。

まず、Web サービスのメソッドの戻り値の型の形式として XML を指定するときは、ScriptMethodAttribute 属性 を追加し、ResponseFormat プロパティ を Xml に設定します。さらに、メソッドが XmlDocument オブジェクト を返すようにします。以下のような感じです。

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlDocument GetXmlDocument()
{
    // Xml 形式の文字列を組み立て。
    string _xmlString = CreateXmlString();

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(_xmlString);
    return xmlDoc;
}

こうしておくと、XmlDocument オブジェクトはサーバーで Xml 形式の文字列にシリアル化され、このメソッドを呼んだクライアントに返されます。また、応答ヘッダには Content-Type: text/xml が含まれるようになります。

ScriptMethod 属性の ResponseFormat プロパティを Xml に設定しておかない場合、Web サービスのメソッドが返すデータの形式は、クライアントからの要求ヘッダの Content-Type の指定によるようです。

クライアントからサーバーへデータを送信する場合、要求ヘッダの Content-Type は、application/x-www-form-urlencoded または application/json のいずれかになるはずです(データを送信しない場合、Content-Type を指定しないこともありますが)。

前者は普通に form データをサーバーに POST する時のデータ形式、後者は Ajax でのデータ交換フォーマットのデファクトスタンダード(?)である JSON 形式です。

要求ヘッダの Content-Type が application/json となっている場合、ScriptMethod 属性の ResponseFormat プロパティを Xml に設定しておかないと、戻り値が Xml 形式にならない(といって、正しい Json 形式にもならない)ので注意してください。

要求ヘッダの Content-Type を設定しない、または application/x-www-form-urlencoded とした場合は、ResponseFormat プロパティの設定に関係なく、戻り値は Xml 形式になります。(ResponseFormat プロパティを Json 設定しても無視されて、戻り値は Xml 形式になります。)

クライアントで Web サービスからのデータを受け取るのは jQuery Ajax の success ハンドラです。jQuery Ajax は、サーバーからの応答ヘッダに含まれる Contetnt-Type を見て success ハンドラに渡すデータの形式を決めます。

jQuery API の解説ページ jQuery.ajax() に次の説明があります。

"The text and xml types return the data with no processing. The data is simply passed on to the success handler, either through the responseText or responseXML property of the jqXHR object, respectively."

上のサンプルに書いたコードの場合、Web サービスからの応答ヘッダに Contente-Type: text/xml が含まれますので、success ハンドラに渡される data は jqXHR.responseXML から取得されます。

jqXHR.responseXML は何かというと、MSDN ライブラリの responseXML property に書いてあるように、XML DOM オブジェクト(ただのシリアル化された文字列ではなく)になります。

シリアル化された文字列を表示したい場合は、IE であれば xml プロパティが使えます。詳しくは、MSDN ライブラリの IXMLDOMDocument/DOMDocument Members を参照してください。

ただし、xml プロパティは IE 専用なので、Mozilla 系のブラウザの場合は以下のように XMLSerializer を使用できます。

function getXmlDocument() {
  $.post("163-ScriptMethodAttribute.asmx/GetXmlDocument",
    function (data, textStatus, jqXHR) {
      $('#output').empty();
      $('#output').text(data.xml || 
        (new XMLSerializer()).serializeToString(data));
    }
  );
}

または、jqXHR.responseText から取得することも可能です。

Tags: , ,

AJAX

XML ファイルの更新操作

by WebSurfer 27. September 2010 23:14

XML ファイルをデータソースに使った場合、表示するだけなら XmlDataSource を使えば、ほぼコーディングレスで Web アプリケーションを作成できます。ただし、XmlDataSource には更新機能がないので、必要な場合は自力でコードを書いて更新機能を実装する必要があります。

MSDN ライブラリの XmlDataSource の説明には、GetXmlDocument メソッドを使って XmlDataDocument オブジェクトを取得し、それに変更を加えてから Save するという方法が紹介されていますが、GridView や ListView 上で編集して更新するにはその方法は難しそうです。

それより、XML ファイル操作用のクラス(選択、削除、挿入、更新操作を行うメソッドを実装)を作り、そのクラスを ObjectDataSource を経由 GridView や ListView にバインドして操作するのが簡単そうです。

そのサンプルは MSDN ライブラリ の「GridView で XML ファイルをデータ ソースとして使いレコードを編集する方法」に紹介されています。そのサンプルに削除、挿入機能を加えて、さらに ID も更新できるように拡張したコードを書いておきます。なお、言語はサンプルの VB.NET を C# に変更しました。

まず、XML ファイル操作用クラス(UserInfoTable クラス)の UpdateDataSet メソッドを、ID も更新できるように変更します。具体的には、引数に original_id を追加し、original_id で DataSet の行を検索し、ヒットした行の当該項目を id に書き換えるよう修正します。次に、削除と挿入操作のためのメソッドを追加します。修正、追加後の UserInfoTable クラスは以下のようになります。

using System;
using System.Data;
using System.Web;
using System.ComponentModel;

public class XmlDataSet
{
  public class UserInfoTable : IDisposable
  {
    const string strXmlFile = "~/App_Data/UserInfo.xml";
    private DataSet myDataSet;

    public UserInfoTable()
    {
      myDataSet = new DataSet();
      myDataSet.Locale = 
        System.Globalization.CultureInfo.InvariantCulture;
      string filePath = 
        HttpContext.Current.Server.MapPath(strXmlFile);
      myDataSet.ReadXml(filePath);
    }

    public virtual void Dispose(bool disposing)
    {
      if (disposing)
      {
        myDataSet.Dispose();
      }
    }

    public void Dispose()
    {
      Dispose(true);
      System.GC.SuppressFinalize(this);
    }

    ~UserInfoTable()
    {
      Dispose(false);
    }

    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public DataSet GetDataSet()
    {
      return myDataSet;
    }

    [DataObjectMethod(DataObjectMethodType.Update, true)]
    public void UpdateDataSet(string id, string name, string original_id)
    {
      string strFillter = "ID='" + original_id + "'";
      DataRow[] rows = myDataSet.Tables[0].Select(strFillter);
      if (rows.Length > 0)
      {
        rows[0]["ID"] = id;
        rows[0]["NAME"] = name;
        Save();
      }
    }

    [DataObjectMethod(DataObjectMethodType.Delete, true)]
    public void DeleteItem(string original_id)
    {
      string strFillter = "ID='" + original_id + "'";
      DataRow[] rows = myDataSet.Tables[0].Select(strFillter);
      if (rows.Length > 0)
      {
        rows[0].Delete();
        Save();
      }
    }

    [DataObjectMethod(DataObjectMethodType.Insert, true)]
    public void InsertItem(string id, string name)
    {
      DataRow row = myDataSet.Tables[0].NewRow();
      row["ID"] = id;
      row["NAME"] = name;
      myDataSet.Tables[0].Rows.Add(row);
      Save();
    }

    private void Save()
    {
      string filePath = 
        HttpContext.Current.Server.MapPath(strXmlFile);
      myDataSet.WriteXml(filePath, XmlWriteMode.IgnoreSchema);
    }
  } 
}

新しい aspx ファイルを作成し、それに ObjectDataSource と ListView を配置します。UserInfoTable クラスをベースに、ウィザードで ObjectDataSource と ListView を設定していくと、以下のようなコードになるはずです。

<asp:ObjectDataSource ID="ObjectDataSource1" 
  runat="server" 
  DeleteMethod="DeleteItem" 
  InsertMethod="InsertItem" 
  SelectMethod="GetDataSet" 
  TypeName="XmlDataSet+UserInfoTable" 
  UpdateMethod="UpdateDataSet">
  <DeleteParameters>
    <asp:Parameter Name="original_id" Type="String" />
  </DeleteParameters>
  <InsertParameters>
    <asp:Parameter Name="id" Type="String" />
    <asp:Parameter Name="name" Type="String" />
  </InsertParameters>
  <UpdateParameters>
    <asp:Parameter Name="id" Type="String" />
    <asp:Parameter Name="name" Type="String" />
    <asp:Parameter Name="original_id" Type="String" />
  </UpdateParameters>
</asp:ObjectDataSource>
<asp:ListView ID="ListView1" 
  runat="server" 
  DataSourceID="ObjectDataSource1" 
  EnableModelValidation="True">
</asp:ListView>

しかしなから、このままではうまく動きません。問題点は以下のとおりです

  • ListView に DataKeyNames="id" の定義がないので、id の値が ObjectDataSource に渡されません。
  • ObjectDataSource に OldValuesParameterFormatString="original_{0}" の設定がないので、id の新旧の区別ができません。
  • ListView の中身(Template やその中の TextBox, Button など)は自動生成されません。自力でコードを書く必要があります。
  • ListView に挿入の行を表示するため、InsertItemPosition="LastItem" を追加します。

以上の点を修正したコードは以下のとおりです。

<asp:ObjectDataSource ID="ObjectDataSource1" 
  runat="server"
  OldValuesParameterFormatString="original_{0}"
  DeleteMethod="DeleteItem" 
  InsertMethod="InsertItem" 
  SelectMethod="GetDataSet" 
  TypeName="XmlDataSet+UserInfoTable" 
  UpdateMethod="UpdateDataSet">
  <DeleteParameters>
    <asp:Parameter Name="original_id" Type="String" />
  </DeleteParameters>
  <InsertParameters>
    <asp:Parameter Name="id" Type="String" />
    <asp:Parameter Name="name" Type="String" />
  </InsertParameters>
  <UpdateParameters>
    <asp:Parameter Name="id" Type="String" />
    <asp:Parameter Name="name" Type="String" />
    <asp:Parameter Name="original_id" Type="String" />
  </UpdateParameters>
</asp:ObjectDataSource>
<asp:ListView ID="ListView1" 
  runat="server"
  DataKeyNames="id"
  DataSourceID="ObjectDataSource1"
  InsertItemPosition="LastItem"
  EnableModelValidation="True">
  <ItemTemplate>
    <tr>
      <td>
        <asp:Button ID="DeleteButton" 
          runat="server" 
          CommandName="Delete" 
          Text="削除" />
        <asp:Button ID="EditButton" 
          runat="server" 
          CommandName="Edit" 
          Text="編集" />
      </td>
      <td>
        <asp:Label ID="idLabel" 
          runat="server" 
          Text='<%# Bind("id") %>' />
      </td>
      <td>
        <asp:Label ID="nameLabel" 
          runat="server" 
          Text='<%# Bind("name") %>' />
      </td>
    </tr>
  </ItemTemplate>
  <InsertItemTemplate>
    <tr>
      <td>
        <asp:Button ID="InsertButton" 
          runat="server" 
          CommandName="Insert" 
          Text="挿入" />
        <asp:Button ID="CancelButton" 
          runat="server" 
          CommandName="Cancel" 
          Text="クリア" />
      </td>
      <td>
        <asp:TextBox ID="idTextBox" 
          runat="server" 
          Text='<%# Bind("id") %>' />
      </td>
      <td>
        <asp:TextBox ID="nameTextBox" 
          runat="server" 
          Text='<%# Bind("name") %>' />
      </td>
    </tr>
  </InsertItemTemplate>
  <LayoutTemplate>
    <table id="Table2" runat="server">
      <tr id="Tr1" runat="server">
        <td id="Td1" runat="server">
          <table ID="itemPlaceholderContainer" 
            runat="server">
            <tr id="Tr2" runat="server">
              <th id="Th1" runat="server">
              </th>
              <th id="Th2" runat="server">
                id</th>
              <th id="Th3" runat="server">
                name</th>
            </tr>
            <tr ID="itemPlaceholder" runat="server">
            </tr>
          </table>
        </td>
      </tr>
    </table>
  </LayoutTemplate>
  <EditItemTemplate>
    <tr>
      <td>
        <asp:Button ID="UpdateButton" 
          runat="server" 
          CommandName="Update" 
          Text="更新" />
        <asp:Button ID="CancelButton" 
          runat="server" 
          CommandName="Cancel" 
          Text="キャンセル" />
      </td>
      <td>
        <asp:TextBox ID="idTextBox" 
          runat="server" 
          Text='<%# Bind("id") %>' />
      </td>
      <td>
        <asp:TextBox ID="nameTextBox" 
          runat="server" 
          Text='<%# Bind("name") %>' />
      </td>
    </tr>
  </EditItemTemplate>
</asp:ListView>

Tags: , ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  July 2019  >>
MoTuWeThFrSaSu
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar