WinRT: Establecer un estilo Condicional (2) #Metro #Win8

Introducción

Ayer publique una entrada en la que hablaba de aplicar un estilo condicional a un control en xaml.

Después de  revisar si se puede utilizar StyleSelector o DataTemplateSelector, ambos son válidos a aplicar para un control como el ListBox, pero no por ejemplo para un TextBox o un TextBlock.

Código V2:

Dandole una pequeña vuelta de tuerca, y a pesar que me sigue pareciendo un “Bad Code Smell”, me he creado un nuevo converter:

   1: public class BooleanStyleConverter : IValueConverter

   2: {

   3:  

   4:     public object Convert(object value, Type targetType, object parameter, string language)

   5:     {

   6:         var page = new MyXamlPage();

   7:  

   8:         return ((bool)value ? page.Resources["StyleA"] as Style : page.Resources["StyleB"] as Style);

   9:     }

  10:  

  11:     public object ConvertBack(object value, Type targetType, object parameter, string language)

  12:     {

  13:         throw new NotImplementedException();

  14:     }

  15: }

En el converter se define la pagina donde se encuentran los estilos, y nuestro control, y a través del diccionario de recursos devolvemos un estilo según nuestro condicionante.

Su aplicación en  código:

1) Definir el converter en los recursos:

   1: <converters:BooleanStyleConverter x:Name="GenderConverter"/>

2) Definir nuestro control con su Binding y Converter:

   1: <TextBlock Text="{Binding Child.Name}" Style="{Binding Child.Gender,Converter={StaticResource GenderConverter}}" />

Espero que os sea de utilidad, o si veis alguna opción mejor, lo comenteis Open-mouthed smile

 

Saludos!

WinRT: Establecer un estilo Condicional #Metro #Win8

Introducción

Estoy realizando una pequeña app para Windows8 con WinRT y Metro.

Pese a que no soy ningun experto en WPF, creo que condicionar el estilo a un elemento de Binding era algo trivial en WPF o Silverlight, en WinRT, (espero que de momento) no lo es.

Solución que hemos hablado por Twitter

En una conversación mantenida con @Antiocool y con @CorsarioVasco, hablabamos de definir 2 bloques de texto, uno para cada estilo (puesto que el condicional era para un booleano) y cada uno tuviera el estilo correspondiente. Y jugar con la visibilidad del segundo con respecto de la visibilidad del primero. Pese a que es un poco “BADSMELL”, de momento es la “única” solución rápida que he encontrado.

1) Partiendo de un Converter BooleanToVisibility

   1: public class BooleanToVisibilityConverter : IValueConverter 

   2:  {

   3:      public object Convert(object value, Type targetType, object parameter, string language)

   4:      {

   5:          bool val = (bool)value;

   6:          return (val ? Visibility.Visible : Visibility.Collapsed);

   7:            

   8:      }

   9:  

  10:      public object ConvertBack(object value, Type targetType, object parameter, string language)

  11:      {

  12:          var val = (Visibility)value;

  13:          return (val == Visibility.Visible);

  14:      }

  15:  }

2) Definiremos un Visibility Inverter Converter:

   1: public class VisibilityInverterConverter : IValueConverter 

   2:     {

   3:         public object Convert(object value, Type targetType, object parameter, string language)

   4:         {

   5:             return ((Visibility)value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible);

   6:         }

   7:  

   8:         public object ConvertBack(object value, Type targetType, object parameter, string language)

   9:         {

  10:             return ((Visibility)value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible);

  11:         }

  12:     }

3) Escribiremos el xaml necesario para utilizarlo:

3.1) Definimos los converters como recursos:

   1: <UserControl.Resources>

   2:        

   3:        <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->

   4:        <converters:BooleanToVisibilityConverter x:Name="BooleanConverter"/>

   5:        <converters:VisibilityInverterConverter x:Name="VisibilityConverter"/>

   6:    </UserControl.Resources>

   7: </UserControl.Resources>

3.2) Definimos los bindings necesarios:

   1: <TextBlock x:Name="tName" 

   2:     Text="{Binding Child.Name}" 

   3:     Visibility="{Binding Child.Gender,

   4:                 Converter={StaticResource BooleanConverter}}" 

   5:                 Grid.Row="0" Grid.ColumnSpan="3" 

   6:                 Style="{StaticResource ChildNameStyle}" d:LayoutOverrides="Margin"/>

   7: <TextBlock Text="{Binding Child.Name}" 

   8:             Visibility="{Binding ElementName=tName, 

   9:             Path=Visibility,Converter={StaticResource VisibilityConverter}}"

  10:              Grid.Row="0" Grid.ColumnSpan="3" 

  11:             Style="{StaticResource ChildNameStyleGirl}" d:LayoutOverrides="Margin"/>

  12:   

Como se puede observar cada TextBlock tiene el mismo texto asignado, y cambia el estilo.

La propiedad Visivility del segundo TextBlock está asignada a la misma propiedad del primer TextBlock aplicando el converter que hemos definido previamente.

 

Espero que os sea de utilidad y/o si conoceis otra alternativa, por favor comentarla!.

 

Saludos!!

Win8: Serializar y Deserializar con WinRT C#

Introducción

En este breve post vamos a ver como llevar a cabo la serialización de objetos dentro de una aplicación metro con WinRT y C#.

Código

Partiendo de una clase tipo:

 

   1: public class Employee

   2: {

   3:     public int Id { get; set; }

   4:     public string FirstName { get; set; }

   5:     public string LastName { get; set; }

   6:     public DateTime BirthDate { get; set; }

   7: }

