Windows Phone–Tutorial XV – Monitorizar el trafico http de tu emulador usando fiddler

En los anteriores artículos Windows Phone–Tutorial XIV – Usando datos en Windows Phone 7–Servicios RES y Windows Phone–Tutorial XIII – Usando datos en Windows Phone 7–Web Services vimos como acceder a servicios tanto SOAP como REST para mostrarlos en nuestros Windows Phone, yo siempre que desarrollo con servicios en algún momento tengo que monitorizar el trafico por una o otra razón. En mi caso Fiddler es la herramienta que utilizo y considero imprescindible que mi equipo la utilice. 

Si abro Fiddlery utilizo la aplicación de ejemplo de servicios REST de traductor de Google vemos que se produce el siguiente error, no encuentra el servidor

 

image

 

Debemos habilitar Fiddler para ello seguimos los siguientes pasos

 

  • Click Tools > Fiddler Options.
  • En la pestaña Connections marcar Allow remote computers to connect

image

  • En QuickExec box bajo la lista de sesiones introducimos prefs set fiddler.network.proxy.registrationhostname HostName donde HostName

    es el nombre de tu equipo

image

  • Cerramos y abrimos de nuevo Fiddler
  • Cerramos y abrimos de nuevo el emulador

Y ya esta podemos empezar a monitorizar el trafico que envía nuestro emulador de Windows Phone 7

+30 Tutoriales de Windows Phone 7

 

30+ Excellent Windows Phone 7 Development Tutorials

Hoy me he encontrado en el blog de Microsoft Lebanon’s Official Blog una entrada con mas de 30 tutoriales de desarrollo de Windows Phone 7 una gran colección de recursos para aprender.

 

Custom tool warning: Cannot import wsdl:portType

Hoy mientras desarrollaba la aplicación de Windows Phone que tengo en mente me he encontrado con un error que ha hecho que este dos horas buscando la solución. El problema me ha surgido cuando desde mi aplicación de Windows Phone he hecho referencia a un servicio WCF que tengo en otro proyecto de la solución.  El error era el siguiente

Warning    22    Custom tool warning: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: Could not load type ‘System.Runtime.Serialization.DataContractSet’ from assembly ‘System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’.
XPath to Error Source: //wsdl:definitions[@targetNamespace=’http://tempuri.org/’]/wsdl:portType[@name=’IVerblijfService’]    C:UsersNicoDocumentsVisual Studio 2010ProjectsTestAppl1Phone7 – kopieTestAppl1Phone7Service ReferencesVerblijfServiceReference.svcmap    1    1    TestAppl1Phone7
—————————–

Lo que hacia que fuera imposible generar la clase proxy que consumiese el servicio web. Después de navegar un rato por Internet he descubierto que este error se producía cuando el VS2010 se ejecuta en modo administrador,tan solo he tenido que ejecutar el VS2010 en modo “normal” y lo he podido referenciar correctamente el servicio WCF.

Es un error reportado a connect lo podéis ver aquí https://connect.microsoft.com/VisualStudio/feedback/details/624984/error-warnings-when-adding-web-reference-on-windows-phone-7-project?wa=wsignin1.0.

 

Espero que os ayude a no perder tanto tiempo como me paso a mi.

Windows Phone–Tutorial XIV – Usando datos en Windows Phone 7–Servicios REST

En el anterior post vimos como utilizar un servicio SOAP, en este vamos a consumir un servicio REST, para ello vamos a aprovecharnos de todo el código anterior y utilizaremos el servicio de Google de traducción que es de tipo REST.

En nuestro caso recoger los lenguajes que nos permite traducir no es posible ya que Google no lo proporciona para ello

1 private void GetLanguagesGoogle() 2 { 3 Language la = new Language(); 4 la.Code = "en"; 5 la.Name = "English"; 6 _languages.Add(la); 7 8 la = new Language(); 9 la.Code = "es"; 10 la.Name = "Spanish"; 11 _languages.Add(la); 12 13 la = new Language(); 14 la.Code = "ar"; 15 la.Name = "Arabic"; 16 _languages.Add(la); 17 } 18

Para utilizar la traducción de Google llamaremos a la url https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source=en&target=es&q=Hello

