2009-04-07 28 views
2


如果控件始终是绑定到数据源控件的声明顺序排列,然后

A)以下问题是基于这样的假设控件始终是绑定在预定数据源控件它们声明?所以,在我们的例子SqlDataSource1将连接到数据源之前SqlDataSource2从而lstCities将值之前GridView1填充,并宣称原因是在于lstcitiesGridView1?!



B)如果是这样,那么当究竟ControlParameter检索的DropDownList值?我假设它是在之后的SqlDataSource1_Selected()事件处理程序和之前的SqlDataSource2_Selecting()事件处理程序,但是何时精确?

在.aspx页面中:

<asp:SqlDataSource ID="SqlDataSource1" ... > 
    </asp:SqlDataSource> 

    <asp:DropDownList ID="lstCities" DataSourceID="SqlDataSource1" 
     DataTextField="City" runat="server"></asp:DropDownList> 

    <asp:SqlDataSource ID="SqlDataSource2" ... > 
     <SelectParameters> 
      <asp:ControlParameter ControlID="lstCities" Name="City" 
       PropertyName="SelectedValue" /> 
     </SelectParameters> 
    </asp:SqlDataSource> 

    <asp:GridView DataSourceID="SqlDataSource2" runat="server" …> 
    </asp:GridView> 


感谢名单

编辑:

如果是回发,但随后这些参数会得到从装在页面的OnLoadComplete上的viewstate,再次按照它们声明的顺序。

Q1 - 假设ControlParameter绑定到控制C.我会想象在回传的财产C1 ControlProperty总是能够从ViewState中,没有C是什么类型的事情得到C.C1的价值,即使C ViewState禁用?!

Q2 - 但是我可以问为什么,如果是第一次创建了一个页面,不能为ControlParameter值也可以从视图状态检索?最后,当lstCities从数据源检索数据时,lstCities.SelectedValue是否设置了它的值?



感谢名单队友


第二个编辑:

我不及早回信,但是我不知道你已经回答。当我做到了,我花了整整20分钟试图让我的3个braincells才能正常工作,但我不知道如果我很成功


A)所以ControlParameter评估C.C1和从而在C被绑定后检索C.C1的值?!


Q1 - ControlParameter只读取自己的状态,只有以确定它是否改变了

A)所以ControlParameter检查它的ViewState是否改变(在之前,为了激发OnParameterChanged事件)绑定发生 - >因此它在Page.OnLoadComplete期间检查它的ViewState。 但是ControlParameter如何知道它的ViewState已经改变了(它会在第一次回发中知道)?最后,从第一次创建页面开始,ControlParameter的ViewState将始终被标记为脏,那么从一次回发到另一次回送,ControlParameter将如何知道其值在回发之间是否发生了变化?

B)我假设ControlParameter检查它的Viewstate是否只改变了,以便它能触发OnParameterChanged事件。但为什么处理这个事件如此重要?


第一次物业评估情况是在Page.OnLoadComplete

通过你的意思是ControlParameter检查自己的ViewState属性的评价?因此,你不是说ControlParameter评估C.C1(我假设C已被绑定后发生)


我真的很感谢你的帮助


第三编辑:

我真的很抱歉再次把你的时间。我会尽我所能,使这个我最后编辑。


更新()都在的onLoadComplete和当数据绑定发生被调用。内部更新()也执行了下面的句子:

this.ViewState["ParameterValue"] = actualValue; 

因此,如果更新()被调用时,数据绑定发生,那么这意味着什么是 为:当在下一回发更新()被调用的onLoadComplete, C.C1和ControlParameter已经将有相同的价值观,从而

   if ((actualValue == null && storedValue != null) 
      || (actualValue != null && actualValue != storedValue)) 

将始终返回false(更新时()被调用的onLoadComplete),如果是这样OnParameterChanged事件永远不会被解雇?1,我失败看到需要在OnLoadComplete中调用Update()!


非常感激

+0

我已经更新了我的答案。简而言之,Q1 - ControlParameter只读取自己的状态,并且只确定它是否改变; Q2 - ControlParameter总是评估C.C1,而不是视图状态,此时C.C1为空(或默认),因为在视图状态中没有任何内容,并且没有DataBind。 – Ruslan 2009-04-08 21:36:26

+0

提供更多信息,附带一些代码。 – Ruslan 2009-04-09 15:32:09

回答

2

你的第一个假设是正确的。

对于第二个问题,它取决于它是否回发和/或您是否明确约束。如果不是回发并且绑定自动发生,那么粗略地说,当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将被解雇。顺便说一下,这个活动至少有十个地方被触发。它在数据绑定和属性检索过程中不起重要作用(如果有的话)。