Sector 7G

Sector7G Live Search

About Me

About Me

Windows Live Messenger Presence Gadget

Twitter Gadget

My Photo Albums

My Photo Web Albums

Logos

  • Sector7G
  • ilitia Technologies

Kartones.Net MVF Winner
Ejecución de consultas en LINQ

En LINQ las consultas pueden ser ejecutadas de dos formas diferentes. Mediante ejecución inmediata, la consulta devuelve los resultados en el mismo momento en el que es definida, es decir, en el caso de LINQ To SQL el acceso a la base de datos se ejecuta cuando la sentencia es construida. Y mediante ejecución diferida, la sentencia LINQ es creada y su ejecución se produce cuando el resultado es enumerado, al hacer un foreach por ejemplo.

Ejecución diferida en LINQ

Una consulta es de ejecución diferida, cuando la ejecución de la consulta se produce en el momento de ser enumerado el resultado, no en el instante de ser creada. Para entender esto mejor veamos el siguiente ejemplo, ¿cuál es el resultado?.

List<string> blogs = new List<string> { 
    "Sector 7G", "KaRt0nEs Blog", "La Web de Programación",  
    "Code, Freak and Videotape", "Dave Dan", "Frankys", "FreakWorld", 
    "Haztelo Tu", "Jad Engine Blog", "Lobo666 Blog", "MAD-MAX", 
    "Mi Ubuntu y yo", "Myrjam's Blog", "NetCódigo e Internet",  
    "The Elder Thoughts", "The Spike", "Berks Worlds"
};
 
var names = from b in blogs
                where b.EndsWith("7G")
                select b;
 
blogs[1] = "KaRt0nEs Blog 7G";
 
foreach (var item in names)
{
    Console.WriteLine(item);
}

Seguramente en un primer momento pienses que el resultado es:


Sector 7G

Pero realmente el resultado de ejecutar esa sentencia LINQ es:


Sector 7G
KaRtOnEs Blog 7G

Esto es debido a que cuando la sentencia es definida dentro del objeto names, ésta todavía no ha sido ejecutada, es decir, todavía no se han devuelto los resultados. Este objeto almacenado dentro de names ya implementa la interfaz IEnumerable<string>.

var names = from b in blogs
                where b.EndsWith("7G")   <- La consulta no se
                select b;                   ejecuta aquí.

Así que hasta este punto names sólo sabe que tiene que hacer, pero todavía no ha hecho nada. La consulta será ejecuta, cuando ésta esa enumerada a través del método GetEnumerator, el cual hace uso del operador yield. Así que hasta que el foreach no es ejecutado no tiene lugar la consulta, es decir,  la consulta no se ha ejecutada realmente. De esta manera, al verse alterada la colección blogs antes del foreach, el resultado esperado también se ha visto alterado.

foreach (var item in names)     <- Aquí es cuando la consulta
{                                  tiene lugar.
    Console.WriteLine(item); 
}

Por este motivo, por ejemplo en LINQ to SQL, una consulta que es ejecutada varias veces puede tener resultados diferentes. Si no se quiere que esto ocurra, se puede hacer que la consulta sea de ejecución inmediata. Para que una consulta se ejecute nada más definirla se pueden usar cualquiera de estos métodos: ToArray, ToList, ToLookup, ToDictionary, etc (ver el listado de operadores inmediatos). Estos métodos cambian la estructura de datos de datos y cachean el resultado.

Listado de operadores de ejecución diferida:

Operador Operator Name
Conversion Cast, OfType, AsEnumerable
Element DefaultIfEmpty
Generation Empty, Range, Repeat
Grouping GroupBy
Union GroupJoin, Join
Ordination OrderBy, ThenBy, OrderByDescending, ThenByDescending, Reverse
Partition Skip, SkipWhile, Take, TakeWhile
Restriction Where
Selection Select, SelectMany
Set Concat, Distinct, Except, Intersect, Union

Evidentemente esto tiene sus beneficios y sus inconvenientes, sólo hay que conocerlo para poder sacar el mayor provecho.

Ejecución inmediata

Una consulta es de ejecución inmediata, cuando ésta es ejecutada en el momento de su definición. Para conseguir forzar la ejecución de una consulta, sólo hay que usar cualquiera de los operadores que se muestran en la lista de abajo. Estos operadores lo que hacen es cambiar la estructura de datos devuelta por la consulta y cachear el resultado.

var names = (from b in blogs
                where b.EndsWith("7G")
                select b).ToList();   <- La consulta SÍ es ejecutada
                                         aquí.
 
foreach (var item in names)
{
    Console.WriteLine(item);
}

Esta vez el resultado si es:


Sector 7G

Listado de operadores de ejecución inmediata:

Operador Operator Name
Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum
Conversion ToArray, ToDictionary, ToList, ToLookup
Element ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
Equality SequenceEqual
Quantifiers All, Any, Contains