Para conseguir tu key debes de registrarte en https://code.google.com/apis/console/?pli=1#welcome

Definimos una variable con la url

1 private readonly string SERVICE_URL = @"https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source={0}&target={1}&q={2}";

Para llamar a un servicio REST debemos de utilizar el objeto WebClient por lo que en nuestro método Traslate

1 private void Translate() 2 { 3 WebClient _proxy = new WebClient(); 4 _proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_proxy_DownloadStringCompleted); 5 string googleTranslateUrl = string.Format(SERVICE_URL, 6 LanguageFromSelected.Code, LanguageToSelected.Code, LanguageFrom); 7 _proxy.DownloadStringAsync(new Uri(googleTranslateUrl)); 8 } 9

Observáis como componemos la URL con los datos y llamamos al método DownloadStringAsync , para recoger el resultado debemos parsearlo ya que al no ser un servicio SOAP nos va a devolver un XML o JSON, para ello utilizaremos DataContractJsonSerializer, en el ejemplo que voy a poner voy a utilizar la v1 de la API de Google en la que no hace falta la API key que os he explicado antes, la url es

https://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q={0}&langpair={1}|{2}
Un ejemplo seria
https://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=Hello,%20my%20friend!&langpair=en%7Ces
La respuesta que obtendríamos en el navegador es
{
  "responseData": {
    "translatedText": "Hola, mi amigo!"
  },
  "responseDetails": null,
  "responseStatus": 200
}

Con DataContractJsonSerializer deberíamos crear una clase en el model que refleje los datos JSON que vamos a serializar, yo voy a crear dos clases TranslationResponse y ResponseData estas clases deben de estar decoradas con los atributos DataContract y DataMember

1 [DataContract(Name = "translateResponse")] 2 public class TranslationResponse 3 { 4 5 [DataMember(Name = "responseData")] 6 public ResponseData ResponseData { get; set; } 7 8 9 [DataMember(Name = "responseDetails")] 10 public string ResponseDetails { get; set; } 11 12 13 [DataMember(Name = "responseStatus")] 14 public int ResponseStatus { get; set; } 15 }

 
1 [DataContract(Name = "translations")] 2 public class ResponseData 3 { 4 5 [DataMember(Name = "translatedText")] 6 public string TranslatedText { get; set; } 7 8 9 [DataMember(Name = "detectedSourceLanguage")] 10 public string DetectedSourceLanguage { get; set; } 11 }

Ahora para deserializar la respuesta es tan sencillo como el código que tenéis abajo

 

1 void _proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 2 { 3 4 DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TranslationResponse)); 5 MemoryStream ms = new MemoryStream(Encoding. UTF8.GetBytes(e.Result)); 6 7 TranslationResponse t = (TranslationResponse)serializer.ReadObject(ms); 8 9 LanguageTo = t.ResponseData.TranslatedText; 10 11 }

El resultado sería

image

 

Os dejo el código, no os asustéis del nombre del proyecto ya que he reutilizado el anterior, pero en vez de bing es el de Google

 

Nuevo Libro de Windows Phone 7

Hoy Reyes me he encontrado en el blog de Rob Miles  que han publicado un curso de programación para Windows Phone 7 en Microsoft Faculty Center.

Windows Phone 7 Blue Book

Este libro es una introducción para Windows Phone 7 no esperéis conceptos avanzados. Tiene los capítulos

  1. WP7, Introducción a Silverlight
  2. Introducción a Visual Studio 2010,
  3. Interfaces con Silverlight
  4. Consumo de servicios
  5. XNA
  6. Creando aplicaciones para WP7
  7. Windows Phone Marketplace

Podéis descárgalo a través de este enlace.

Windows Phone–Tutorial XIII – Usando datos en Windows Phone 7–Web Services

En Windows Phone 7 no existe una base de datos como en compact framework, existen algunas no oficiales como Sterling aunque al final lo que utilizan por debajo es  IsolatedStorage como ya vimos. No se si Microsoft en futuras versiones nos ofrecerá esta posibilidad pero en mi opinión no creo que sea una característica por la que debemos rasgarnos las vestiduras aunque necesaria si Microsoft quiere que Windows Phone tenga éxito en el ámbito empresarial, aunque ahora mismola única manera de obtener datos y manejarlos es a través de servicios. En este articulo vamos a ver varios tipos de acceso a datos.

