Modificando la carga del ViewState en Mono
"Alberto León" <[email protected]>
| Newsgroups | gmane.comp.gnome.mono.hispano |
|---|---|
| Message-ID | <[email protected]> |
Al final he seguido vuestro consejo sobre como colaborar y tras muchas horas
de estudio he dado con una posible solución que quiero discutir con
vosotros.
Con lo que estoy obsesionado es con permitir la carga de valores de
ViewState a través del ID ya que actualmente se hace por índice en
ASP.NETde Mono. Esto hace que algunas aplicaciones o frameworks de
AJAX sean
capaces de hacer el UpdatePanel o ForceAndUpdate, que es realizar una
llamada callback o postback de una pequeña porción de código y actualizarlo.
El caso que nos ocupa nos permite actualizar el contenido de DataGrid,
Repeaters, etc. sin tener que recargar la página entera. Sin embargo esto
hace que el nuevo control generado cambie el orden de las cosas y pierda su
información, por ejemplo, teníamos un Repeater que nos generaba lo
siguiente:
<asp:TextBox ID="texto1" runat="server" Text="texto del control
1"></asp:TextBox>
<asp:TextBox ID="texto2" runat="server" Text="texto del control
2"></asp:TextBox>
<asp:TextBox ID="texto3" runat="server" Text="texto del control
3"></asp:TextBox>
<asp:TextBox ID="texto4" runat="server" Text="texto del control
4"></asp:TextBox>
Sin embargo hemos generado un comando que nos aumenta el número de elementos
en 2 nuevos que además ordena distinto por la razón que sea:
<asp:TextBox ID="texto4" runat="server" Text="texto del control
5"></asp:TextBox>
<asp:TextBox ID="texto5" runat="server" Text="texto del control
4"></asp:TextBox>
<asp:TextBox ID="texto3" runat="server" Text="texto del control
3"></asp:TextBox>
<asp:TextBox ID="texto2" runat="server" Text="texto del control
2"></asp:TextBox>
<asp:TextBox ID="texto1" runat="server" Text="texto del control
1"></asp:TextBox>
<asp:TextBox ID="texto6" runat="server" Text="texto del control
6"></asp:TextBox>
Cuando la página guarda el estado de vista de sus controles guarda su propio
estado (SaveViewState) en un objeto Triplet: los valores de sus propios
atributos en un StateBag, la lista de índices de sus controles en un
ArrayList, los estados de vista de sus controles en un ArrayList.
Cuando volvemos a cargar la página o uno de sus controles llaman a
LoadViewState, esta función de forma predeterminada retorna los valores de
los atributos en estricto orden.
Para controlesArrayList[0] buscará estadoVistaArrayList[0], el propio
control se encargará de buscar en su estado de vista los valores de sus
atributos.
Hasta aquí bien. Y eso ocurre en la clase Control.cs de la que heredan
WebControl y otras tantas clases. El problema viene con las llamadas
AjaxCallBack que actualizan el contenido de un panel con DataGrid o
Repeater, añadiendo elementos o cambiando su orden.
En el caso explicado el nuevo control de la posición 0 tiene el ID texto4,
para el que tratará de cargar el estado de vista 0, que en el atributo Text
contendrá "texto del control 1". Para evitar esto en .Net 2.0 se incluyó el
LoadViewStateByIdAttribute. Cuando antes de la llamada al constructor de un
control se coloca una etiquta con este atributo le indica que su búsqueda de
estados de vista no se va a hacer por el índice de la matriz si no por ID.
No he visto el código C# ni el SIL de Control.cs, pero sí el de Mono.
Imagino que en la clase LoadViewState tiene una condición: si la carga por
ID es verdadera, hace la asignación de viewstates por ese camino. En el
LoadViewState de Control.cs en Mono no hay ninguna condición que pregunte
por el ID, simplemente asigna los ViewState por el orden en la matriz.
Por otro lado la propiedad LoadViewStateByIdAttribute no está implementada,
está comenzada en el archivo LoadViewStateById.jvm.cs, esta es la mayor
fuente de problemas para diferentes librerías .Net y Ajax. Esta propiedad lo
único que hace realmente es poner en true la propiedad LoadViewStateById del
control.
De modo que implementar la propiedad parece sencillo. Lo que puede ser más
complicado es modificar el LoadViewState de Control.cs, que es el método que
carga los estados de vista en los controles hijo de un control, tengo alguna
idea que me gustaría que me comentaráis.
Esta es la parte del LoadViewState de Mono que carga los estados de vista en
los controles hijos:
(savedInfo.Sencond solo contiene un Array de índices, es decir es un listado
de integers)
ArrayList controlList = savedInfo.Second as ArrayList;
if (controlList == null)
return;
ArrayList controlStates = savedInfo.Third as ArrayList;
int nControls = controlList.Count;
for (int i = 0; i < nControls; i++) {
int k = (int) controlList [i];
if (k < Controls.Count && controlStates != null) {
Control c = Controls [k];
c.LoadViewStateRecursive (controlStates [i]);
}
else {
if (pendingVS == null)
pendingVS = new Hashtable ();
pendingVS [k] = controlStates [i];
}
}
Propongo añadir un if antes del for de la siguiente manera:
if(LoadViewStateById){
List<Control> controles = new List<Control>(Controls);
List<StateBag> estados = new List<StateBag>(controlStates);
controles.ForEach(delegate (Control c) {
c.LoadViewStateRecursive(
estados.Find(delegate (StateBag estado) {
return estado["ID"] == c.ID;
});
);
});
}
La idea es usar generics para hacer el trabajo sucio. Espero opiniones,
gracias.
_______________________________________________
Mono-hispano mailing list
[email protected]
https://listas.hispalinux.es/mailman/listinfo/mono-hispano