Posted: Apr 19 2008, 09:09 PM by Pedroafa | with no comments
Filed under: , ,
Sintaxis LINQ: Average

El operador Average calcula la média aritmética de una colección de registros. Las signaturas del método son las siguientes:

   1:  public static decimal Average(
   2:      this IEnumerable<decimal> source)
   3:   
   4:  public static double Average(
   5:      this IEnumerable<int> source)
   6:   
   7:  public static Nullable<decimal> Average(
   8:      this IEnumerable<Nullable<decimal>> source)
   9:   
  10:  public static Nullable<double> Average(
  11:      this IEnumerable<Nullable<double>> source)
  12:   
  13:  public static double Average(
  14:      this IEnumerable<long> source)
  15:   
  16:  public static Nullable<double> Average(
  17:      this IEnumerable<Nullable<int>> source)
  18:   
  19:  public static double Average(
  20:      this IEnumerable<double> source)
  21:   
  22:  public static Nullable<double> Average(
  23:      this IEnumerable<Nullable<long>> source)
  24:   
  25:  public static Nullable<float> Average(
  26:      this IEnumerable<Nullable<float>> source)
  27:   
  28:  public static float Average(
  29:      this IEnumerable<float> source)
  30:   
  31:  public static decimal Average<TSource>(
  32:      this IEnumerable<TSource> source, 
  33:      Func<TSource, decimal> selector)
  34:   
  35:  public static double Average<TSource>(
  36:      this IEnumerable<TSource> source, 
  37:      Func<TSource, double> selector)
  38:   
  39:  public static double Average<TSource>(
  40:      this IEnumerable<TSource> source, 
  41:      Func<TSource, int> selector)
  42:   
  43:  public static double Average<TSource>(
  44:      this IEnumerable<TSource> source, 
  45:      Func<TSource, long> selector)
  46:   
  47:  public static Nullable<decimal> Average<TSource>(
  48:      this IEnumerable<TSource> source, 
  49:      Func<TSource, Nullable<decimal>> selector)
  50:   
  51:  public static Nullable<double> Average<TSource>(
  52:      this IEnumerable<TSource> source, 
  53:      Func<TSource, Nullable<double>> selector)
  54:   
  55:  public static Nullable<double> Average<TSource>(
  56:      this IEnumerable<TSource> source, 
  57:      Func<TSource, Nullable<int>> selector)
  58:   
  59:  public static Nullable<double> Average<TSource>(
  60:      this IEnumerable<TSource> source, 
  61:      Func<TSource, Nullable<long>> selector)
  62:   
  63:  public static Nullable<float> Average<TSource>(
  64:      this IEnumerable<TSource> source, 
  65:      Func<TSource, Nullable<float>> selector)
  66:   
  67:  public static float Average<TSource>(
  68:      this IEnumerable<TSource> source, 
  69:      Func<TSource, float> selector)

Cómo se puede observar este método tiene una sobrecarga para cada tipo numérico.

Veamos un ejemplo y cómo se utilizaría el método en cuestión.

   1:  double average = (from n in numeros
   2:                    select n).Average();
   3:   
   4:  double average = numeros.Average();

Cómo se puede ver en los ejemplos este método carece de palabra clave o alias.

Cast vs OfType en LINQ

LINQ no puede trabajar con colecciones que no implementen la interfaz IEnumerable<T>. Esto es debido a que no se encuentran fuertemente tipadas. Por este motivo dentro de un ArrayList podríamos encontrarnos tanto elementos de tipo string como de tipo integer.

ArrayList products = new ArrayList{
    new Product { Name= "Product1"},
    new Product { Name= "Product2"},
    1
};

Esto ocurre con todos los tipos de colecciones que se encuentran dentro del namespace System.Colleccitons:

En este punto entran en juego los métodos Cast<T> y OfType<T>. Estos métodos son capaces de convertir una colección que no implemente la interfaz IEnumerable<T>, en una que si lo haga. De esta manera es posible utilizar este tipo de colecciones dentro de LINQ.

var items = products.OfType<Product>()
                .Where(p => p.Name.EndsWith("1"));
 
foreach (var item in items)
{
    Console.WriteLine(item.Name);
}


Product1

La diferencia que existe entre los dos métodos es que en el caso de Cast, si dentro de la colección se encuentra un elemento que no pueda ser convertido al tipo marcado, se lanzará una excepción. En el caso de OfType, si se encuentra un elemento que no se pueda convertir al tipo indicado, este se desecha.

var items = products.Cast<Product>()
                        .Where(p => p.Name.EndsWith("1"));
 
var item in items)
{
    Console.WriteLine(item.Name);
}


Product1
Invalid cast from ‘Sistem.Int32’ to SampleLinq.Product’.

Posted: Apr 16 2008, 08:41 PM by Pedroafa | with 1 comment(s)
Filed under: ,
Twitter Gadget

Twitter follower twitter follower twitter follower, ¿Quién gana: 'Twitter' o 'follower'?.