El primer tipo que voy a explicar es como acceder a través de un servicio SOAP, para ello vamos a utilizar el servicio Translator de Bing con lo que creamos nuestro proyecto para WindowsPhone y como siempre utilizando MVVM

 

Para utilizar la API de Bing debemos de hacer referencia la servicio http://api.microsofttranslator.com/V2/Soap.svc, para ello en “References” pulsamos botón derecho del ratón y en el menu "Add service reference", añadimos la url anterior.

image

Nos va a generar la referencia al servicio web de Bing

 

image

 

Vamos a crear un modelo con las propiedades Code y Name de los lenguajes

1 namespace BingTranslatorMVVM.Model 2 { 3 public class Language 4 { 5 public string Code { get; set; } 6 public string Name { get; set; } 7 } 8 }

 

Ahora en nuestra ViewModel vamos a utilizar el servicio web que hemos referenciado de Bing para ello  añadimos el using

1 using BingTranslatorMVVM.BingTranslatorService;

Creamos la instancia de la clase LanguageServiceClient que expone el servicio web y llamamos al método para traernos los lenguajes, debemos recordar que al igual que en Silverlight las llamadas a los servicios web son asíncronas. El código para realizar las llamadas para recoger los lenguajes sería

1 private void GetLanguages() 2 { 3 LanguageServiceClient proxy = new LanguageServiceClient(); 4 proxy.GetLanguagesForTranslateAsync(APPID); 5 proxy.GetLanguagesForTranslateCompleted += new System.EventHandler<GetLanguagesForTranslateCompletedEventArgs>(proxy_GetLanguagesForTranslateCompleted); 6 } 7 8 void proxy_GetLanguagesForTranslateCompleted(object sender, GetLanguagesForTranslateCompletedEventArgs e) 9 { 10 11 _codes = e.Result.ToList(); 12 LanguageServiceClient proxy = new LanguageServiceClient(); 13 proxy.GetLanguageNamesCompleted += new System.EventHandler<GetLanguageNamesCompletedEventArgs>(proxy_GetLanguageNamesCompleted); 14 proxy.GetLanguageNamesAsync(APPID, "en", e.Result); 15 } 16 17 void proxy_GetLanguageNamesCompleted(object sender, GetLanguageNamesCompletedEventArgs e) 18 { 19 _names = e.Result.ToList(); 20 LoadLanguages(); 21 } 22 23 private void LoadLanguages() 24 { 25 for (int index = 0; index < _codes.Count; index++) 26 { 27 _languages.Add(new Language 28 { 29 Code = _codes[index], 30 Name = _names[index] 31 }); 32 } 33 }

Como podéis observar hemos tenido que llamar a dos métodos del web service para recuperar los lenguajes que nos da bing para la traducción.

El XAML nos quedaría

1 <Grid x:Name="ContentGrid" 2 Grid.Row="1"> 3 <StackPanel Orientation="Vertical"> 4 <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 5 <StackPanel Orientation="Vertical"> 6 <TextBlock TextAlignment="Center">From</TextBlock> 7 <ListBox Name="lbxFrom" Height="140" ItemsSource="{Binding Languages}" Margin="0,3,0,0"> 8 <ListBox.ItemTemplate> 9 <DataTemplate> 10 <TextBlock Text="{Binding Name}" FontSize="20" /> 11 </DataTemplate> 12 </ListBox.ItemTemplate> 13 </ListBox> 14 </StackPanel> 15 <StackPanel Orientation="Vertical" Margin="5,0,0,0"> 16 <TextBlock Margin="10,0,0,0" TextAlignment="Center">To</TextBlock> 17 <ListBox Name="lbxTo" Height="140" ItemsSource="{Binding Languages}" Margin="0,3,0,0"> 18 <ListBox.ItemTemplate> 19 <DataTemplate> 20 <TextBlock Text="{Binding Name}" FontSize="20" /> 21 </DataTemplate> 22 </ListBox.ItemTemplate> 23 </ListBox> 24 </StackPanel> 25 </StackPanel> 26 <TextBox Name="txtInput" Text="{Binding LanguageFrom}" Height="180" /> 27 <Button Name="btnTranslate" Content="Translate"/> 28 <TextBox Name="txtOutput" Text="{Binding LanguageTo}" Height="180" /> 29 </StackPanel> 30 </Grid> 31 </Grid> 32

