Если элементы управления всегда связаны с элементами управления источником данных в порядке их объявления, то - PullRequest
2 голосов
/ 07 апреля 2009


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>


* 1030 спасибо *

EDIT:

Однако, если это обратная передача, эти параметры будут загружены из состояния просмотра на OnLoadComplete страницы, опять же, в порядке их объявления.

Q1 - Давайте предположим, что ControlParameter связан со свойством C1 элемента управления C. Я мог бы предположить, что на обратных передачах ControlProperty всегда сможет получить значение C.C1 из ViewState, независимо от того, какой тип C, и даже если C отключил ViewState?!

В2. Но могу ли я спросить, почему, если страница создается впервые, нельзя ли получить значение ControlParameter также из viewstate? В конце концов, в тот момент, когда lstCities извлекает данные из источника данных, lstCities.SelectedValue имеет свое значение?



Спасибо, приятель


ВТОРОЕ РЕДАКТИРОВАНИЕ:

Я прошу прощения за то, что не ответил раньше, но я не понял, что вы ответили. И когда я это сделал, я потратил добрые 20 минут, пытаясь заставить мои 3 умных мозга работать должным образом, но я не уверен, что мне это удалось


A) Значит, ControlParameter оценивает C.C1 и, таким образом, получает значение C.C1 после привязки C?!


Q1 - ControlParameter только читает свое собственное состояние и только для определения, изменилось ли оно

A) Таким образом, ControlParameter проверяет, изменился ли его ViewState (чтобы инициировать событие OnParameterChanged) до того, как произойдет привязка -> таким образом, он проверяет свой ViewState во время Page.OnLoadComplete. Но как ControlParameter узнает, что его ViewState изменился (он узнает при первой обратной передаче)? В конце концов, с первого раза, когда страница создается, ViewState ControlParameter всегда будет помечен как грязный, так как, при переходе с одного постбэка на другой, ControlParameter узнает, изменилось ли его значение между постбэками?

B) Я предполагаю, что ControlParameter проверяет, изменилось ли только его Viewstate, чтобы он мог инициировать событие OnParameterChanged. Но почему обработка этого события так важна?


Первый раз, когда выполняется оценка свойства, находится на Page.OnLoadComplete

Под оценкой свойства вы имеете в виду ControlParameter, проверяющий свой собственный ViewState? Таким образом, вы не имеете в виду ControlParameter, оценивающий C.C1 (что, как я полагаю, происходит после привязки C)


Я очень ценю вашу помощь


ТРЕТЬЕ РЕДАКТИРОВАНИЕ:

Мне очень жаль, что я снова потратил ваше время. Я сделаю все возможное, чтобы сделать это моим последним редактированием.


Update () вызывается как в OnLoadComplete, так и при привязке данных. Внутри Update () также выполняется следующее предложение:

this.ViewState["ParameterValue"] = actualValue;

Так что если Update () вызывается, когда происходит привязка данных, то это означает что при следующей обратной передаче в OnLoadComplete вызывается UpDate (), C.C1 и ControlParameter уже будут иметь одинаковые значения и, таким образом,

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

всегда будетповернуть false (когда Update () вызывается в OnLoadComplete), и поэтому событие OnParameterChanged никогда не будет запущено? 1 Если это так, то я не вижу необходимости вызывать Update () в OnLoadComplete!


очень обязан

1 Ответ

2 голосов
/ 08 апреля 2009

Ваше первое предположение верно.

На ваш второй вопрос это зависит от того, является ли это сообщение обратно или нет, и / или явно ли вы связываете. Если это не обратная запись и привязка происходит автоматически, то, грубо говоря, значение ControlParameter извлекается, когда DataSourceView вызывает метод Select для DataBind, непосредственно перед событием OnSelecting. Последовательность для вида сетки (и любого данного элемента управления в этом отношении) следующая:

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 привязан к свойству C1 элемента управления C. Я бы предположил, что на обратных передачах ControlProperty всегда сможет получить значение C.C1 из ViewState, независимо от типа C и даже если C отключил ViewState?!

Это не совсем так ... При обратной передаче (и при первоначальном запросе по этому вопросу) состояние представления ControlParemeter оценивается только для того, чтобы увидеть, изменилось ли оно так, что событие OnParameterChanged может быть запущено. Фактическое значение ControlParameter оценивается по отношению к элементу управления, на который он указывает (посредством отражения). В вашем случае это будет "C.C1". Теперь, когда он читает C.C1, его значение, скорее всего, читается из состояния просмотра. Но ни в коем случае ControlParameter непосредственно не считывает состояние просмотра C.

В2. Но могу ли я спросить, почему, если страница создается впервые, нельзя ли получить значение для 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?!

ControlParameter извлекает значения всякий раз, когда его запрашивают, что в этом сценарии происходит (косвенно) в двух местах: OnLoadComplete и DataBind (инициируется PreRenderRecursiveInternal). На 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 проверяет, изменилось ли только его Viewstate, чтобы он мог инициировать событие OnParameterChanged. Но почему обработка этого события так важна?

Я не знаю, что это важно. Я полагаю, что, как и любое другое событие, оно позволяет вам отслеживать изменения в свойствах параметра и действовать в соответствии с вашими потребностями. Его запускают во многих местах, но я не вижу, где кто-то подписывается на него. Итак ...

Под оценкой свойства вы подразумеваете, что ControlParameter проверяет свой собственный ViewState? Таким образом, вы не имеете в виду ControlParameter, оценивающий C.C1 (что, как я полагаю, происходит после привязки C)

Это мЭто означает, что вызывается ControlParameter.UpdateValue, который проверяет ViewState по указанным причинам, затем вызывает ControlParameter.Evalue, который затем находит элемент управления и извлекает данные, используя отражение (Eval). Смотри выше.

Третье редактирование

Я предполагаю, что под Update вы подразумеваете UpdateValue.

Так что, если Update () вызывается, когда происходит привязка данных, то это означает, что при следующей обратной передаче UpDate () вызывается в 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 будет запущен. Кстати, есть еще как минимум десять мест, где это событие будет запущено. Он не играет большой роли (если таковая имеется) в процессе привязки данных и поиска свойств.

...