2

この質問はとても単純に思えますが、答えが見つかりません。私は何かが欠けていると確信しています。

項目テンプレート内でポストバック (ボタン) を実行するコントロールと共に、データ バインドされたコントロール (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 の方法でこの問題を解決する方法を知りたいです。私は何が欠けていますか?

4

1 に答える 1