Tras un primer intento de hacer un gadget que consumirá los post de Twitter (ver demo). Diego y yo nos quedamos con las ganas de hacer una versión del mismo con Silverlight. Así que el otro día que tenía algo de tiempo me puse manos a la obra. El resultado final se puede ver en esta Live Demo o en la parte izquierda de mi blog.

twitter gadget

Para poder utilizar el gadget dentro de un blog o una web, sólo hay que hacer uso de un iframe. La url donde se encuentra hospedado el gadget es http://demos.kartones.net/006/default.html. Esta url hace uso de dos parámetros dentro de su querystring: user, donde se introduce el código de usuario del Twitter y foot que se debe establecer a 0 para esconder el pie de la página. También hay que tener en cuenta que el gadget tiene un tamaño de 150x150 pixeles. El siguiente snippet de código es el que he utilizado para embeberlo dentro de mi blog.

<iframe id="Iframe1" height="150" width="150" frameborder="0" scrolling="no" src="http://demos.kartones.net/006/default.html?user=9658712&foot=0"></iframe>

Así de sencillo es embeber el gadget dentro de una web :).

Gadget Enjoin!!.

DEMOS.KARTONES.NET

Hace unos meses Diego nos ofreció, a todos los bloggers, un espacio dentro de la comunidad donde poder alojar todas esas demos y ejemplos que acompañan a los post. Así que este post más o menos viene a presentar esta nueva sección del portal.

Presas del aburrimiento, nos hemos currado una mini web (con Silverlight :) ) donde iremos recopilando todas las demos, experimentos y de más cosas que se nos vayan ocurriendo. Vamos!!, casi cualquier cosa que tenga un soporte web, la podréis llegar a encontrar aquí.

Por el momento ya tenemos demos que hacen uso de: JSON, Javascript, Windows Live APIS, WPF 3.5,… y bueno, esta lista irá creciendo hasta el infinito ;).

Si queréis daros una vuelta por las demos, aquí os dejo la url demos.kartones.net.

Por cierto, si alguien quiere unirse a la comunidad sólo tiene que pedir un blog, que para eso están estos inventos del Community Server. Si a alguien le interesa puede informarse aquí.

Demo Enjoin!!.

iZ, Nosotros estuvimos allí.

En todos los proyectos en los que participamos nos gusta dejar nuestra huella, para poder echar la vista atrás y decir “Nosotros estuvimos allí”. Sobre todo cuando el proyecto en el que has participado ha salido bastante bien.

En el tema del desarrollo de Windows Live Agents (WLA) lo tenemos muy fácil. El propio template del proyecto trae un patrón de conversación para poder preguntar al bot quién lo ha desarrollado. En este caso, nosotros dejamos ahí nuestro “huevo de pascua”. Si le preguntabas a iZ, “¿Quíen te ha desarrollado?” en sus tres primeros días de vida contestaba “Me desarrolló ilitia Technologies para el PSOE”.

iz - ilitia 2 533

Si se lo preguntas ahora, te responderá que fue Microsoft. Nos lo hicieron cambiar por temas contactuales, pero bueno, tuvimos nuestro minuto de gloria que es lo que importa.

Sintaxis LINQ: Any, All y Contains

Any

El operador Any se utiliza para determinar si existe un elemento dentro de una secuencia que cumpla una condición expecífica. Las signaturas del método son las siguientes:

   1:  public static bool Any<TSource>(
   2:      this IEnumerable<TSource> source)
   3:   
   4:  public static bool Any<TSource>(
   5:      this IEnumerable<TSource> source, 
   6:      Func<TSource, bool> predicate)

Como se puede ver en las signaturas el método devuelve true si algún elemento cumple con la condición y false si no encuentra nada. En el siguiente ejemplo queremos comprobar si existe algún desarrollador que se llame Jorge dentro de nuestra colección.

   1:  var list = (from d in developers
   2:              select d).Any(d => d.Name == "Jorge");

El ejemplo anterior devolverá true ya que existe un desarrollador que se llame Jorge. Para el siguiente ejemplo, en el cual utilizamos una lista vacía, el método Any devolverá false ya que no existe ningún elemento en la colección.

   1:  var list = Enumerable.Empty<Developer>()
   2:                          .Any(d => d.Name == "Jorge");

All

El operador All se utiliza para determinar si todos los elementos de una colección cumplen con una condición específica. La signatura del método es la siguiente:

   1:  public static bool All<TSource>(
   2:      this IEnumerable<TSource> source, 
   3:      Func<TSource, bool> predicate)

Este método devolvera true, si todos los elementos cumplen con la condición indicata y false, si hay algún elemento que no cumpla con la condición. En el siguiente ejemplo queremos comprobar que todos los desarroladores haya estado por lo menos en un cliente.

   1:  var list = (from d in developers
   2:              select d).All(d => d.Customers.Count() >= 1);

