我有一个相当复杂的页面,可以在转发器内动态构建用户控件。在初始化ViewState
之前,必须在初始化页面事件期间绑定此转发器,否则动态创建的用户控件将不会保留其状态。
这会创建一个有趣的Catch-22,因为我需要在初始页面加载时创建绑定转发器的对象,然后将其保留在内存中,直到用户选择离开或保存为止。
因为我不能使用ViewState
来存储这个对象,但是在Init期间可以使用它,我被迫将它存储在Session中。
这也有问题,因为我必须在非回发期间显式地使会话值为空,以便模拟ViewState
的工作方式。
在这种情况下,必须有一种更好的状态管理方法。有什么想法吗?
编辑:关于使用LoadViewState
的一些好建议,但是当我这样做时,我仍然遇到状态未恢复的问题。
如果页面结构
,则有所不同页面 - > UserControl - >中继器 - > N量的UserControls动态创建。
我将重写的LoadViewState
放在父UserControl
中,因为它被设计为完全封装并独立于它所在的页面。我想知道问题出在哪里。
答案 0 :(得分:4)
页面上的LoadViewState方法绝对是答案。这是一般的想法:
protected override void LoadViewState( object savedState ) {
var savedStateArray = (object[])savedState;
// Get repeaterData from view state before the normal view state restoration occurs.
repeaterData = savedStateArray[ 0 ];
// Bind your repeater control to repeaterData here.
// Instruct ASP.NET to perform the normal restoration of view state.
// This will restore state to your dynamically created controls.
base.LoadViewState( savedStateArray[ 1 ] );
}
SaveViewState需要创建我们上面使用的savedState数组:
protected override object SaveViewState() {
var stateToSave = new List<object> { repeaterData, base.SaveViewState() };
return stateToSave.ToArray();
}
不要忘记使用以下代码绑定Init或Load中的转发器:
if( !IsPostBack ) {
// Bind your repeater here.
}
答案 1 :(得分:1)
这也有问题,因为我必须在非回发期间显式地使会话值为空,以便模拟ViewState的工作方式。
为什么 明确地将值清空(除了内存管理等)?它不是检查Page.IsPostback的选项,是否可以使用Session变量执行某些操作?
答案 2 :(得分:1)
我总是在LoadViewState事件中重新创建动态控件。您可以在viewstate中存储需要创建的控件数,然后使用LoadViewState事件中的LoadControl方法动态创建其中的许多控件。在这种情况下,您可以访问ViewState,但尚未恢复到页面上的控件。
答案 3 :(得分:0)
@DancesWithBamboo:
如果我动态绑定那里的控件,ASP.NET会自动处理它们的状态吗?在Page_Load中执行此操作的问题是viewstate已经加载,并且它不会在转发器中添加动态控件。我认为它会在LoadViewState中做同样的事情吗?
答案 4 :(得分:0)
1)可能有办法让它工作......你只需要确保在适当的时候将控件添加到树中。太快了,你没有得到ViewState。太晚了,你没有得到ViewState。
2)如果你无法弄清楚,也许你可以关闭井页的viewstate,然后只依赖查询字符串进行状态更改?之前回发的任何链接都是指向另一个URL(或回发重定向)的链接。
这确实可以减轻页面的重量,并且更容易避免ViewState出现问题。
答案 5 :(得分:0)
@Jonathan:
是的,只要您创建正确数量的控件,运行时就会填充控件的视图状态。控件的viewstate将在此事件之后填充。
答案 6 :(得分:0)
是的,只要您创建正确数量的控件,运行时就会填充控件的视图状态。控件的viewstate将在此事件之后填充。
LoadViewState调用的顺序是什么?我添加了一个重写的方法签名,它似乎没有踩到它。
答案 7 :(得分:0)
protected override void LoadViewState(object savedState)
{
// Put your code here before base is called
base.LoadViewState(savedState);
}
这是你的意思吗?或者您的意思是控件处理的顺序是什么?我认为答案就是准随机。
另外,为什么不能在Page_Load之前加载绑定的对象?如果必须,可以在页面生命周期的任何时间调用业务层,除了预渲染和之后的任何内容。
答案 8 :(得分:0)
我必须显式地使会话无效 非回发期间的价值 模拟ViewState的工作方式。
为什么你不能存储你在会话中绑定的任何对象,我仍然模糊不清。如果您可以将该对象存储在会话中,则以下内容应该有效:
这应该有效。但是,如果由于某种原因无法使用会话,则必须采取稍微不同的方法,例如在绑定控件后将数据库中存储的任何内容存储在数据库中,然后将其从数据库中拉出并重新绑定每次回发都会再次出现。
我错过了一些关于你情况的明显细节吗?我知道在不发布代码的情况下解释情况的微妙之处可能非常棘手。
编辑:我在此解决方案中将对OnInit的所有引用更改为OnPreInit。我忘了MS在ASP.NET 2.0中引入了这个新事件。根据他们的page lifecycle documentation,OnPreInit是应该创建/重新创建动态控件的地方。
答案 9 :(得分:0)
创建动态控件时...我只在初始加载时填充它们。后来我在页面加载事件中重新创建了回发控件,并且视图状态似乎处理了值的重新填充而没有任何问题。