martes, 19 de octubre de 2010

Reflection y cómo ser un Jedi (Part 1)

¿Qué es reflection?

Respuesta wikipedia: "Reflection es el proceso por el cual un programa puede observar y modificar su propia estructura o comportamiento en tiempo de ejecución."

Respuesta maestro Jedi: "reflection es el control de la fuerza."

Respuesta serie Numb3rs: "Usamos reflection todos los días, al usar el IntelliSense, para debuggar, al usar contenedor IoC. También lo usamos para añadir webparts, para inspeccionar el código y para predecir su comportamiento. Con reflection podemos solucionar los misterios que se nos planteen."

¿Qué debemos hacer para empezar a utilizar la fuerza?

Existe un namespace llamado System.Reflection y una clase conocida como System.Type que nos acompañaran, en esta, fabulosa aventura hacia el interior del código.

Y así, sin más, ¿puedo empezar a usarlo?

Claro, pero no esperes aquí una clase magistral… <tono de Bilbao> ¡¡que somos desarrolladores joder!!</tono de Bilbao>. Dame un  punto de apoyo  HelloWorld y moveré el mundo conoceré toda la sintaxis.

Así que aquí van unas cuantos ejemplos, para la explicación vamos a utilizar una clase estúpida dentro de un namespace estúpido.

namespace StupidNameSpace
{
public class StupidClass
{
private string _field1;
private string _field2;

public StupidClass()
{
}

public StupidClass(string field1, string field2)
{
_field1 = field1;
_field2 = field2;
}

public string Field1
{
get { return _field1; }
set { _field1 = value; }
}

public string Field2
{
get { return _field2; }
set { _field2 = value; }
}

public string FooMethod1()
{
return string.Empty;
}

public string FooMethod2(string parameter)
{
return parameter;
}
}


Ahora vamos a crear una pequeña aplicación de consola para interrogar, utilizando la fuerza (reflection), a nuestra clase.

Ejemplo 1:
En el primer ejemplo vamos a crear un objeto de tipo StupidClass, usando el constructor público sin parámetros y luego utilizando el constructor con parámetros.



using System;
using System.Reflection;

namespace StupidNameSpace
{
public class Program
{
static void Main(string[] args)
{
// Obtenemos el tipo, tenemos que pasadle todo el fully qualified name,
// tened en cuenta que estamos en el mismo namespace, y en el mismo assembly, sino fuera así,
// tendriamos que pasarle, el nombre del assembly.
var type = Type.GetType("StupidNameSpace.StupidClass");
// Podriamos haber usado:
// var type = typeof(StupidClass);

// Usamos el constructor sin parámetros (default constructor) para crear un objecto llamado
// myStupidObject
var types = new Type[0];
var constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, types, null);
var myStupidObject = (StupidClass)constructorInfo.Invoke(null);

// Ahora hacemos lo mismo pero llamamos al constructor que recibe 2 parámetros
// y creamos un objeto llamado myStupidObject2
types = new Type[2];
types[0] = typeof (string);
types[1] = typeof (string);

var parameters = new object[2];
parameters[0] = "param1";
parameters[1] = "param2";

constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, types, null);
var myStupidObject2 = (StupidClass) constructorInfo.Invoke(parameters);
}
}
}


Esto esta muy bien, pero porque sabemos que constructor tiene la clase, si es público o privado, si recibe parámetros, etc. Pero y si no lo sabemos. Pues preguntémosle.



using System;
using System.Reflection;

namespace StupidNameSpace
{
public class Program
{
static void Main(string[] args)
{
// Obtenemos el tipo, tenemos que pasadle todo el fully qualified name,
// tened en cuenta que estamos en el mismo namespace, y en el mismo assembly, sino fuera así,
// tendriamos que pasarle, el nombre del assembly.
var type = Type.GetType("StupidNameSpace.StupidClass");

ConstructorInfo[] constructors = type.GetConstructors();
foreach(ConstructorInfo ci in constructors)
{
Console.WriteLine("===========");
Console.WriteLine("CONSTRUCTOR");
Console.WriteLine("===========");
Console.WriteLine(ci.Name);
if(ci.IsPrivate) Console.WriteLine("Private");
else Console.WriteLine("Public");
if(ci.IsStatic) Console.WriteLine("Static");
if(ci.IsAbstract) Console.WriteLine("Abstract");
if (ci.IsVirtual) Console.WriteLine("Virtual");
var parameters = ci.GetParameters();
if(parameters.Length > 0) Console.WriteLine("Parameters:");

foreach(ParameterInfo pi in parameters)
{
Console.WriteLine("-->" + pi.Name);
Console.WriteLine("-->" + pi.ParameterType);
}
}

Console.Read();
}
}
}

