asp.net - DropDownList OnSelectedIndexChange al 0 ° índice sin ViewState
user-controls drop-down-menu (2)
El problema es que está cargando los datos cada vez y esto está restableciendo el índice seleccionado. Imagina que este es tu menú desplegable:
zero [selected]
one
two
Luego, en el cliente, cambia el índice seleccionado:
zero
one [selected]
two
Esto rellena la entrada oculta __EVENTARGUMENT
con su nuevo índice (1) y la entrada oculta __EVENTTARGET
con la id
de su menú desplegable. Ahora el código del lado del servidor entra en acción y vuelve a cargar sus datos:
zero [selected]
one
two
"cero" es el valor seleccionado porque ese es el valor predeterminado cuando se cargan los datos. Luego, ASP.NET busca __EVENTTARGET
y __EVENTARGUMENT
en la Request
y encuentra el id
su lista desplegable y encuentra el nuevo índice (1). Ahora su menú desplegable se ve así:
zero
one [selected]
two
Dado que el índice ha cambiado, el menú desplegable aumenta su evento SelectedIndexChanged
, lo que indica que el índice ha cambiado. Obviamente esta es la parte que está funcionando, ahora veamos por qué seleccionar el primer elemento de la lista no plantea el evento.
Ahora digamos que todavía tenemos el menú desplegable en el estado en el que se encontraba (con "uno" seleccionado y el índice seleccionado de 1). ¿Qué sucede cuando seleccionamos el primer elemento de la lista en el cliente?
__EVENTTARGET
y __EVENTARGUMENT
se completan con la id
del menú desplegable y el nuevo índice (0). Luego, el servidor carga los datos en el menú desplegable y el menú desplegable ahora se ve así:
zero [selected]
one
two
Tenga en cuenta que, dado que recargó los datos antes de que se dispararan los eventos, el índice ya está establecido en 0 porque ese es el valor predeterminado. Ahora, cuando se activa su evento y el índice seleccionado de la lista desplegable se establece en 0, el menú desplegable no ve esto como un cambio ya que el índice seleccionado (hasta donde sabe) no ha cambiado.
Aquí es cómo solucionar el problema:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
}
Lo que esto hará es solo cargar los datos en el menú desplegable si la página no es una devolución de datos. Esto significa que ViewState mantendrá los datos para usted, así como también el índice seleccionado, de modo que cuando publique nuevamente, el menú desplegable comparará el nuevo índice con el índice que vio en el cliente.
Seguí el artículo TRULLY Understanding ViewState (gran artículo por cierto) y llenar mi lista desplegable está funcionando muy bien. Incluso configuré un evento OnSelectedIndexChange que dispara casi igual de genial.
El problema que he encontrado es que el evento SelectedIndexChanged no se activará al seleccionar el 0 ° índice. Lo hace todas las otras veces sin embargo.
Aquí hay un código:
<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false"
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
protected override void OnInit(EventArgs e)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
base.OnInit(e);
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
OnSelectedQueueChanged(e);
}
public void OnSelectedQueueChanged(EventArgs e)
{
// Do stuff.
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e)
{
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Supongo que puedo hacer algún tipo de control en el método Page_Load:
if(ViewState["selectedIndexChangedFlag"] != 1)
// raise OnSelectedChange event
¿O hay algo que puedo configurar en el método OnInit () donde estoy reencuadernando esta información cada vez que puedo?
Ver, mi EventHander personalizado plantea un evento que es capturado por una página principal en la que reside este control, de modo que el padre pueda tomar alguna acción usando el valor recién seleccionado. Y esto actualmente está funcionando para todos los casos donde el índice seleccionado es> 0.
Creo una propiedad en este control que contiene el índice seleccionado más recientemente, en cuyo caso mi página principal puede actuar en este valor de propiedad en cada Page_Load ... dunno.
Abierto a sugerencias. O cómo forzar este evento SelectedIndexChanged para disparar para esa 0ª selección de índice.
Mi objetivo al deshabilitar ViewState en esta lista desplegable es minimizar el tamaño de ViewState para la página.
El problema que tuve con solo hacer el if (! Page.IsPostBack) {... DataBind () ...}, es que cuando seleccionas un elemento por primera vez y la página se vuelve a cargar, mi lista desplegable se vacía .
Lo que terminé haciendo fue crear otra propiedad en este control, LastIndex. Cuando se desencadena el evento OnSelectedIndexChanged, actualizo el valor de LastIndex. En Page_Load, comparo los valores del índice Actual y Último, si son diferentes, y luego disparo un evento cambiado en el Índice.
public int SelectedValue{
get { return this.DropDownList1.SelectedItem.Value; }
}
public int LastIndex{
get { return this.ViewState["lastIndex"] == null ? -1 : (int)this.ViewState["lastIndex"]; }
set { this.ViewState["lastIndex"] = value; }
}
protected override void OnInit(EventArgs e){
base.OnInit(e);
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e){
if (this.LastIndex != this.SelectedValue)
this.OnSelectedQueueChanged(new EventArgs());
}
private ListItemCollection fillQueueDropDown(){...}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){
OnSelectedQueueChanged(e);
this.LastIndex = this.SelectedValue;
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e){
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Tienes razón, sin embargo. Los datos se vuelven a cargar y volver a enlazar en la fase OnInit. Luego se restaura el ViewState (y cuando se restaura el 0 ° índice), cuando finalmente llegamos a la fase de Eventos, el control no detecta el cambio.
No estoy seguro de que esta sea la ruta más elegante, pero está funcionando bien hasta el momento.
Luego encontré esto en los documentos msdn para IPostBackDataHandler:
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection) {
String presentValue = Text;
String postedValue = postCollection[postDataKey];
if (presentValue == null || !presentValue.Equals(postedValue)) {
Text = postedValue;
return true;
}
return false;
}
Como el valor presente es el mismo que el valor cambiado, el evento no se dispara.