この質問はとても単純に思えますが、答えが見つかりません。私は何かが欠けていると確信しています。
項目テンプレート内でポストバック (ボタン) を実行するコントロールと共に、データ バインドされたコントロール (ListView など) を使用したいと考えています。このアイテムのデータに対して何らかのアクションを実行するボタンが必要です。
コードは次のようになります。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebFormListCommand.aspx.cs"
Inherits="TestWebApplication.WebFormListCommand" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView ID="lvTest" runat="server" EnableViewState="false"
onitemdatabound="lvTest_ItemDataBound" onitemcommand="lvTest_ItemCommand">
<ItemTemplate>
<br />
<asp:Button ID="btnTest" runat="server" />
</ItemTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
コードビハインド:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace TestWebApplication
{
public partial class WebFormListCommand : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
lvTest.DataSource = Enumerable.Range(0, 5);
lvTest.DataBind();
}
else
{
lvTest.DataSource = Enumerable.Range(5, 5);
lvTest.DataBind();
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void lvTest_ItemDataBound(object sender, ListViewItemEventArgs e)
{
Button button = (Button)e.Item.FindControl("btnTest");
int value = (int)e.Item.DataItem;
button.CommandName = "someCommand";
button.CommandArgument = value.ToString();
button.Text = value.ToString();
}
protected void lvTest_ItemCommand(object sender, ListViewCommandEventArgs e)
{
//e.CommandArgument has the new value from the new databinding
}
}
}
問題は、ボタンが押されたときに e.CommandArgument がポストバック データバインドからの値を持っていることです。ポストバックでデータバインドを行わないと、イベントはまったく発生しません。ほとんどの場合、同じデータにデータバインドするため、これは問題になりません。ただし、1 人のユーザーがたとえばアイテム 3 を削除し、2 番目のユーザーが同時にアイテム 3 を削除することを決定した場合、2 番目のユーザーは実際には 4 番目のアイテムを削除します。これは、アイテムがポストバックで並べ替えられるためです。これは、ViewState が有効になっている場合は回避できますが、ViewState を使用せずにコマンドを実行できるはずです (ViewState を回避する必要がある場所の 1 つは、データバインドされたコントロールです)。けがに侮辱を加えるために、元の(正しい)値がサーバーに投稿されていることがはっきりとわかります。Request.Form["lvTest$ctrl2$btnTest" で取得できます
アイテム コマンドの代わりにボタン クリックを使用したり、DataKeys を使用したりするなど、正しいアイテムにコマンドを適用する多くの方法を試しましたが、データ アイテムの正しい値を取得できませんでした。データバインドされたコントロールは、実際にブラウザーによって投稿された値ではなく、常に行番号を使用してコマンド引数を取得しているようです。私が見つけた唯一の方法は、手動で Request.Form コレクションを調べることでしたが、これは正しくないようです。もちろん、JavaScript 関数と AJAX 呼び出しを接続することで問題を回避できますが、純粋な WebForms の方法でこの問題を解決する方法を知りたいです。私は何が欠けていますか?