Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果控件总是按照声明顺序绑定到数据源控件,则_C#_Asp.net_Data Binding_Objectdatasource - Fatal编程技术网

C# 如果控件总是按照声明顺序绑定到数据源控件,则

C# 如果控件总是按照声明顺序绑定到数据源控件,则,c#,asp.net,data-binding,objectdatasource,C#,Asp.net,Data Binding,Objectdatasource,A) 下面的问题基于这样的假设:控件总是按照声明的顺序绑定到数据源控件?所以在我们的示例中,SqlDataSource1将连接到SqlDataSource2之前的数据源,因此lstCities将填充GridView1之前的值,原因是lstCities是在GridView1之前声明的 B) 如果是,那么ControlParameter什么时候从DropDownList中检索值?我假设它位于SqlDataSource1_Selected()事件处理程序之后,SqlDataSource2_Selec


A) 下面的问题基于这样的假设:控件总是按照声明的顺序绑定到数据源控件?所以在我们的示例中,SqlDataSource1将连接到SqlDataSource2之前的数据源,因此lstCities将填充GridView1之前的值,原因是lstCities是在GridView1之前声明的



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>
所以,如果在数据绑定发生时调用Update(),那么这意味着 在OnLoadComplete中调用OnNext postback UpDate()时,C.C1和ControlParameter将已经具有相同的值,因此

             if ((actualValue == null && storedValue != null)
             || (actualValue != null && actualValue != storedValue))
将始终返回false(在OnLoadComplete中调用Update()时),因此OnParameterChanged事件将永远不会被触发?1如果是,则我看不到在OnLoadComplete中调用Update()的必要性



非常感谢你的第一个假设是正确的

对于第二个问题,这取决于它是否是回发邮件和/或是否显式绑定。如果不是回发和绑定自动发生,那么粗略地说,当DataSourceView调用Select on DataBind时,在选择事件之前检索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,然后触发参数检索、onselection、数据检索和onselect

但是,如果是回发,则这些参数将从页面的OnLoadComplete上的viewstate中加载,再次按照声明的顺序加载

这就是你要找的吗

编辑

Q1-假设ControlParameter绑定到控件C的属性C1。我可以想象,在回发时,ControlProperty始终能够从ViewState获取C.C1的值,无论C是什么类型,即使C禁用了ViewState

这不完全是怎么发生的。。。在回发(以及针对该问题的初始请求)时,仅评估ControlParemeter的视图状态,以查看其是否已更改,从而触发OnParameterChanged事件。对照ControlParameter指向的控件(通过反射)计算ControlParameter的实际值。在你的情况下,应该是“C.C1”。现在,当它读取C.C1时,它的值很可能是从视图状态读取的。但是ControlParameter在任何时候都不会直接读取C的视图状态

问题2-但我可以问一下,如果第一次创建页面,为什么不能从viewstate中检索ControlParameter的值?毕竟,当lstCities从数据源中检索数据时,lstCities.SelectedValue是否设置了其值

就是这样,在那一点上(第一次加载页面时),lstCities还没有检索到任何数据。第一次属性求值发生在Page.OnLoadComplete上,但在任何数据绑定之前(这发生在触发Page.prerenderCursiveInternal后不久)

以粗略的形式,尝试将其放置在页面的生命周期中:

...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被绑定后检索C.C1的值

ControlParameter在任何时候被询问时都会检索值,在本场景中,这(间接)发生在两个位置:OnLoadComplete和DataBind(由PreRenderRecursiveInternal触发)。在OnLoadComplete上,C不绑定。在PreRenderCursiveInternal上,在数据绑定之后,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检查其Viewstate是否仅为触发OnParameterChanged事件而更改。但为什么处理这一事件如此重要

我不知道这有多重要。我想,和任何其他事件一样,它允许您跟踪参数属性的更改,并根据您的需要采取相应的行动。它在很多地方被炒了,但我看不到有人订阅它。所以

属性评估是指ControlParameter检查自己的ViewState?因此,您不是指对C.C1求值的控制参数(我假设这发生在C被绑定之后)

这意味着调用ControlParameter.UpdateValue,它会检查ViewState是否存在指定的原因,然后调用ControlParameter.Evalue,它会找到一个控件并使用反射(Eval)检索数据。见上文

第三次编辑

我想你所说的更新是指更新值

所以,如果在数据绑定发生时调用Update(),那么这意味着在OnLoadComplete中调用下一次回发Update()时,C.C1和ControlParameter将已经具有相同的值

没有必要。您忘记了视图状态是在LoadAllState上加载的,在它和OnLoadComplete之间还有六个步骤(参见上面的生命周期页面)。每一个都可以修改源代码管理的(C.C1)值

假设你有C.C1=“x”并回复了一篇帖子。现在,所有控件的视图状态都已加载(LoadAllState)。如果C.C1将其值存储在视图状态,它将加载“x”。在加载(LoadRecursive)页面上,您决定设置C.C1=“y”。这里,C.C1可能决定是否将“y”存储在其视图状态中——这与此无关。然后其他事件接踵而至。下一个是onload complete。
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
        //...
    }
}
if ((actualValue == null && storedValue != null)
 || (actualValue != null && actualValue != storedValue))
    this.OnParameterChanged();