Otra de las preguntas recurrentes de la gente es en la listas, combox, items control como cambiar el aspecto de la información que se muestra cuando el usuario selecciona una fila. Esto es muy sencillo de realizar en WPF. Para hacer esto lo primero que intenta la gente es subscribirse al evento SelectionChanged de la lista y cambiar un diferente DataTemplate, pero esto no funciona ya que cambia a toda la lista.
Para realizar esto debemos basarnos en la clase System.Windows.Controls.DataTemplateSelector, debemos de crear una clase que herede de esta y sobrescribir el método SelectTemplate. Basándonos en la aplicación del post DataTemplates en WPF, creamos la clase PersonDataTemplateSelector y heredamos de DataTemplateSelector
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
En este método como vemos tenemos el parámetro item, que nos va a pasar el objeto seleccionado, la propiedad container que es ContentPresenter de la lista. En este método lo que tenemos que implementar es cambiar el DataTemplate dependiendo si el item esta seleccionado o no, yo he creado en recursos un nuevo DataTemplate para cuando este seleccionado, mostrando la imagen y el texto mas grande
<DataTemplate x:Key="TemplatePersonSelect"> <DataTemplate.Resources> <LinearGradientBrush x:Key="backBrush" StartPoint="0,0.5" EndPoint="1,0.5"> <GradientStop Color="#1100CC22" Offset="0" /> <GradientStop Color="#8800CC22" Offset="0.97" /> <GradientStop Color="#AA10FF18" Offset="0.999" /> <GradientStop Color="#44FFFFFF" Offset="1" /> </LinearGradientBrush> <local:PersonImageConverter x:Key="imageConverter" /> </DataTemplate.Resources> <Border x:Name="personsBorder" Style="{StaticResource PersonBorderStyle}" BorderThickness="8" CornerRadius="5" BorderBrush="#FF201F1F" Width="450"> <Grid> <StackPanel Orientation="Horizontal"> <Image Width="60" Height="60" Source="{Binding Path=ImageRef, Converter={StaticResource imageConverter}}"> <Image.BitmapEffect> <DropShadowBitmapEffect /> </Image.BitmapEffect> </Image> <TextBlock x:Name="personName" Text="{Binding Name}" Padding="15,15" Foreground="Black" FontSize="20" /> </StackPanel> </Grid> </Border> </DataTemplate>
Una vez que tenemos el DataTemplate implementamos el método SelectTemplate
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) { Person person = item as Person; DataTemplate dataTemplate = null; if (person != null) { Window window = System.Windows.Application.Current.MainWindow; ListBox list = window.FindName("personItems") as ListBox; Person selectedPerson = list.SelectedItem as Person; ContentPresenter pres = container as ContentPresenter; if (selectedPerson != null && selectedPerson.Name == person.Name) dataTemplate = pres.FindResource("TemplatePersonSelect") as DataTemplate; else dataTemplate = pres.FindResource("TemplatePerson") as DataTemplate; } return dataTemplate; }
Como podéis observar si la persona seleccionada es la misma que el item enviado por parámetro devolvemos el DataTemplate que queremos para los objetos seleccionado, sino el de por defecto, esto no solo sirve para los seleccionados, sino por ejemplo si la comprobación hubiera sido que el nombre fuese Oscar o lo que queramos, este método nos permite cambiar el DataTemplate dinámicamente.
Ahora lo que tenemos que hacer es implementar el using de XAML para poder referenciar la clase PersonDataTemplateSelector , en nuestra aplicacion
xmlns:local="clr-namespace:WPFDataTemplates"
Crear el recurso para el DataTemplate Selector
<Window.Resources> <local:PersonDataTemplateSelector x:Key="PersonTemplateSelector" /> </Window.Resources>
Implementarlo en la lista
<ListBox x:Name="personItems" Grid.Row="1" ItemTemplateSelector="{StaticResource PersonTemplateSelector}" SelectionChanged="personItems_SelectionChanged" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Center" />
Nos tenemos que fijar en dos cosas, primero debemos de tener en cuenta es que no podemos tener asignada la propiedad ItemTemplate que especificabamos en el post anterior junto con ItemTemplateSelector. Segundo debemos de implementar el evento SelectionChanged que en nuestro caso seria
private void personItems_SelectionChanged(object sender, SelectionChangedEventArgs e) { personItems.ItemTemplateSelector = new PersonDataTemplateSelector(); }
La aplicación nos quedaría:
Otra de las preguntas recurrentes de la gente es en la listas, combox, items control como cambiar el
Como ejemplo está muy bien, pero personalmente preferiría tener la propiedad «IsSelected» en la clase Persona, «bindeada» a «IsSelected» de su correspondiente ListBoxItem, y en el DataTemplate reaccionar a los cambios en esa propiedad de Persona con un DataTrigger. Así me ahorro suscribirme a un evento (SelectionChanged), que suele dar problemas en WPF, además de que no siempre puedes hacerlo en XAML (por ejemplo, si el elemento está en un diccionario de recursos).
Muy bueno el post
Hay algo raro en el ejemplo
Si usas las teclas de subir y bajar no va del todo bien
Hola Sergi, en efecto era el siguiente post y la causa de que tenga ese efecto raro con las teclas, has sido muy rapido en darte cuenta que es mejor realizarlo con un DataTrigger
Enhorabuena !!!
Veo que lo tenías todo calculado :D.
cuando doy cursos suelo meter algun error de temas anteriores para ver si la gente esta «despierta» ya vero que si y la verdad es que me alegra