lunes, 11 de octubre de 2010

Error JavaScript en LookupField Control

Hoy he estado peleándome con uno de esos errores que odias encontrar, ya que son de esos errores que cuesta un poco reproducir, y por lo tanto su resolución no se prevé facilona.

Voy a intentar situarlos en contexto:

Cuando mostramos un LookupField control, por ejemplo al editar un item de una lista que uno de sus campos es un lookup hacia otra lista (editform.aspx), éste se puede mostrar de dos maneras diferentes, una cuando la lista a la que hacemos el lookup tiene menos de 20 items o 20 items y otra cuando tiene más de 20 items. En el primer caso, el control muestra un DropDownList y en el segundo muestra un textbox, un par de literales y una imagen (para no hacer que el dropdown sea demasiado largo), con ciertas llamadas a funciones javascript.

Una de estas llamadas se ejecuta al hacer click en la imagen, concretamente es una llamada a la función ShowDropdown que se encuentra en el fichero core.js. Esta función acaba llamando a otras dos funciones AbsLeft y AbsTop, que son el objeto de este post.

Código original de las funciones:

function AbsLeft(obj)
{
var x=obj.offsetLeft;
var parent=obj.offsetParent;
while (parent.tagName !="BODY")
{
x+=parent.offsetLeft;
parent=parent.offsetParent;
}
x+=parent.offsetLeft;
return x;
}

function AbsTop(obj)
{
var y=obj.offsetTop;
var parent=obj.offsetParent;
while (parent.tagName !="BODY")
{
y+=parent.offsetTop;
parent=parent.offsetParent;
}
y+=parent.offsetTop;
return y;
}


Resulta que estas dos funciones lanzan un null reference exception cuando el control lookup esta contenido dentro de un div y ese div contiene un position:relative.



Googleando un poco me he encontrado que este era un error conocido, pero la resolución que daban en un foro de sharepoint no me parecía la correcta, a saber, eliminar el position:relative.



http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/91f91a91-434f-444d-8a96-7823c91f862e



Mi solución final ha sido sobreescribir estas funciones en la master page de mi solución:



function AbsLeft(obj) {
var x = obj.offsetLeft;
var parent = obj.offsetParent;

while (parent != null && parent.tagName != "DIV" && parent.tagName != "BODY") {
x += parent.offsetLeft;
parent = parent.offsetParent;
}

if (parent != null && parent.tagName != "DIV" && parent != null) x += parent.offsetLeft;

return x;
}

function AbsTop(obj) {
var y = obj.offsetTop;
var parent = obj.offsetParent;

while (parent != null && parent.tagName != "DIV" && parent.tagName != "BODY") {
y += parent.offsetTop;
parent = parent.offsetParent;
}

if (parent != null && parent.tagName != "DIV" && parent != null) y += parent.offsetTop;

return y;
}


Pero aquí no ha acabado todo, estas funciones estan dentro del core.js y el core.js tiene el atributo defer=True, por lo tanto, nunca se llamaban a las funciones que había sobreescrito. Solución: cambiar este attributo añadiendo lo siguiente en la master page.

<SharePoint:ScriptLink language="javascript" name="core.js" Defer="false" runat="server"/>



Para más información sobre el attribute defer, aquí.

lunes, 4 de octubre de 2010

Periodic table HTML 5

Os dejo un enlace a una chuleta donde se muestran los diferentes elementos existentes en HTML 5, en forma de tabla períodica de los elementos. Cada “elemento” contiene links a W3C developer’s guide y a W3Schools.

http://joshduck.com/periodic-table.html