Me gustaría antes de seguir adelante que os fijaseis en los controles ListBox, en Windows Phone no existe la propiedad SelectedValuePath para indicar la propiedad que contiene el código del item de cada fila.

Si ejecutamos la aplicación tendríamos por el momento

 

image

 

Ahora debemos de recoger los idiomas que seleccione el usuario, para saber el item seleccionado utilizando el patrón MVVM es muy sencillo en nuestra ViewModel crearemos una propiedad del tipo que hacemos binding y la enlazamos mediante DataBinding a la propiedad SelectedItem.

1 private Language _languageFromSelected; 2 public Language LanguageFromSelected 3 { 4 get { return _languageFromSelected; } 5 6 set 7 { 8 _languageFromSelected = value; 9 RaisePropertyChanged("LanguageFromSelected"); 10 } 11 } 12

El código XAML

 

1 <ListBox Name="lbxFrom" Height="140" ItemsSource="{Binding Languages}" SelectedItem="{Binding LanguageFromSelected, Mode=TwoWay}" Margin="0,3,0,0"> 2 <ListBox.ItemTemplate> 3 <DataTemplate> 4 <TextBlock Text="{Binding Name}" FontSize="20" /> 5 </DataTemplate> 6 </ListBox.ItemTemplate> 7 </ListBox>

Una vez que sabemos los idiomas a traducir solo tenemos que llamar al método de traducción con los parámetros correctos.

 

1 private void Translate() 2 { 3 LanguageServiceClient proxy = new LanguageServiceClient(); 4 proxy.TranslateCompleted += new System.EventHandler<TranslateCompletedEventArgs>(proxy_TranslateCompleted); 5 proxy.TranslateAsync(APPID, LanguageFrom, LanguageFromSelected.Code, LanguageToSelected.Code); 6 } 7 8 void proxy_TranslateCompleted(object sender, TranslateCompletedEventArgs e) 9 { 10 LanguageTo = e.Result; 11 } 12

Ejecutamos nuestra aplicación y ya tenemos nuestro traductor

image

 

Os dejo el código, os recuerdo si queréis ejecutarlo debéis de crear vuestra key en Bing Developer Center

 

En el siguiente post veremos como utilizar un servicio REST

Debug DataBinding con PresentationTraceSources.TraceLevel en VS2010

Si recordáis mi articulo de http://geeks.ms/blogs/oalvarez/archive/2009/07/22/debugeando-los-binding-de-wpf.aspx en el que os explicaba como debugear bindings en wpf había una opción en la que nos permitía tracear los bindings en la ventana de Output

 

“PresentationTraceSources.TraceLevel es una clase que te permite enviar a la ventana de Output mucha mas información del DataBinding, podemos monitorizar todos los pasos que se producen en un Binding, para habilitarlo tenemos que añadir el namespace System.Diagnostics y en el binding añadir PresentationTraceSources.TraceLevel=High. Esta opción aparece a partir de la versión 3.5”

1 <Window x:Class="DebugBindings.Window1"... xmlns:trace="clr-namespace:System.Diagnostics;assembly=WindowsBase"> 2 <StackPanel> 3 <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=OneWay, trace:PresentationTraceSources.TraceLevel=High}" Height="30" Width="100" Margin="10"/> 4 <Slider Minimum="0" Maximum="100" Value="20" Margin="10" x:Name="slider" /> 5 StackPanel> 6 Window>

En VS2010 no funciona correctamente y es debido a que a la hora de instalarse el VS2010 las settings con las que se instala no se activa esta opción, para activarla vamos a Tools, Options, Debugging, Output Window, WPF Trace Settings, Data Binding y lo cambiamos al valor Warning

 

ToolsOptionsDataBinding

