Jeff
Jeff

Reputation: 3

Styling individual cells in a listview

On the internet I found many examples of styling a complete column or complete row in a listview.

I need to be able to dynamically style individual cells in the listview. How can I access the properties of individual items in a row?

Upvotes: 0

Views: 1840

Answers (2)

Benny Jobigan
Benny Jobigan

Reputation: 5304

If you've got a finite number of properties in your data objects that you want to use to style your items, you can create data templates and styles, and use data triggers to switch between them. I've used something like this to alter the appearance of data objects in a list based on if they are "active/inactive" and to create a collapsed/expanded version of the object based on whether it's selected or not.

You can also use converters (built-in or custom) to get some effects easily. For example, I used a built-in boolean to visibility converter to hide/unhide the combobox/textblock in my TaskSelectedTemplate based on if the object's IsActive member.

<DataTemplate x:Key="TaskSelectedTemplate">
    <Grid Margin="4">
        ...
        <Border Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 4 0"
                BorderThickness="0" 
                CornerRadius="2">
            <Border.Background>
                <MultiBinding Converter="{StaticResource ActiveToColor}">
                    <Binding Path="."/>
                    <Binding Path="IsActive"/>
                    <Binding Path="IsPaused"/>
                </MultiBinding>
            </Border.Background>
        </Border>

        <StackPanel Grid.Row="0" Grid.Column="1"
                    Orientation="Horizontal"
                    Margin="0 2">
            <ComboBox ItemsSource="{Binding Source={StaticResource TaskTypes}}"
                      SelectedItem="{Binding Type}"
                      Text="{Binding Type}"
                      Visibility="{Binding IsActive, Converter={StaticResource BoolToVis}}"/>
            <TextBlock Text="{Binding Type}"
                       FontWeight="Bold"
                       Visibility="{Binding IsActive, Converter={StaticResource InvBoolToVis}}"/>
            <TextBlock Text=" task"/>
        </StackPanel>
        ...
    </Grid>
</DataTemplate>

<DataTemplate x:Key="TaskNotSelectedTemplate">
    <Grid Margin="4">
        ...
        <Border Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 4 0"
                BorderThickness="0" 
                CornerRadius="2">
            <Border.Background>
                <MultiBinding Converter="{StaticResource ActiveToColor}">
                    <Binding Path="."/>
                    <Binding Path="IsActive"/>
                    <Binding Path="IsPaused"/>
                </MultiBinding>
            </Border.Background>
        </Border>

        <TextBlock Grid.Row="0" Grid.Column="1"
                   Text="{Binding Type}"/>
        <TextBlock Grid.Row="0" Grid.Column="2"
                   TextAlignment="Right">
                <Run Text="{Binding Length.TotalMinutes, StringFormat='0', Mode=OneWay}"/>
                <Run Text=" min"/>
            </TextBlock>
        <TextBlock Grid.Row="0" Grid.Column="3"
                   TextAlignment="Right">
                <Run Text="{Binding TimesPerformed, Mode=OneWay}"/>
                <Run Text=" tasks"/>
            </TextBlock>            
    </Grid>
</DataTemplate>

<Style x:Key="ContainerStyle" TargetType="{x:Type ListBoxItem}">
    <!--this part changes the selected item highlight color-->
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border Name="Border">
                    <ContentPresenter />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="true">
                        <Setter TargetName="Border" 
                                Property="Background" Value="#2000BFFF">
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <!--this part causes selected task to expand-->
    <Setter Property="ContentTemplate" Value="{StaticResource TaskNotSelectedTemplate}"/>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource TaskSelectedTemplate}"/>
        </Trigger>
    </Style.Triggers>
</Style>

For more complex scenarios, you might want to look at DataTemplateSelector. I've never used it, but it seems like it might be ideal if you've got a lot of data templates to juggle.

Upvotes: 2

svick
svick

Reputation: 244777

Generally speaking, you shouldn't need this. Assuming you are using GridView, you should be able to use CellTemplate or CellTemplateSelector of your GridViewColumns.

If you really want to access specific cells, I think there is no clean way, you'd be better using DataGrid (from .Net 4 or WPF toolkit for .Net 3.5). With that, you can do something like this:

((TextBlock)datagrid.Columns[1].GetCellContent(m_specificItem)).Background = Brushes.Red

Upvotes: 0

Related Questions