Si aplicamos este método sobre una colección vacía, este devolverá true. Esto es debido aque el método devuelve false encuanto encuentra un elemento que no coincide con la condición seleccionada y evidentemente en una colección vacía no va ha encontrar ningún elemento. 

   1:  var list = Enumerable.Empty<Developer>()
   2:                 .All(d => d.Customers.Count() >= 1);

Contains

El método Contains determina si un determinado elemento se encuentra en la colección. Las signaturas del método son las siguientes:

   1:  public static bool Contains<TSource>(
   2:      this IEnumerable<TSource> source, 
   3:      TSource value)
   4:   
   5:  public static bool Contains<TSource>(
   6:      this IEnumerable<TSource> source, 
   7:      TSource value, 
   8:      IEqualityComparer<TSource> comparer)

En la segunda signatura nos permite personalidar la forma en la que las comparaciones son realizas. Este método devolverá true si en cuentra el elemento y false sino existe el elemento en la colección.

En el siguiente ejemplo, queremos comprobar que en la colección exista el desarrollador, Jorge. Como veréis en el código ,hemos aprovechado la segunda signatura de este método para que se busque por el nombre simplemente.

   1:  Developer d = new Developer{ Name="Jorge", Language="C#", Age=18};
   2:   
   3:  var list = developers.Contains(d, new DeveloperComparer());
   4:   
   5:  public class DeveloperComparer : IEqualityComparer<Developer>
   6:  {
   7:      public bool Equals(Developer x, Developer y)
   8:      {
   9:          if (x.Name == y.Name)
  10:          {
  11:              return true;
  12:          }
  13:   
  14:          return false;
  15:      }
  16:   
  17:      public int GetHashCode(Developer obj)
  18:      {
  19:          return obj.Name.ToString().GetHashCode();
  20:      }
  21:  }

Nota: Para la realización de estos ejemplos se han utilizado una serie entidades y colecciones que podréis encontrar aquí.

Jugando Con Windows Live Virtual Earth y Javascript a Muerte

Windows Live Virtual Earth Map es un sistema de búsqueda de mapas. Usando este control se pueden buscar direcciones, empresas, tiendas y todo tipo de ubicaciones. Al igual que Google Map, este sistema es ideal para la creación de MashUps con mapas.

Para poder interactuar con el mapa Virtual Earth, esté expone una API en javascript. Usando esta API se pueden hacer un montón de cosas con el mapa como: buscar ubicaciones, poner chinchetas en diferentes lugares, hacer búsquedas de rutas, etc.

Para que el renderizado del mapa se haga bien, es necesario que la página web (html, aspx) donde se va ubicar el control se genere en formato UTF-8. Si la página no es generada en este formato, alguno de los objetos del mapa no se verán bien. Por eso es necesario añadir la siguiente línea de código:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Como anteriormente comentaba, la API para trabajar está desarrollada en javascript. Esto hace necesario agregar a la lista de archivos javascript el siguiente:

<script type="text/javascript" 
src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6">
</script>

Para presentar el control solamente hará falta el uso de una etiqueta div con un identificador único. Este id se le pasará a la API para que sepa donde tiene que mostrar el mapa.

Como recomendación, dentro de los estilos css de este div, además de definir el tamaño del mapa, también será necesario marcarlo con una posición relativa. De esta manera se evitará que el mapa se salga del tamaño especificado.

<div id="MapaSmaple" style="position:relative; width:500px; height:500px;">       
</div>

Las instrucciones javascript que nos harán falta para mostrar el mapa y cargarlo dentro del div son tan sencillas como las siguientes:

var map = new VEMap("MapaSmaple");
var point = new VELatLong(40.42036965902929, -3.7057537120230912)
map.LoadMap(point, 19, VEMapStyle.Road, false, 
               VEMapMode.Mode2D, true, 1);
map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers); 

Nota: Para ampliar un poco más acerca de cómo trabaja el método LoadMap consultar el SDK.http://msdn2.microsoft.com/en-us/library/bb412546.aspx

Hay que tener en cuenta que el mapa por defecto es cargado en millas. Para hacer que trabaje en KM sólo hay que cambiarle la unidad de distancia, como se muestra en el snippet de código anterior.

Para realizar una búsqueda de una localización se utiliza el método Find. Es método tiene varios parámetros, pero los más importantes son “what” y “where”, donde se indica que buscas (empresas, tiendas, etc) y la dirección que buscas. También hay un parámetro muy interesante que te permite hacer un callback a una función con el resultado de la búsqueda.

map.Find(null,
          place,
          null,
          null,
          0,
          1,
          true,
          true,
          false,
          true,
         resultSearch);     

function(layer, resultsArray, places, hasMore, veErrorMessage)
{
    if (places.length > 0)
    {
        alert(places[0].Name);
    }
}

Nota: Para ampliar un poco más acerca de cómo trabaja el método Find consultar el SDK. http://msdn2.microsoft.com/en-us/library/bb429645.aspx