Serializando un objeto:

   1: Employee obj;

   2: using (var fileStream = await ApplicationData.Current.RoamingFolder.OpenStreamForWriteAsync(String.Format("ci{0}{1}.xml",

   3:  obj.LastName, obj.FirstName), 

   4:                     CreationCollisionOption.ReplaceExisting))

   5:                 {

   6:                     var serializer = new XmlSerializer(typeof(ChildInfo));

   7:                     serializer.Serialize(fileStream, obj);

   8:                 }

Deserializando un objeto:

   1: Employee obj;

   2: sing(var fileStream = await ApplicationData.Current.RoamingFolder.OpenStreamForReadAsync(root))

   3:  

   4:    XmlSerializer serializer=new XmlSerializer(typeof(Employee));

   5:    obj = (Employee)serializer.Deserialize(fileStream);

Espero que os sirva.

 

Saludos!

MVC: Trabajando con campos con etiquetas HTML

Introducción:

En este post vamos a ver como trabajar con un modelo donde una de nuestras propiedades va a almacenar valores de tipo HTML, como por ejemplo el contenido del post de un blog:

   1: <p>Este el texto del post, con un enlace <a href='http://bing.com'>bing</a></p>

Abordando el problema:

Partiendo de un modelo sencillo:

   1: public class Post

   2: {

   3:     public Guid ID { get; set; }

   4:     public string Title { get; set; }

   5:     public string Content { get; set; }

   6: }

donde nuestra propiedad “Content” va a ser la que va almacenar el código HTML vamos a cualificarla con el atributo AllowHtml, para que en el momento de grabar nuestros post desde el explorador, permitirá evitar la validación de dicho campo sin tener que comprobar las etiquetas HTML introducidas en él.

Posteriormente para poder visualizar nuestro HTML con el formato HTML, vamos a hacer uso del método Raw del Helper HTML, por lo que el contenido de nuestra vista quedaría:

   1: @foreach (var c in Model)

   2: {

   3:     <article>

   4:         <h1>@c.Title</h1>

   5:         @Html.Raw(@c.Content)

   6:     </article> 

   7: }

 

Espero que os sea de utilidad.

Saludos!!

Convertir un IEnumerable<T> a DataTable

Introducción

En este post vamos a ver como llevar a cabo la exportación de un objeto IEnumerable<T> a un DataTable. Pero, espera!!! Ya existe un método extensor CopyToDataTable, que parece realizar esta acción.

Todo parece que sí, pero parece demasiado bonito. Si nos fijamos en la firma del método:

   1: public static DataTable CopyToDataTable<T>(

   2:     this IEnumerable<T> source

   3: )

   4: where T : DataRow

Veremos que este método, solo lo podremos utilizar en el caso de que T sea de tipo DataRow o implemente a DataRow.

Bueno, el porque del post es debido a una preguntaba que lanzó ayer en Twitter @Zpektrum, sobre porque no podía utilizar dicho método con una consulta Linq.

Código:

Para ilustrar el ejemplo vamos a ver una query linq contra un DataTable:

   1: var query = from t in dt1.AsEnumerable()

   2:                         select new

   3:                         {

   4:                             ID = t.Field<string>("ID"),

   5:                             Nombre = t.Field<string>("Name")

   6:                         };

Como podeís apreciar estamos realizando una consulta sobre las filas de la tabla dt1, y escogiendo las columnas ID y Nombre. El resultado de esta consulta va a devolver un IEnumerable<T> donde T va a ser un tipo anónimo, por lo que dicho tipo no va a ser DataRow y no vamos a tener disponible el método CopyToDataTable.

Bien, para construir nuestro nuevo método extensor, tendremos que definir una nueva clase estática y un método estático que retorne un objeto de Tipo DataTable, y haremos que el método sea genérico.

   1: public static class IEnumerableExtensions

   2:     {

   3:         public static DataTable CopyAnonymusToDataTable<T>(this IEnumerable<T> info)

   4:         {

   5:             var type = typeof(T);

   6:             if (type.Equals(typeof(DataRow))) 

   7:                 return (info as IEnumerable<DataRow>).CopyToDataTable();

   8:             DataTable dt = new DataTable();

   9:             DataRow r;

  10:             type.GetProperties().ToList().ForEach(a=>  dt.Columns.Add(a.Name));

  11:             foreach (var c in info)

  12:             {

  13:                 r = dt.NewRow();

  14:                 c.GetType().GetProperties().ToList().ForEach(a => r[a.Name] = a.GetValue(c,null));

  15:                 dt.Rows.Add(r);

  16:             }

  17:             return dt;

  18:         }

  19:         

  20:     }

Para que el método sea un método extensor es necesario que sea estático, que este contenido en una clase estática y que su primer parámetro tenga el modificador “this” y el tipo que va a extender.

Explicando el método:

El método es sencillo, en primer lugar comprobamos que si el tipo de T es DataRow que ejecute el método CopyToDataTable ya existente.

En caso contrario, a través de reflectión obtendremos las propiedades del Tipo T, e iremos definiendo nuevas columnas con el nombre de dichas propiedades en la tabla resultante.

Por último, iteraremos sobre el contenido de la colección e iremos agregando las filas para devolverlos.

Ejecución del método:

Continuando con el ejemplo anterior:

   1: var query = (from t in dt1.AsEnumerable()

   2:                         select new

   3:                         {

   4:                             ID = t.Field<string>("ID"),

   5:                             Nombre = t.Field<string>("Name")

   6:                         }).CopyAnonymusToDataTable();

De está manera query, será de tipo DataTable y ya podremos manejar dicha tabla a nuestro gusto.

 

Un saludo y espero que os sea de utilidad.