Este tip esta sacado de Karl on WPF y me ha venido muy bien para unas pruebas que estoy realizando.

Windows Phone–Tutorial XII–ProgressBar y MVVM Light

En esta ocasión voy ha hablar sobre como implementar una barra de progreso con el framework MVVM light. Es importante notificar al usuario que la aplicación esta esperando a que un servicio responda o que le informemos del porcentaje de bajada/subida de un fichero, siempre debemos de preocuparnos de darle feedback sin ese feedback puede que el usuario sienta que la aplicación se ha colgado y se salga de ella cuando lo único que esta haciendo es esperar la respuesta de un servicio.

Windows Phone nos provee de un control ProgressBar (igual que el de silverlight) que podemos utilizar en nuestros desarrollos, pero a mi me gusta mucho mas (es el que utilizo) el creado por Alex Yakhnin (podéis descargarlo de http://blogs.msdn.com/b/priozersk/archive/2010/09/20/creating-progress-dialog-for-wp7.aspx) me ofrece muchas mas opciones que el estándar. El objetivo del articulo no es hablar del control ProgressBar sino como desde nuestra viewmodel somos capaces de acceder a elementos de la vista.

Imaginaros que en nuestra aplicación a la hora de autenticarse utilizamos un servicio WCF que se nos proporciona con el método Authenticate, como supongo que sabréis, la llamada a servicios se hacen siempre de forma asíncrona al igual que Silverlight. Si ese servicio de autentificación tarda unos segundos debemos de notificar al usuario que la aplicación esta haciendo algo y que no esta colgada

image

La problemática  es que al servicio se llama desde la viewmodel y en ese momento debemos mostrar el control progressbar y cuando nos llega el evento Completed del servicio debemos de esconder el control. Para resolver este problema MVVM Light nos ofrece la clase estática DispatcherHelper junto con el método CheckBeginInvokeOnUI que nos permite acceder a la vista desde la viewmodel, como siempre mejor con un ejemplo

En la viewmodel definiremos una propiedad que es el control de la barra de progreso

1 private ProgressIndicator _progress; 2 public ProgressIndicator Progress 3 { 4 get 5 { 6 return _progress; 7 } 8 set 9 { 10 _progress = value; 11 RaisePropertyChanged("Progress"); 12 } 13 } 14

En el método invocado por el RelayCommand SaveCommand tendremos el siguiente código

1 public MainViewModel() 2 { 3 if (IsInDesignMode) 4 { 5 // Code runs in Blend --> create design time data. 6 } 7 else 8 { 9 _setingsUser = new Settings(); 10 SaveCommand = new RelayCommand(Save); 11 } 12 } 13 14 private void Save() 15 { 16 if (SettingsUser != null) 17 { 18 DispatcherHelper.CheckBeginInvokeOnUI(() => 19 { 20 if (Progress == null) 21 { 22 Progress = new ProgressIndicator(); 23 Progress.ProgressType = ProgressTypes.WaitCursor; 24 Progress.Text = "Loading data..."; 25 } 26 Progress.Show(); 27 }); 28 MyNikePlusProxy.MyNikePlusServiceClient proxy = new MyNikePlusProxy.MyNikePlusServiceClient(); 29 proxy.AuthenticateCompleted += new System.EventHandler<MyNikePlusProxy.AuthenticateCompletedEventArgs>(proxy_AuthenticateCompleted); 30 proxy.AuthenticateAsync(SettingsUser.IdUser, SettingsUser.Password); 31 32 } 33 34 } 35

 

Como podéis observar es muy fácil de utilizar y  no necesita ninguna explicación, solo nos quedaría el completed

 

1 void proxy_AuthenticateCompleted(object sender, MyNikePlusProxy.AuthenticateCompletedEventArgs e) 2 { 3 if (e.Error == null && e.Result != string.Empty) 4 { 5 SettingsUser.AuthenticatedCookie = e.Result; 6 IsolatedStorageHelper ish = new IsolatedStorageHelper(); 7 ish.SaveEntity<Settings>("settings.dat", SettingsUser); 8 DispatcherHelper.CheckBeginInvokeOnUI(() => 9 { 10 Progress.Hide(); 11 }); 12 13 } 14 } 15

No necesita mas explicación, a probarlo!!!

Quitar Converter de WPF con BindingBase.StringFormat

La propiedad BindingBase.StringFormat es nueva en WPF 4.0 y nos va ayudar a reducir los converters que hemos tenido que hacer en las versiones anteriores, en la MSDN vienen unos cuantos ejemplos los podéis descargar y echar un vistazo, yo como siempre os lo voy a enseñar a través de un ejemplo.

Si creamos la típica clase Persona con las siguientes propiedades

1 public enum Sexo 2 { 3 hombre, 4 mujer 5 } 6 7 public class Person : INotifyPropertyChanged 8 { 9 #region Properties 10 11 public string Nombre 12 { 13 get { return _nombre; } 14 set { _nombre = value; OnPropertyChanged("Nombre"); } 15 } 16 17 private string _nombre; 18 19 public string Apellido 20 { 21 get { return _apellido; } 22 set { _apellido = value; OnPropertyChanged("Apellido"); } 23 } 24 private string _apellido; 25 26 public int Edad 27 { 28 get { return _edad; } 29 set { _edad = value; OnPropertyChanged("Edad"); } 30 } 31 private int _edad; 32 33 public DateTime FechaNacimiento 34 { 35 get { return _fechaNacimiento; } 36 set { _fechaNacimiento = value; OnPropertyChanged("FechaNacimiento"); } 37 } 38 private DateTime _fechaNacimiento; 39 40 public Sexo Sex 41 { 42 get { return _sex; } 43 set { _sex = value; OnPropertyChanged("Sex"); } 44 } 45 private Sexo _sex; 46 47 #endregion 48 49 #region Constructor(s) 50 51 public Person() { } 52 53 public Person(string firstName, string lastName, int age, DateTime birthDate, Sexo sex) 54 { 55 this.Nombre = firstName; 56 this.Apellido = lastName; 57 this.Edad = age; 58 this.FechaNacimiento = birthDate; 59 this.Sex = sex; 60 } 61 62 #endregion 63 64 #region INotifyPropertyChanged Members 65 66 public event PropertyChangedEventHandler PropertyChanged; 67 68 void OnPropertyChanged(string propName) 69 { 70 if (this.PropertyChanged != null) 71 this.PropertyChanged(this, new PropertyChangedEventArgs(propName)); 72 } 73 74 #endregion 75 }

 

Típica clase que al hacer el binding deberíamos realizar diferentes converters para el Sexo, la Edad y el Nombre, con BindingBase.StringFormat vamos a ver como no harían falta estos converters

En el code-behind de la ventana crearíamos la instancia de persona y asignaríamos el DataContext

1 public partial class MainWindow : Window 2 { 3 public Person Person 4 { 5 get 6 { 7 if (_person == null) 8 _person = new Person("Oscar", "Alvarez", 29, new DateTime(1978, 3, 9), Sexo.hombre); 9 10 return _person; 11 } 12 set 13 { 14 _person = value; 15 } 16 }private Person _person; 17 18 public MainWindow() 19 { 20 InitializeComponent(); 21 this.DataContext = Person; 22 } 23 24 }

Ahora el Xaml para ver como utilizaríamos la propiedad

1 <Window x:Class="WPFStringFormat.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="350" Width="525"> 5 <Grid> 6 <StackPanel> 7 <TextBlock Margin="5"> 8 <TextBlock.Text> 9 <MultiBinding StringFormat="Hola {0} {1}!"> 10 <Binding Path="Nombre"/> 11 <Binding Path="Apellido"/> 12 </MultiBinding> 13 </TextBlock.Text> 14 </TextBlock> 15 <TextBlock Text="{Binding Path=Edad, StringFormat='Tienes{0} años.'}" Margin="5"/> 16 <TextBlock Text="{Binding Path=Sex, StringFormat='Eres un {0}.'}" Margin="5"/> 17 <TextBlock Text="{Binding Path=FechaNacimiento, StringFormat='naciste en {0:dd/MM/yyyy}'}" Margin="5"/> 18 </StackPanel> 19 </Grid> 20 </Window> 21

Con esta nueva característica ahorraremos bastantes converters