Cambiar el Template del item seleccionado en una lista de WPF - Blog de Oskar Alvarez

Cambiar el Template del item seleccionado en una lista de WPF

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:

 

image

Published 28/7/2009 9:22 por Oskar Alvarez
Archivado en:
Comparte este post:
http://geeks.ms/blogs/oalvarez/archive/2009/07/28/cambiar-el-template-del-item-seleccionado-en-una-lista-de-wpf.aspx

Comentarios

# Cambiar el Template del item seleccionado en una lista de WPF

Otra de las preguntas recurrentes de la gente es en la listas, combox, items control como cambiar el

Tuesday, July 28, 2009 10:09 AM por .NET con oskar

# re: Cambiar el Template del item seleccionado en una lista de WPF

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).

Tuesday, July 28, 2009 10:58 AM por Sergi Díaz

# re: Cambiar el Template del item seleccionado en una lista de WPF

Muy bueno el post

Tuesday, July 28, 2009 11:28 AM por Julio Trujillo Leon

# re: Cambiar el Template del item seleccionado en una lista de WPF

Hay algo raro en el ejemplo

Si usas las teclas de subir y bajar no va del todo bien

Tuesday, July 28, 2009 11:30 AM por Julio Trujillo Leon

# re: Cambiar el Template del item seleccionado en una lista de WPF

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 !!!

Tuesday, July 28, 2009 2:17 PM por Oskar Alvarez

# re: Cambiar el Template del item seleccionado en una lista de WPF

Veo que lo tenías todo calculado :D.

Tuesday, July 28, 2009 4:17 PM por Sergi Díaz

# re: Cambiar el Template del item seleccionado en una lista de WPF

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

Tuesday, July 28, 2009 6:44 PM por Oskar Alvarez