Como el sistema de búsquedas es muy bueno, es necesario poner la dirección exacta del lugar a buscar. Por ejemplo, para buscar una calle, hay que poner “Nombre de la Calle Número, Código Postal Localidad”, sino el sistema no será capaz de encontrar el sitio exacto.

Otra cosa interesante que tiene Virtual Earth Map, es que permite poner marcas, chinchetas, en una localización. Para ello utilizamos el método AddPushpin, que añadirá una chincheta sobre el mapa en la localización que queramos. Este método devuelve un objeto VEShape, que permite personalizar un poco el panel que se muestra al posicionar el ratón sobre la marca. A este panel se le puede cambiar el diseño, añadir una imagen, un link a una página, etc.

var point = new VELatLong(40.42036965902929, -3.7057537120230912)
var pin = map.AddPushpin(point);
pin.SetTitle("Madrid");
pin.SetDescription("Madrid es una ciudad…");

Nota: Para ampliar un poco más acerca de cómo trabaja el método AddPushpin consultar el SDK. http://msdn2.microsoft.com/en-us/library/bb412535.aspx

En esta LIVE DEMO, se puede ver un ejemplo del uso de Virtual Earh. 

Referencias:
Maps Live
Virtual Earth Map Control Class Reference
Virtual Earth Developer Center
Windows Live Dev: Microsoft Virtual Earth

Generar clases automáticamente con Xsd.exe

En alguna ocasión me ha ocurrido que tengo la necesidad de serializar una serie de clases con un determinado formato XML.

Realizar esta operación es bastante sencillo si cuentas con un XSD. Un archivo XSD define el esquema que tendrá el XML y existe una herramienta, Xsd.exe, que es capaz de generar las clases serializables en Xml que cumplan dicho esquema. En el caso de que no tengas ese archivo XSD, con tener un XML de ejemplo es suficiente ya que Visual Studio puede encargarse de sacar el esquema muy fácilmente.

Para ilustrar este ejemplo vamos a utilizar el siguiente XSD.

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" >
  <xs:element name="data">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="album">
          <xs:complexType>
            <xs:sequence>
              <xs:element maxOccurs="unbounded" name="slide">
                <xs:complexType>
                  <xs:attribute name="title" type="xs:string"/>
                  <xs:attribute name="description" type="xs:string"/>
                  <xs:attribute name="image" type="xs:string"/>
                  <xs:attribute name="thumbnail" type="xs:string"/>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="title" type="xs:string"  />
            <xs:attribute name="description" type="xs:string"  />
            <xs:attribute name="image" type="xs:string"  />
            <xs:attribute name="transition" type="xs:string"  />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="startalbumindex" type="xs:unsignedByte"/>
      <xs:attribute name="transition" type="xs:string"  />
    </xs:complexType>
  </xs:element>
</xs:schema>

La herramienta xsd.exe viene incorporada en el SDK del .Net Framework. El uso de la herramienta es muy sencillo, solamente hay que ir a la consola del Visual Studio 2008 y escribir la siguiente línea:

xsd C:\data.xsd /classes /language:CS

Nota: También se puede generar código en VB.Net, pero a mí personalmente me produce urticaria :P.

La herramienta crea un archive .cs en la siguiente ruta: C:\Program Files\Microsoft Visual Studio 9.0\VC.

Así que con una pequeña función para serializar en XML, podemos obtener un XML que cumpla con los requisitos del XSD.

<data transition="WipeRightTransition">
  <album title="Place">
    <slide image="images/a01.jpg" />
    <slide image="images/a02.jpg" />
  </album>
</data>
Posted: Jan 16 2008, 08:49 PM by Pedroafa | with no comments
Filed under: , , ,
De 2D a 3D con Viewport2DVisual3D en WPF 3.5

Una de las nuevas novedades que presenta WPF 3.5 es la capacidad de poder convertir cualquier elemento en 3D. Hasta el momento esto también se podía lograr, pero era bastante complejo ya que había que hacer uso de herramientas externas al Framework.

El elemento que hace posible esto se llama Viewport2DVisual3D. Cómo bien sugiere su nombre su utilizada es esa, pasar una vista en 2D a una vista en 3D sin que el elemento en 2D pierda ninguna de sus funcionalidades al transformarse. El esquema XAML que presenta este elemento es el siguiente:

