C#动态创建的LinkButton命令事件处理程序
所以我这里有一个奇怪的情况……我有一个System.Web.UI.WebControls.WebParts.EditorPart类。它呈现一个"搜索"按钮,当我们单击该按钮时,它的clickHandler方法将进行数据库搜索,并为其返回的每一行动态创建一个LinkButton,设置CommandName和CommandArgument属性并添加CommandEventHandler方法,然后添加LinkButton控件到页面。
问题是,当我们单击LinkButton时,它的CommandEventHandler方法将永远不会被调用,它看起来就像页面只是回贴到按下原始"搜索"按钮之前的位置一样。
我看到有帖子说我们需要在OnLoad()或者其他早期方法中添加事件处理程序,但是直到用户告诉我们要搜索的内容并单击"搜索"按钮后,我的LinkButton才创建。关于如何处理这个问题有什么想法吗?
谢谢!
解决方案
我们需要在onload中重新添加动态创建的控件,以便它们可以在页面层次结构中并触发其事件。
这是我最喜欢的把戏:)
我们的方案是首先呈现一个控件。然后,使用来自用户的一些输入,渲染进一步的控件,并使它们响应事件。
这里的关键是状态,我们需要在控件到达PostBack时知道其状态,因此我们使用ViewState。这个问题就变成了鸡与蛋的问题。在调用LoadViewState()之后,ViewState才可用,但是必须在调用之前创建控件,以正确触发事件。
诀窍是重写" LoadViewState()"和" SaveViewState()",以便我们可以控制事物。
(请注意,下面的代码是粗糙的,来自内存,可能有问题)
private string searchQuery = null; private void SearchButton(object sender, EventArgs e) { searchQuery = searchBox.Text; var results = DataLayer.PerformSearch(searchQuery); CreateLinkButtonControls(results); } // We save both the base state object, plus our query string. Everything here must be serializable. protected override object SaveViewState() { object baseState = base.SaveViewState(); return new object[] { baseState, searchQuery }; } // The parameter to this method is the exact object we returned from SaveViewState(). protected override void LoadViewState(object savedState) { object[] stateArray = (object[])savedState; searchQuery = stateArray[1] as string; // Re-run the query var results = DataLayer.PerformSearch(searchQuery); // Re-create the exact same control tree as at the point of SaveViewState above. It must be the same otherwise things will break. CreateLinkButtonControls(results); // Very important - load the rest of the ViewState, including our controls above. base.LoadViewState(stateArray[0]); }
我刚想到的一个肮脏的技巧是创建具有与真实按钮相同的ID的虚拟LinkButton。
因此,假设我们要在Pre_Render上创建一个LinkButton" foo"(为时已晚),然后在Page_Load上创建一个虚拟foo:
var link = new LinkButton(); link.ID = "foo"; link.Click += fooEventHandler; dummyButtons.Controls.Add(link);
(其中" dummyButtons"只是页面上的PlaceHolder,而Visibility设置为false。)
很难看,但是可以用。