I need to generate buttons initially based on quite a processor and disk intensive search. Each button will represent a selection and trigger a postback. My issue is that the postback does not trigger the command b_Command. I guess because the original buttons have not been re-created. I cannot affort to execute the original search in the postback to re-create the buttons so I would like to generate the required button from the postback info.
我需要最初基于相当多的处理器和磁盘密集型搜索来生成按钮。每个按钮代表一个选择并触发回发。我的问题是回发不会触发命令b_Command。我猜是因为没有重新创建原始按钮。我无法在回发中执行原始搜索以重新创建按钮,因此我想从回发信息生成所需的按钮。
How and where shoud I be doing this? Should I be doing it before Page_Load for example? How can I re-construct the CommandEventHandler from the postback - if at all?
我该怎么做以及在哪里做这件事?我应该在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);
}
}
}
6 个解决方案
#1
5
The b_Command Event Handler method is not being executed because on post back buttons are not being recreated (since they are dynamically generated). You need to re-create them every time your page gets recreated but in order to do this you need to explicitly cache information somewhere in state.
没有执行b_Command事件处理程序方法,因为没有重新创建回发按钮(因为它们是动态生成的)。每次重新创建页面时都需要重新创建它们,但为了做到这一点,您需要在状态中的某处显式地缓存信息。
If this a page-scoped operation easiest way is to store it in the ViewState (as strings - if you start loading the ViewState with objects you'll see performance go down) so that you can check it on next load (or any other previous event) and re-create buttons when reloading the page. If the operation is session-scoped, you can easily store an object (array or whatever) in session and retrieve it on next Load (or Init) to re-create your controls.
如果这是一个页面范围操作最简单的方法是将它存储在ViewState中(作为字符串 - 如果你开始用对象加载ViewState,你会看到性能下降),这样你就可以在下次加载时检查它(或任何其他的事件)并在重新加载页面时重新创建按钮。如果操作是会话范围的,您可以轻松地在会话中存储对象(数组或其他),并在下一个Load(或Init)上检索它以重新创建控件。
This scenario means that you need just to store some info about your button in your b_Command EventHandler instead of creating and adding buttons since if you do so you'll lose relative information in the next postback (as it is happening now).
这种情况意味着您只需要在b_Command EventHandler中存储有关按钮的一些信息,而不是创建和添加按钮,因为如果这样做,您将在下一次回发中丢失相关信息(现在正在发生)。
so your code would become something like:
所以你的代码会变成这样的:
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
}
}
}
If you don't want to call recreateButtons on page load you can do it on PreLoad or on Init events, I don't see a difference since you'll be able to access ViewState/Session variables everywhere (on Init viewstate is not applied but you can access it to re-create your dynamic buttons).
如果您不想在页面加载时调用recreateButtons,您可以在PreLoad或Init事件上执行它,我没有看到区别,因为您将能够到处访问ViewState / Session变量(在Init viewstate上未应用)但你可以访问它来重新创建你的动态按钮)。
Someone will hate this solution but as far as I know the only way to retain state data server-side is ViewState - Session - Page.Transfer or client-side cookies.
有人会讨厌这个解决方案,但据我所知,保留状态数据服务器端的唯一方法是ViewState - Session - Page.Transfer或客户端cookie。
#2
1
The buttons need to be created before the load event, or state won't be wired up correctly. Re-create your buttons in Init() instead.
需要在加载事件之前创建按钮,否则状态将无法正确连接。改为在Init()中重新创建按钮。
As for how to do this without re-running the search, I suggest you cache the results somewhere. The existence of a result set in the cache is how your button code in the Init() event will know it needs to run.
至于如何在不重新运行搜索的情况下执行此操作,我建议您将结果缓存到某处。缓存中存在的结果集是Init()事件中的按钮代码如何知道它需要运行。
Alternatively, you could place the buttons on the page statically. Just put enough there to handle whatever the search returns. If you're thinking that maybe that would be way too many items, then ask your self this: will your users really want to sort through that many items? Maybe you should consider paging this data, in which case static buttons aren't as big a deal any more.
或者,您可以静态地将按钮放在页面上。只要放足够处理搜索返回的内容。如果你认为这可能是太多的项目,那么问问你自己:你的用户真的想要对这么多项进行排序吗?也许您应该考虑分页这些数据,在这种情况下,静态按钮不再是一个大问题。
#3
1
What happens when the postback event handling tries to find the control it dosen't exists on the collection. Checkout Denis DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
当回发事件处理试图找到它在集合上不存在的控件时会发生什么。 Checkout Denis DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
Hope it helps Bruno Figueiredo http://www.brunofigueiredo.com
希望它有助于Bruno Figueiredo http://www.brunofigueiredo.com
#4
0
Does your ASPX have the event handler wired up?
你的ASPX是否连接了事件处理程序?
<asp:Button id="btnCommand" runat="server" onClick="b_Command" text="Submit" />
#5
0
I agree with Joel about caching the search results. As for the buttons you can create them dynamically at the init or load phases of the page lifecycle but be aware that if you remove a button and then add it back programmatically you will mess up your state.
我同意Joel关于缓存搜索结果的看法。至于按钮,您可以在页面生命周期的初始化或加载阶段动态创建它们,但请注意,如果删除按钮然后以编程方式将其添加回来,则会破坏您的状态。
In one of my projects we have a dynamic form that generates field son the fly and the way we make it work is through an array that is stored in the cache or in the viewstate for the page. The array contains the buttons to display and on each page load it re-creates the buttons so that state can be loaded properly into them. Then if I need more buttons or a whole new set I flag the hide value in the array and add a new set of values in the array for the new set of corresponding buttons. This way state is not lost and the buttons continue to work.
在我的一个项目中,我们有一个动态表单,它可以生成字段,我们使它工作的方式是通过存储在缓存中或页面的视图状态中的数组。该数组包含要显示的按钮,并在每个页面加载时重新创建按钮,以便可以将状态正确加载到它们中。然后,如果我需要更多按钮或整个新集合,我会在数组中标记隐藏值,并在数组中为新的相应按钮集添加一组新值。这样状态不会丢失,按钮继续工作。
You also need to ensure that you add a handler for the on_click event for your buttons if you create them programmatically which I think I see in your code up at the top.
如果以编程方式创建按钮,还需要确保为按钮的on_click事件添加处理程序,我认为我在顶部的代码中看到了这个处理程序。
#6
0
Here is a sample with custom viewstate handling (note that buttons have EnableViewState = false
):
以下是自定义视图状态处理的示例(请注意,按钮具有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; }
}
#1
5
The b_Command Event Handler method is not being executed because on post back buttons are not being recreated (since they are dynamically generated). You need to re-create them every time your page gets recreated but in order to do this you need to explicitly cache information somewhere in state.
没有执行b_Command事件处理程序方法,因为没有重新创建回发按钮(因为它们是动态生成的)。每次重新创建页面时都需要重新创建它们,但为了做到这一点,您需要在状态中的某处显式地缓存信息。
If this a page-scoped operation easiest way is to store it in the ViewState (as strings - if you start loading the ViewState with objects you'll see performance go down) so that you can check it on next load (or any other previous event) and re-create buttons when reloading the page. If the operation is session-scoped, you can easily store an object (array or whatever) in session and retrieve it on next Load (or Init) to re-create your controls.
如果这是一个页面范围操作最简单的方法是将它存储在ViewState中(作为字符串 - 如果你开始用对象加载ViewState,你会看到性能下降),这样你就可以在下次加载时检查它(或任何其他的事件)并在重新加载页面时重新创建按钮。如果操作是会话范围的,您可以轻松地在会话中存储对象(数组或其他),并在下一个Load(或Init)上检索它以重新创建控件。
This scenario means that you need just to store some info about your button in your b_Command EventHandler instead of creating and adding buttons since if you do so you'll lose relative information in the next postback (as it is happening now).
这种情况意味着您只需要在b_Command EventHandler中存储有关按钮的一些信息,而不是创建和添加按钮,因为如果这样做,您将在下一次回发中丢失相关信息(现在正在发生)。
so your code would become something like:
所以你的代码会变成这样的:
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
}
}
}
If you don't want to call recreateButtons on page load you can do it on PreLoad or on Init events, I don't see a difference since you'll be able to access ViewState/Session variables everywhere (on Init viewstate is not applied but you can access it to re-create your dynamic buttons).
如果您不想在页面加载时调用recreateButtons,您可以在PreLoad或Init事件上执行它,我没有看到区别,因为您将能够到处访问ViewState / Session变量(在Init viewstate上未应用)但你可以访问它来重新创建你的动态按钮)。
Someone will hate this solution but as far as I know the only way to retain state data server-side is ViewState - Session - Page.Transfer or client-side cookies.
有人会讨厌这个解决方案,但据我所知,保留状态数据服务器端的唯一方法是ViewState - Session - Page.Transfer或客户端cookie。
#2
1
The buttons need to be created before the load event, or state won't be wired up correctly. Re-create your buttons in Init() instead.
需要在加载事件之前创建按钮,否则状态将无法正确连接。改为在Init()中重新创建按钮。
As for how to do this without re-running the search, I suggest you cache the results somewhere. The existence of a result set in the cache is how your button code in the Init() event will know it needs to run.
至于如何在不重新运行搜索的情况下执行此操作,我建议您将结果缓存到某处。缓存中存在的结果集是Init()事件中的按钮代码如何知道它需要运行。
Alternatively, you could place the buttons on the page statically. Just put enough there to handle whatever the search returns. If you're thinking that maybe that would be way too many items, then ask your self this: will your users really want to sort through that many items? Maybe you should consider paging this data, in which case static buttons aren't as big a deal any more.
或者,您可以静态地将按钮放在页面上。只要放足够处理搜索返回的内容。如果你认为这可能是太多的项目,那么问问你自己:你的用户真的想要对这么多项进行排序吗?也许您应该考虑分页这些数据,在这种情况下,静态按钮不再是一个大问题。
#3
1
What happens when the postback event handling tries to find the control it dosen't exists on the collection. Checkout Denis DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
当回发事件处理试图找到它在集合上不存在的控件时会发生什么。 Checkout Denis DynamicControlsPlaceholder @ http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
Hope it helps Bruno Figueiredo http://www.brunofigueiredo.com
希望它有助于Bruno Figueiredo http://www.brunofigueiredo.com
#4
0
Does your ASPX have the event handler wired up?
你的ASPX是否连接了事件处理程序?
<asp:Button id="btnCommand" runat="server" onClick="b_Command" text="Submit" />
#5
0
I agree with Joel about caching the search results. As for the buttons you can create them dynamically at the init or load phases of the page lifecycle but be aware that if you remove a button and then add it back programmatically you will mess up your state.
我同意Joel关于缓存搜索结果的看法。至于按钮,您可以在页面生命周期的初始化或加载阶段动态创建它们,但请注意,如果删除按钮然后以编程方式将其添加回来,则会破坏您的状态。
In one of my projects we have a dynamic form that generates field son the fly and the way we make it work is through an array that is stored in the cache or in the viewstate for the page. The array contains the buttons to display and on each page load it re-creates the buttons so that state can be loaded properly into them. Then if I need more buttons or a whole new set I flag the hide value in the array and add a new set of values in the array for the new set of corresponding buttons. This way state is not lost and the buttons continue to work.
在我的一个项目中,我们有一个动态表单,它可以生成字段,我们使它工作的方式是通过存储在缓存中或页面的视图状态中的数组。该数组包含要显示的按钮,并在每个页面加载时重新创建按钮,以便可以将状态正确加载到它们中。然后,如果我需要更多按钮或整个新集合,我会在数组中标记隐藏值,并在数组中为新的相应按钮集添加一组新值。这样状态不会丢失,按钮继续工作。
You also need to ensure that you add a handler for the on_click event for your buttons if you create them programmatically which I think I see in your code up at the top.
如果以编程方式创建按钮,还需要确保为按钮的on_click事件添加处理程序,我认为我在顶部的代码中看到了这个处理程序。
#6
0
Here is a sample with custom viewstate handling (note that buttons have EnableViewState = false
):
以下是自定义视图状态处理的示例(请注意,按钮具有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; }
}