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