<Viewport2DVisual3D x:Name="Test">
    <Viewport2DVisual3D.Geometry>
        <MeshGeometry3D Normals="" TriangleIndices="" Positions=""
             TextureCoordinates=""></MeshGeometry3D>
    </Viewport2DVisual3D.Geometry>
    <Viewport2DVisual3D.Material>
        <MaterialGroup>
            <DiffuseMaterial AmbientColor="" Brush="" Color="">
            </DiffuseMaterial>
            <EmissiveMaterial Brush="" Color="" ></EmissiveMaterial>
            <SpecularMaterial Brush="" Color=""
               SpecularPower=""></SpecularMaterial>
        </MaterialGroup>
    </Viewport2DVisual3D.Material>
    <Viewport2DVisual3D.Transform>
        <Transform3DGroup >
            <Transform3DGroup.Children>
                <MatrixTransform3D Matrix=""></MatrixTransform3D>
                <RotateTransform3D CenterX="" CenterY="" CenterZ="" 
                   Rotation="" ></RotateTransform3D>
                <ScaleTransform3D CenterX="" CenterY="" CenterZ="" 
                     ScaleX="" ScaleY="" ScaleZ="" >
                </ScaleTransform3D>
                <TranslateTransform3D OffsetX="" OffsetY=""
                     OffsetZ=""></TranslateTransform3D> 
            </Transform3DGroup.Children>
        </Transform3DGroup>
    </Viewport2DVisual3D.Transform>
    <Viewport2DVisual3D.Visual>
    </Viewport2DVisual3D.Visual>
</Viewport2DVisual3D>

El elemento Geometry define la forma tendrá el objeto al convertirse en 3D. En el elemento Material se define como será la apariencia del objeto en 3D. Dentro del elemento Transform, como es de esperar, se definirán las transformaciones que sufrirá el objeto. Por último, dentro del elemento Visual se definirán los elementos que queremos pasar de 2D a 3D.

Para comprenderle mejor cómo funciona esta nueva característica de WPF 3.5 veamos un pequeño ejemplo. La idea es convertir mi tarjeta de contacto en un elemento en 3D para poder tener más versatilidad a la hora de jugar con ella en diferentes aplicaciones.

Viewport2DVisual3D

Lo primero que habrá que hacer es crear un elemento Viewport3D, en el cual definiremos la cámara que usaremos y la luz que ilumitará al objeto, además de contener la tarjeta. Así que añadiremos la siguiente cámara para este ejemplo:

<Viewport3D.Camera>
    <PerspectiveCamera x:Name="Camera" FieldOfView="45"
             FarPlaneDistance="100" LookDirection="0,0,-5" 
             NearPlaneDistance="0.1" Position="0,0,7" 
             UpDirection="0,1,0"/>
</Viewport3D.Camera>

Seguido añadimos la luz sobre el objeto, en este caso hemos elegido una luz ambiental blanca.

<ModelVisual3D x:Name="AmbientLightContainer">
    <ModelVisual3D.Content>
        <AmbientLight x:Name="AmbientLight" Color="#FFFFFFFF" />
    </ModelVisual3D.Content>
</ModelVisual3D>

Una vez hecho esto, creamos un elemente ContainerUIElement3D. Dentro de este elemento se encontrará un elemento Viewport2DVisual3D que sostendrá la tarjeta. Seguidamente creamos el elemento geométrico que dará forma al objeto y sobre el que se apoyará la tarjeta.

