6

我最初需要基于相当多的处理器和磁盘密集型搜索来生成按钮。每个按钮将代表一个选择并触发回发。我的问题是回发不会触发命令 b_Command。我猜是因为原始按钮尚未重新创建。我无法在回发中执行原始搜索以重新创建按钮,因此我想从回发信息中生成所需的按钮。

我应该如何以及在哪里做这件事?例如,我应该在 Page_Load 之前这样做吗?我怎样才能从回发中重建 CommandEventHandler - 如果有的话?

   namespace CloudNavigation
{
    public partial class Test : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack)
            {
                // how can I re-generate the button and hook up the event here
                // without executing heavy search 1
            }
            else
            {
                // Execute heavy search 1 to generate buttons
                Button b = new Button();
                b.Text = "Selection 1";
                b.Command += new CommandEventHandler(b_Command);
                Panel1.Controls.Add(b);
            }
        }

        void b_Command(object sender, CommandEventArgs e)
        {
            // Execute heavy search 2 to generate new buttons
            Button b2 = new Button();
            b2.Text = "Selection 2";
            b2.Command += new CommandEventHandler(b_Command);
            Panel1.Controls.Add(b2);
        }
    }
}
4

6 回答 6

5

b_Command 事件处理程序方法没有被执行,因为回发按钮没有被重新创建(因为它们是动态生成的)。每次重新创建页面时,您都需要重新创建它们,但为了做到这一点,您需要在状态的某处显式缓存信息。

如果这是一个页面范围的操作,最简单的方法是将其存储在 ViewState 中(作为字符串 - 如果您开始使用对象加载 ViewState,您将看到性能下降),以便您可以在下次加载时检查它(或任何其他先前的事件)并在重新加载页面时重新创建按钮。如果操作是会话范围的,您可以轻松地将对象(数组或其他)存储在会话中,并在下一次加载(或初始化)时检索它以重新创建控件。

这种情况意味着您只需要在 b_Command EventHandler 中存储有关按钮的一些信息,而不是创建和添加按钮,因为如果这样做,您将在下一次回发中丢失相关信息(就像现在发生的那样)。

所以你的代码会变成这样:

namespace CloudNavigation
{
    public partial class Test : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack)
            {
                this.recreateButtons();
            }
            else
            {
                // Execute heavy search 1 to generate buttons
                Button b = new Button();
                b.Text = "Selection 1";
                b.Command += new CommandEventHandler(b_Command);
                Panel1.Controls.Add(b);
                //store this stuff in ViewState for the very first time
            }
        }

        void b_Command(object sender, CommandEventArgs e)
        {
            //Execute heavy search 2 to generate new buttons
            //TODO: store data into ViewState or Session
            //and maybe create some new buttons
        }

        void recreateButtons()
        {
            //retrieve data from ViewState or Session and create all the buttons
            //wiring them up to eventHandler
        }
    }
}

如果您不想在页面加载时调用 recreateButtons,您可以在 PreLoad 或 Init 事件上执行此操作,我看不出有什么不同,因为您可以在任何地方访问 ViewState/Session 变量(在 Init viewstate 上未应用但您可以访问它来重新创建您的动态按钮)。

有人会讨厌这种解决方案,但据我所知,在服务器端保留状态数据的唯一方法是ViewState - Session - Page.Transfer 或客户端 cookie。

于 2008-11-09T18:09:20.430 回答
1

需要在加载事件之前创建按钮,否则状态将无法正确连接。而是在 Init() 中重新创建按钮。

至于如何在不重新运行搜索的情况下执行此操作,我建议您将结果缓存在某处。缓存中结果集的存在是您在 Init() 事件中的按钮代码如何知道它需要运行的方式。

或者,您可以将按钮静态放置在页面上。只要放足够的东西来处理搜索返回的任何内容。如果你认为这可能是太多的项目,那么问问你自己:你的用户真的想要对这么多项目进行排序吗也许您应该考虑对这些数据进行分页,在这种情况下,静态按钮不再那么重要了。

于 2008-11-07T18:07:23.243 回答
1

当回发事件处理试图找到它在集合中不存在的控件时会发生什么。结帐丹尼斯 DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx

希望它可以帮助布鲁诺·菲格雷多 http://www.brunofigueiredo.com

于 2008-11-07T18:22:10.577 回答
0

您的 ASPX 是否连接了事件处理程序?

<asp:Button id="btnCommand" runat="server" onClick="b_Command" text="Submit" />
于 2008-11-07T18:03:02.877 回答
0

我同意 Joel 关于缓存搜索结果的观点。至于按钮,您可以在页面生命周期的初始化或加载阶段动态创建它们,但请注意,如果您删除一个按钮,然后以编程方式将其添加回来,您将弄乱您的状态。

在我的一个项目中,我们有一个动态表单,可以动态生成字段,我们使其工作的方式是通过存储在缓存中或页面视图状态中的数组。该数组包含要显示的按钮,并在每个页面加载时重新创建按钮,以便可以将状态正确加载到其中。然后,如果我需要更多按钮或一组全新的按钮,我会在数组中标记隐藏值,并在数组中为新的一组相应按钮添加一组新值。这样状态不会丢失,按钮继续工作。

如果您以编程方式创建按钮,您还需要确保为按钮的 on_click 事件添加处理程序,我认为我在顶部的代码中看到了这些处理程序。

于 2008-11-07T18:16:04.833 回答
0

这是一个带有自定义视图状态处理的示例(请注意,按钮具有EnableViewState = false):

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Execute heavy search 1 to generate buttons
            ButtonTexts = new ButtonState[] { 
                new ButtonState() { ID = "Btn1", Text = "Selection 1" } 
            };
        }
        AddButtons();
    }

    void b_Command(object sender, CommandEventArgs e)
    {
        TextBox1.Text = ((Button)sender).Text;

        // Execute heavy search 2 to generate new buttons
        ButtonTexts = new ButtonState[] { 
            new ButtonState() { ID = "Btn1", Text = "Selection 1" }, 
            new ButtonState() { ID = "Btn2", Text = "Selection 2" } 
        };
        AddButtons();
    }

    private void AddButtons()
    {
        Panel1.Controls.Clear();
        foreach (ButtonState buttonState in this.ButtonTexts)
        {
            Button b = new Button();
            b.EnableViewState = false;
            b.ID = buttonState.ID;
            b.Text = buttonState.Text;
            b.Command += new CommandEventHandler(b_Command);
            Panel1.Controls.Add(b);
        }
    }

    private ButtonState[] ButtonTexts
    {
        get
        {
            ButtonState[] list = ViewState["ButtonTexts"] as ButtonState[];
            if (list == null)
                ButtonTexts = new ButtonState[0];
            return list;
        }
        set { ViewState["ButtonTexts"] = value; }
    }

    [Serializable]
    class ButtonState
    {
        public string ID { get; set; }
        public string Text { get; set; }
    }
于 2008-11-07T18:28:36.490 回答