我需要最初基于相当多的处理器和磁盘密集型搜索来生成按钮。每个按钮代表一个选择并触发回发。我的问题是回发不会触发命令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);
}
}
}
答案 0 :(得分:5)
没有执行b_Command事件处理程序方法,因为没有重新创建回发按钮(因为它们是动态生成的)。每次重新创建页面时都需要重新创建它们,但为了做到这一点,您需要在状态中的某处显式地缓存信息。
如果这是一个页面范围操作最简单的方法是将它存储在ViewState中(作为字符串 - 如果你开始用对象加载ViewState,你会看到性能下降),这样你就可以在下次加载时检查它(或者任何其他以前的事件)并在重新加载页面时重新创建按钮。 如果操作是会话范围的,您可以轻松地在会话中存储对象(数组或其他)并在下一个Load(或Init)上检索它以重新创建控件。
这种情况意味着您只需要在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 - 会话 - Page.Transfer或客户端饼干。
答案 1 :(得分:1)
需要在加载事件之前创建按钮,否则状态将无法正确连接。改为在Init()中重新创建按钮。
至于如何在不重新运行搜索的情况下执行此操作,我建议您将结果缓存到某处。缓存中存在的结果集是Init()事件中的按钮代码如何知道它需要运行。
或者,您可以静态地将按钮放在页面上。只要放足够处理搜索返回的内容。如果您认为这可能是方式太多项目,那么请问您自己:您的用户是否真的想要对这么多项目进行排序?也许您应该考虑分页这些数据,在这种情况下,静态按钮不再是一个大问题。
答案 2 :(得分:1)
当回发事件处理试图找到它在集合上不存在的控件时会发生什么。 Checkout Denis DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
希望它有所帮助 布鲁诺菲格雷多 http://www.brunofigueiredo.com
答案 3 :(得分:0)
您的ASPX是否已将事件处理程序连接起来?
<asp:Button id="btnCommand" runat="server" onClick="b_Command" text="Submit" />
答案 4 :(得分:0)
我同意Joel关于缓存搜索结果的看法。至于按钮,您可以在页面生命周期的初始化或加载阶段动态创建它们,但要注意,如果删除按钮然后以编程方式将其添加回来,则会破坏您的状态。
在我的一个项目中,我们有一个动态表单,它可以生成字段,并且我们使其工作的方式是通过存储在缓存中或页面的视图状态中的数组。该数组包含要显示的按钮,并在每个页面加载时重新创建按钮,以便可以将状态正确加载到它们中。然后,如果我需要更多按钮或整个新集合,我会在数组中标记隐藏值,并在数组中为新的相应按钮集添加一组新值。这样状态不会丢失,按钮继续工作。
如果您以编程方式创建按钮,则还需要确保为按钮的on_click事件添加处理程序,我认为我会在您的代码中看到它们。
答案 5 :(得分: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; }
}