<Viewport2DVisual3D.Visual>
    <Canvas Width="226" Height="319" x:Name="Tarjeta">
        <Rectangle Width="228" Height="319" Fill="#FFFFFFFF" 
            Stroke="#FFD9D9D9" RadiusX="5" RadiusY="5"/>
        <Canvas Width="228" Height="319">
            <Canvas Width="228" Height="93" Canvas.Left="1" Canvas.Top="1">
                <Image Width="63" Height="63" Source="img\avatar.PNG"
                   Stretch="Fill" Canvas.Top="4" Canvas.Left="4"
                   x:Name="avatar"/>
                <Image Width="10" Height="13" Source="img\msn.PNG"
                   Stretch="Fill" Canvas.Left="70" Canvas.Top="6.5"
                   x:Name="msn"/>
                <TextBlock Width="135" Height="13" Text="Pedro Álvarez"
                   TextWrapping="Wrap" Canvas.Left="85" Canvas.Top="6.5"
                   FontWeight="Bold"/>
                <TextBlock Width="135" Text="micuenta@hotmail.com"
                   Canvas.Top="22.5" Canvas.Left="85" 
                   Style="{DynamicResource WebLink}"/>
                <Path Width="226" Height="1" Fill="#FFFFFFFF" Stretch="Fill"
                   Stroke="#FFD9D9D9" StrokeThickness="1" 
                   Data="M1.75,57.5 L57.25,57.5" Canvas.Left="0"
                   Canvas.Top="93"/>
                <Path Width="9.691" Height="10.724" Fill="#60000000"
                   Stretch="Fill" 
                   Data="F1 M5.4089999,-1.0079944 L5.4089999,
                     0.11455536 C7.8255739,0.32191041 9.691,2.3713315 9.691,
                      4.8564353 9.691,7.5402994 7.5152459,
                      9.7160006 4.8313169,9.7160006 2.1946342,
                      9.7160006 0.048392281,7.6162248 5.5656413E-09,
                      4.9969373 L1.1169847,4.9969373 C1.1695627, 
                      6.9954443 2.814204,8.5901461 4.8313169,
                      8.5901461 6.8995957,8.5901461 8.5762663,
                      6.913517 8.5762663,4.8452888 8.5762663,
                      2.9773188 7.2085662,1.4287843 5.4089999,
                      1.2184322 L5.4089999,2.1800001 2.564991,
                      0.65836239 5.4089999,
                      -1.0079944 z" 
                      RenderTransformOrigin="0.499,0.552" x:Name="path"
                      Canvas.Left="212" 
                      Canvas.Top="4" Cursor="Hand" />
            </Canvas>
            <Canvas Width="228" Height="153" Canvas.Top="93">
                <TextBlock Width="217" Height="13" TextWrapping="Wrap"
                     Canvas.Top="6.5" Canvas.Left="8" FontWeight="Bold">
                     <Run Language="es-es" 
                         Text="Contact Information"/></TextBlock>
                <TextBlock Width="32" Height="13" FontSize="10"
                    TextWrapping="Wrap" Canvas.Top="23.5" Canvas.Left="8"
                    Text="E-mail:" />
                <TextBlock Width="176" Text="micuenta@hotmail.com"
                    Canvas.Top="23.5" Canvas.Left="44" 
                    Style="{DynamicResource WebLink}"/>
                <TextBlock Width="217" Height="13" FontSize="10"
                    TextWrapping="Wrap" Text="Address: Madrid España"
                    Canvas.Top="36.5" Canvas.Left="8" />
                <TextBlock Width="24" Height="13" FontSize="10"
                    TextWrapping="Wrap" Text="Blog:" Canvas.Top="49.5"
                    Canvas.Left="8" RenderTransformOrigin="0.667,0.385" />
                <TextBlock Width="193" Text="www.sectorsieteg.net"
                    Style="{DynamicResource WebLink}" Canvas.Top="49.5"
                    Canvas.Left="35"/>
            </Canvas>
            <Canvas Width="226" Height="72" Background="#FFDDE8F2"
                  Canvas.Left="1" Canvas.Top="246">
                <TextBlock Text="View pending requests" Canvas.Left="8"
                    Canvas.Top="8" Style="{DynamicResource Link}"/>
                <TextBlock Text="View your posts list" Canvas.Top="22"
                    Canvas.Left="8" Style="{DynamicResource Link}"/>
                <TextBlock Text="View projects list" Canvas.Top="36"
                    Canvas.Left="8" Style="{DynamicResource Link}"/>
                <TextBlock Text="Change your display picture" Canvas.Top="50"
                    Canvas.Left="8" Style="{DynamicResource Link}" />
                <Path Width="226" Height="1" Fill="#FFFFFFFF" Stretch="Fill"
                    Stroke="#FFD9D9D9" StrokeThickness="1" 
                    Data="M1.75,57.5 L57.25,57.5" Canvas.Left="0"
                    Canvas.Top="0"/>
            </Canvas>
        </Canvas>
    </Canvas>
</Viewport2DVisual3D.Visual>

Con todo este proceso hemos conseguido que la tarjeta que en un principio era un elemento en 2D se convirtiera en un elemento en 3D con un esfuerzo relativamente pequeño.

www.sectorsieteg.net

Hace un par de semanas me compré el dominio www.sectorsieteg.net. Así que ya sabéis, no tenéis ninguna excusa para no acordaros de la dirección del blog :) y a ir poniendola en favoritos XD.

Sector 7G

Posted: Dec 15 2007, 12:51 PM by Pedroafa | with 1 comment(s)
Filed under:
Parrondada
"Dícese de aquel evento en el que unas pocas personas (entre una y cuatro) invitan a cerveza y sidra a decenas de otras personas"

El parrondo o parrondada es una tradición implantada por una empresa española llamada ilitia. Este evento, que cada vez congrega un número mayor de personas, nació en el año 2004. La idea surgió de uno de los socios fundadores de la empresa, que debido a sus raíces asturianas es un gran amante de la sidra.

Esta iniciativa fue creada con el fin de presentar a los nuevos ilitios al resto de la empresa, con la intención de fomentar la unidad como grupo. Inicialmente este evento se celebraba en un conocido restaurante madrileño, Casa Parrondo (de donde salió el nombre del evento). En la actualidad sólo es requisito que el lugar de celebración sea una sidrería.

Esta celebración consiste en que el o los nuevos ilitios tienen que correr con todos los gastos de sidra, cerveza y tapas. Entre los asistentes podemos encontrar, a parte de los ilitios, amigos, parejas, familiares, clientes e incluso espontáneos. La afluencia varía entre la docena que asistía a los primeros Parrondos o el más de medio centenar que empieza a ser habitual. La duración suele ser desde las 9:00 de la tarde hasta la hora que cierren el local.

