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>