你的第一个假设是正确的。
对于第二个问题,它取决于它是否回发和/或您是否明确约束。如果不是回发并且绑定自动发生,那么粗略地说,当DataSourceView在OnSelecting事件之前调用DataBind上的Select时,将检索ControlParameter的值。为GridView序列(和与此有关的任何给定的控制)如下:
Page.ProcessRequest
Page.PreRenderRecursiveInternal
...
GridView.EnsureChildControls
GridView.CreateChildControls
GridView.DataBind
GridView.PerformSelect
DataSourceView.Select //comes from either SQLDataSource or LinqDataSource
DataSourceView.ExecuteSelect
//for Linq:
LinqDataSourceView.GetParameterValues(WhereParameters)
//for SQL:
SqlDataSourceView.InitializeParameters(SelectParameters)
Parameters.GetValues
Parameters.UpdateValues //this is where values get retrieved using reflection
DataSourceView.OnSelecting //follows almost immediately
...get data...
DataSourceView.OnSelected
所以,对于在控制层次中的每个控制,该框架递归调用的DataBind,这随后触发的参数,OnSelecting检索,数据检索和OnSelected。
但是,如果它是回发,那么这些参数将从页面的OnLoadComplete上的视图状态再次按它们声明的顺序加载。
这是你在找什么?
编辑
Q1 - 假设ControlParameter绑定到控制C.我会想象在回传的财产C1 ControlProperty总是能够得到的ViewState C.C1的价值,无论是C是什么类型,即使C ViewState被禁用?!
这不完全是如何碰巧......在回传(以及与此有关的初始请求),ControlParemeter的视图状态时,才会评估,看它是否改变,从而OnParameterChanged事件可能会被解雇。 ControlParameter的实际值是根据它指向的控件进行评估的(通过反射)。在你的情况下,它会是“C.C1”。现在,当它读取C.C1时,它的值很可能是从视图状态读取的。但是,ControlParameter不会直接读取C的视图状态。
Q2 - 但我可以问,为什么,如果第一次创建页面,ControlParameter的值也不能从viewstate中获取?最后,当lstCities从数据源检索数据时,lstCities.SelectedValue是否设置了它的值?
就是这样,在这个时候(第一次页面加载时)lstCities没有检索到任何数据。属性评估第一次发生在Page.OnLoadComplete上,但在任何DataBind之前(发生Page.PreRenderRecursiveInternal后不久)。
在原油的形式,试图将其放置在页面的生命周期:
...request...
PerformPreInit
InitRecursive //SqlDataSource subscribes to Page.LoadComplete
OnInitComplete
if PostBack
LoadAllState //the view state gets loaded
ProcessPostData
OnPreLoad
LoadRecursive
if PostBack
ProcessPostData
RaiseChangedEvents
RaisePostBackEvents //you handle your events
//notice that following sections assume that you did not do any data
//binding inside your events
OnLoadComplete //This is where parameters (SelectParemeters/WhereParemeters)
//get updated. At this point none of them are data bound yet.
//And if it the first time, there are no values
//as the ViewState is empty for them.
PreRenderRecursiveInternal //calls the DataBind (if you haven't already),
//then DataSourceView.Select; parameters evaluate their controls.
//The control C would be bound at this point.
PerformPreRenderComplete
SaveAllState
OnSaveStateComplete
RenderControl
第二个编辑
所以ControlParameter评估C.C1,从而获取C.C1的C被绑定后的值?!的onLoadComplete和的DataBind(由PreRenderRecursiveInternal触发):每当有人问,在这种情况下在两个地方发生的(间接)
的ControlParameter检索值。在OnLoadComplete上,C没有绑定。在PreRenderRecursiveInternal上,在DataBind之后,C被绑定。这两次ControlParameter被要求阅读C.C1。也许以下会帮助...
下面是感兴趣的类和方法。将它们放在页面周期的角度,希望它会很清楚。
public class ControlParameter : Parameter
{
public string ControlID { get; set; } //stored in ViewState
public string PropertyName { get; set; } //stored in ViewState
protected override object Evaluate(HttpContext context, Control owner)
{
Control sourceControl = DataBoundControlHelper.FindControl(owner, this.ControlID);
//evaluate C.C1 using reflection
return DataBinder.Eval(sourceControl, this.PropertyName);
}
internal void UpdateValue(HttpContext context, Control owner)
{
//PostBack or not, read stored value (on initial load it is empty)
object storedValue = this.ViewState["ParameterValue"];
//Get the actual value for this parameter from C.C1
object actualValue = this.Evaluate(context, owner);
//Store received value
this.ViewState["ParameterValue"] = actualValue;
//Fire a change event if necessary
if ((actualValue == null && storedValue != null)
|| (actualValue != null && actualValue != storedValue))
this.OnParameterChanged();
}
}
public class SqlDataSource : DataSourceControl
{
//fired by OnLoadComplete
private void LoadCompleteEventHandler(object sender, EventArgs e)
{
//UpdateValues simply calls the UpdateValue for each parameter
this.SelectParameters.UpdateValues(this.Context, this);
this.FilterParameters.UpdateValues(this.Context, this);
}
}
public class SqlDataSourceView : DataSourceView, IStateManager
{
private SqlDataSource _owner;
//this method gets called by DataBind (including on PreRenderRecursiveInternal)
protected internal override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
{
DbConnection connection = this._owner.CreateConnection(this._owner.ConnectionString);
DbCommand command = this._owner.CreateCommand(this.SelectCommand, connection);
//This is where ControlParameter will read C.C1 values again.
//Except this time, C.C1 will be already populated by its own DataBind
this.InitializeParameters(command, this.SelectParameters, null);
command.CommandType = GetCommandType(this.SelectCommandType);
SqlDataSourceSelectingEventArgs e = new SqlDataSourceSelectingEventArgs(command, arguments);
this.OnSelecting(e);
if (e.Cancel)
return null;
//...get data from DB
this.OnSelected(new SqlDataSourceStatusEventArgs(command, affectedRows, null));
//return data (IEnumerable or DataView)
}
private void InitializeParameters(DbCommand command, ParameterCollection parameters, IDictionary exclusionList)
{
//build exlusions list
//...
//Retrieve parameter values (i.e. from C.C1 for the ControlParameter)
IOrderedDictionary values = parameters.GetValues(this._context, this._owner);
//build command's Parameters collection using commandParameters and retrieved values
//...
}
}
A)所以ControlParameter检查其是否ViewState的变化......
参考UpdateValue方法上面看到它如何使用ViewState中。
B)我认为ControlParameter检查其是否视图状态只更改,以便它可以触发事件OnParameterChanged。但为什么处理这个事件如此重要?
我不知道这很重要。我想,就像任何其他事件一样,它允许您跟踪参数属性的更改并根据您的需要采取相应行动。它在许多地方被炒鱿鱼,但我没有看到任何人订阅它。所以...
通过属性评估你的意思是ControlParameter检查自己的ViewState?因此,你不是说ControlParameter评估C.C1(我假设C已被绑定后发生)
这意味着ControlParameter.UpdateValue被调用,这对于陈述的理由检查ViewState中,然后调用ControlParameter.Evalue ,然后找到一个控件并使用反射(Eval)检索数据。往上看。
第三编辑
我相信,通过更新你的意思是UpdateValue。
因此,如果更新()被调用时,数据绑定发生,那么这是什么意思是,当在下次回发更新()被调用的onLoadComplete,C.C1和ControlParameter已经将有相同的价值观...
没有必要。您忘记了视图状态在LoadAllState上加载,并且在它和OnLoadComplete之间还有六个步骤(请参阅上面的页面生命周期)。其中每个可能会修改源代码管理的(C.C1)值。
假设你有C.C1 =“x”并做了回帖。现在,所有控件的视图状态都被加载(LoadAllState)。如果C.C1将它的值存储在视图状态中,它将加载“x”。在Page_Load(LoadRecursive)上,您决定设置C.C1 =“y”。这里C.C1可能决定将“y”存储在它的视图状态或不存在 - 这是无关紧要的。接下来的其他事件。接下来是OnLoadComplete。由于SqlDataSource的赞同这种情况下,它会评估所有相关的参数(LoadCompleteEventHandler),而且由于你没有改变C.C1但ControlParameter的视图状态没了,
if ((actualValue == null && storedValue != null)
|| (actualValue != null && actualValue != storedValue))
this.OnParameterChanged();
将返回true和OnParameterChanged将被解雇。顺便说一下,这个活动至少有十个地方被触发。它在数据绑定和属性检索过程中不起重要作用(如果有的话)。
我已经更新了我的答案。简而言之,Q1 - ControlParameter只读取自己的状态,并且只确定它是否改变; Q2 - ControlParameter总是评估C.C1,而不是视图状态,此时C.C1为空(或默认),因为在视图状态中没有任何内容,并且没有DataBind。 – Ruslan 2009-04-08 21:36:26
提供更多信息,附带一些代码。 – Ruslan 2009-04-09 15:32:09