Fotos del Parrondo de Diana, Lara, David y Antón (11 Ene 2008)
Fotos del Parrondo de Sergio y Rosa (14 Dic 2007)
Fotos del Parrondo de Gabi, Bea y Miguel Ángel (11 Nov 2007)
Fotos del Parrondo de Moisés (15 Sep 2007)
Fotos del Parrondo de Luis, Javier y mío (20 Oct 2006)
Miscelania de Fotos de iltia

Posted: Nov 16 2007, 12:23 PM by Pedroafa | with 2 comment(s)
Filed under:
Windows Live Messenger Presence Gadget

Tras un par de días ya esta finalizado el Gadget que kartones y yo habíamos empezado a hacer el miércoles pasado. Entre otras novedades he facilitado el mecanismo de uso. Si quieres usarlo en tu blog, web o lo que sea, te será muy fácil embeberlo mediante un iframe, como se puede ver en esta demo. Además, ahora existe una versión en español y otra en inglés.

Windows Live Messenger Presence Gadget

Cómo utilizarlo

La url del gadget es http://kartones.net/demos/002/WindowsLiveMessengerPresenceGadget.htm. Esta url acepta dos parámetros en la querystring: userid, con tu cuenta de usuario de Hotmail y mkt, con el idioma que quieras es-ES o en-US. Por ejemplo, para ver el gadget con mi estado del Messenger sería la siguiente url:

http://kartones.net/demos/002/WindowsLiveMessengerPresenceGadget.htm?userid=63d9cced8bc7b3ef%40apps.messenger.live.com&mkt=es-es

Para poder embeber el gadget en un blog o web sólo hay que enchufarlo a un iframe como se puede ver en el siguiente código, el cual he utilizado para poderlo en mi blog:

<iframe id="1" height="70" width="150" frameborder="0" scrolling="no"

src="http://kartones.net/demos/002/WindowsLiveMessengerPresenceGadget.htm?userid=63d9cced8bc7b3ef%40apps.messenger.live.com&mkt=es-ES" ></iframe>

Una cosa importante es poner el siguiente tamaño al iframe “height="70" width="150"” para que se vea perfecto.

A la a disfrutar del invento, :P.

Windows Live Messenger IM Control & Presence API Gadget Parte I

Ayer han anunciado el tan esperado IM Control que permite embeber el cliente de Messenger en una aplicación web. Además, esto permite que en tu web se vea el estado actual en el que te encuentras dentro del menssenger.

Una cosa de las que más me han gustado de este control, es que incorpora una pequeña API en JSON. Evidentemente a Kartones y a mí nos ha faltado tiempo para investigarla y desarrollar una prueba de concepto. Una vez que tuvimos una prueba hecha, desarrollar un pequeño gadget para colocarlo en el blog fue sencillo, que es el gadget que se ve debajo de la nube de tags que se ve a la derecha en mi blog.

Muestra idea ahora sería finalizar el Mashup adaptándolo de tal forma que cualquiera mediante un iframe u otro sistema que se nos ocurra pueda embeberlo y reutilizar lo dentro de su web, blog o lo que sea que se encuentre on-line.

Así que ya os iré informado de cómo va la cosa.

Instalando Microsoft SQL Server 2005 Tools

El martes pasado por motivos de curro me dispuse a instalar en mi equipo las herramientas necesarias para trabajar con reports de SQL Reporting Services 2005 desde mi Visual Studio 2005. Para ello, me dispuse a buscar en el cd del producto el ejecutable SqlRun_Tools.msi. Este ejecutable instala todas las herramientas que puedas necesitar para trabajar contra una base de datos SQL Server.

Cuál fue mi sorpresa cuando salta un mensaje con el siguiente texto lleno de acritud:

“A component that you have specified in the ADD_LOCAL property is already installed. To upgrate the existing component, refer to the template.ini and set the UPGRADE property to the name of the component.”

Tras una par de búsquedas en google di con la solución. Al parecer el conflicto de versión se producía porque en mi equipo estaban instaladas algunas herramientas, en concreto las de mi versión Express del SQL Server (Microsoft SQL Server 2005 Tools Express Edition), :). Así que la solución era tan sencilla como desinstalar estas herramientas.

  1. Ir a Inicio y abrir el Panel de Control.
  2. Hacer doble click en Añadir o Borrar Programanas.
  3. En la lista de programas instalados, buscar Microsoft SQL Server 2005, y hacer click en Cambiar.
  4. En la página de selección de components, selecionar “ Workstation components”, y hacer click en Siguiente.
  5. Click Siguiente.
  6. En cambiar o Borrar una instancia, darle a Cambiar.
  7. En la ventana de componente deseleccionar todos los que se encuentren en verde, es decir, deshabilitar todo.
  8. Click Siguiente.
  9. Click Instalar.

Tras seguir esos pasos ya sólo me queda volver al ejecutable SqlRun_Tools.msi y seguir los pasos que indicaba y bingo!!!, herramientas instaladas, a trabajar!!.

More Posts Next page »